diff --git a/aa.conf b/aa.conf new file mode 100644 index 0000000..383531e --- /dev/null +++ b/aa.conf @@ -0,0 +1,119 @@ + +#user nobody; +worker_processes 1; + +#error_log logs/error.log; +#error_log logs/error.log notice; +#error_log logs/error.log info; + +#pid logs/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on; + + server { + listen 80; + server_name cnxhyc.com; + + #charset koi8-r; + + #access_log logs/host.access.log main; + + location / { + root html; + index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} + } + + + # another virtual host using mix of IP-, name-, and port-based configuration + # + #server { + # listen 8000; + # listen somename:8080; + # server_name somename alias another.alias; + + # location / { + # root html; + # index index.html index.htm; + # } + #} + + + # HTTPS server + + server { + listen 443 ssl http2; + server_name cnxhyc.com; + + ssl_certificate /cert/cnxhyc.com.pem; + ssl_certificate_key /cert/cnxhyc.com.key; + + # 使用更现代的 SSL 配置 + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + ssl_prefer_server_ciphers off; + + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + location / { + root html; + index index.html index.htm; + } + } + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/CorrectVCardGenerator.java b/fys-admin/src/main/java/com/fuyuanshen/CorrectVCardGenerator.java new file mode 100644 index 0000000..8c4b719 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/CorrectVCardGenerator.java @@ -0,0 +1,96 @@ +package com.fuyuanshen; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class CorrectVCardGenerator { + public static void main(String[] args) { + // // 定义江西上饶的134号段(共22个) + // String[] prefixes = { + // "1340703", "1340793", "1342650", "1342651", "1342663", + // "1342664", "1342665", "1343703", "1343793", "1347901", + // "1347902", "1347903", "1347930", "1347931", "1347932", + // "1347933", "1347934", "1347935", "1347936", "1347937", + // "1347938", "1347939" + // }; 1340700 号段(移动) + // 1340708 号段(移动) + // 1340709 号段(移动) + // 1340791 号段(移动) + // 1342668 号段(移动) + // 1343700 号段(移动) + // 1343708 号段(移动) + // 1343709 号段(移动) + // 1343790 号段(移动) + // 1343791 号段(移动) + // 1347910 号段(移动) + // 1347911 号段(移动) + // 1347912 号段(移动) + // 1347913 号段(移动) + // 1347914 号段(移动) + // 1347915 号段(移动) + // 1347916 号段(移动) + // 1347917 号段(移动) + // 1347918 号段(移动) + // 1347919 号段(移动) + + // 定义江西南昌的134号段(共22个) + String[] prefixes = { + "1340700", "1340708", "1340709", "1340791", "1342668", + "1343700", "1343708", "1343709", "1343790", "1343791", + "1347910", "1347911", "1347912", "1347913", "1347914", + "1347915", "1347916", "1347917", "1347918", "1347919" + }; + + // 创建.vcf文件 + String filename = "南昌联系人.vcf"; + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) { + // 生成所有联系人 + int count = 0; + for (String prefix : prefixes) { + for (int i = 0; i < 100; i++) { + String middle = String.format("%02d", i); + String phoneNumber = prefix + middle + "51"; + + // 每个联系人以BEGIN:VCARD开始 + writer.write("BEGIN:VCARD"); + writer.newLine(); + writer.write("VERSION:3.0"); + writer.newLine(); + + // 中文姓名(用户+序号) + writer.write("FN:用户" + (count + 1)); + writer.newLine(); + + // 手机号码 + writer.write("TEL;TYPE=CELL;TYPE=VOICE:" + phoneNumber); + writer.newLine(); + + // 添加唯一标识符 + writer.write("UID:" + phoneNumber + "@shangrao"); + writer.newLine(); + + // 添加备注信息 + writer.write("NOTE:生成于" + new SimpleDateFormat("yyyy-MM-dd").format(new Date())); + writer.newLine(); + + // 每个联系人以END:VCARD结束 + writer.write("END:VCARD"); + writer.newLine(); + writer.newLine(); // 联系人之间空一行 + + count++; + } + } + + System.out.println("成功生成 " + count + " 个联系人"); + System.out.println("文件已保存为: " + filename); + + } catch (IOException e) { + System.err.println("文件写入错误: " + e.getMessage()); + } + } +} \ No newline at end of file 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 beb899e..d4b1695 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 @@ -1,20 +1,23 @@ package com.fuyuanshen.app.controller; import com.fuyuanshen.app.domain.dto.APPReNameDTO; +import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto; import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo; -import com.fuyuanshen.app.service.AppDeviceBizService; import com.fuyuanshen.common.core.domain.R; import com.fuyuanshen.common.mybatis.core.page.PageQuery; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.equipment.domain.Device; import com.fuyuanshen.equipment.domain.dto.AppDeviceBo; import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria; import com.fuyuanshen.equipment.domain.vo.AppDeviceVo; +import com.fuyuanshen.web.service.device.DeviceBizService; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Map; /** * APP设备信息管理 @@ -25,7 +28,7 @@ import java.util.List; @RequestMapping("/app/device") public class AppDeviceController extends BaseController { - private final AppDeviceBizService appDeviceService; + private final DeviceBizService appDeviceService; /** @@ -72,4 +75,19 @@ public class AppDeviceController extends BaseController { appDeviceService.reName(reNameDTO); return R.ok("重命名成功!!!"); } + + + @GetMapping("/realTimeStatus") + public R> getRealTimeStatus(AppRealTimeStatusDto statusDto) { + Map status = appDeviceService.getRealTimeStatus(statusDto); + return R.ok(status); + } + + /** + * 根据mac查询设备信息 + */ + @GetMapping("/getDeviceInfoByDeviceMac") + 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 581c934..613bb7e 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 @@ -5,7 +5,6 @@ import cn.hutool.core.util.RandomUtil; import com.fuyuanshen.app.domain.bo.AppDeviceShareBo; import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo; import com.fuyuanshen.app.domain.vo.AppDeviceShareVo; -import com.fuyuanshen.app.service.AppDeviceShareService; import com.fuyuanshen.app.service.IAppDeviceShareService; import com.fuyuanshen.common.core.constant.Constants; import com.fuyuanshen.common.core.domain.R; @@ -16,6 +15,7 @@ import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.ratelimiter.annotation.RateLimiter; import com.fuyuanshen.common.redis.utils.RedisUtils; import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.web.service.DeviceShareService; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -45,14 +45,14 @@ public class AppDeviceShareController extends BaseController { private final IAppDeviceShareService deviceShareService; - private final AppDeviceShareService appDeviceShareService; + private final DeviceShareService appDeviceShareService; /** * 分享管理列表 */ @GetMapping("/deviceShareList") public TableDataInfo list(AppDeviceShareBo bo, PageQuery pageQuery) { - return deviceShareService.queryPageList(bo, pageQuery); + return appDeviceShareService.queryPageList(bo, pageQuery); } /** @@ -60,7 +60,7 @@ public class AppDeviceShareController extends BaseController { */ @GetMapping("/otherDeviceShareList") public TableDataInfo otherDeviceShareList(AppDeviceShareBo bo, PageQuery pageQuery) { - return deviceShareService.otherDeviceShareList(bo, pageQuery); + return appDeviceShareService.otherDeviceShareList(bo, pageQuery); } /** diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceBJQController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceBJQController.java index 2f7caf8..3cc71f8 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceBJQController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceBJQController.java @@ -4,11 +4,13 @@ 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.app.service.device.AppDeviceBJQBizService; 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; @@ -24,7 +26,7 @@ import org.springframework.web.multipart.MultipartFile; @RequestMapping("/app/bjq/device") public class AppDeviceBJQController extends BaseController { - private final AppDeviceBJQBizService appDeviceService; + private final DeviceBJQBizService appDeviceService; /** * 获取设备详细信息 @@ -41,6 +43,7 @@ public class AppDeviceBJQController extends BaseController { * 人员信息登记 */ @PostMapping(value = "/registerPersonInfo") +// @FunctionAccessAnnotation("registerPersonInfo") public R registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) { return toAjax(appDeviceService.registerPersonInfo(bo)); } @@ -49,6 +52,7 @@ public class AppDeviceBJQController extends BaseController { * 发送信息 */ @PostMapping(value = "/sendMessage") + @FunctionAccessBatcAnnotation(value = "sendMessage", timeOut = 30, batchMaxTimeOut = 40) public R sendMessage(@RequestBody AppDeviceSendMsgBo bo) { return toAjax(appDeviceService.sendMessage(bo)); } @@ -57,6 +61,7 @@ public class AppDeviceBJQController extends BaseController { * 发送报警信息 */ @PostMapping(value = "/sendAlarmMessage") + @FunctionAccessBatcAnnotation(value = "sendAlarmMessage", timeOut = 5, batchMaxTimeOut = 10) public R sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) { return toAjax(appDeviceService.sendAlarmMessage(bo)); } @@ -65,6 +70,7 @@ public class AppDeviceBJQController extends BaseController { * 上传设备logo图片 */ @PostMapping("/uploadLogo") + @FunctionAccessAnnotation("uploadLogo") public R upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) { MultipartFile file = bo.getFile(); @@ -80,6 +86,7 @@ public class AppDeviceBJQController extends BaseController { * 灯光模式 * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) */ +// @FunctionAccessAnnotation("lightModeSettings") @PostMapping("/lightModeSettings") public R lightModeSettings(@RequestBody DeviceInstructDto params) { // params 转 JSONObject @@ -91,6 +98,7 @@ public class AppDeviceBJQController extends BaseController { * 灯光亮度设置 * */ +// @FunctionAccessAnnotation("lightBrightnessSettings") @PostMapping("/lightBrightnessSettings") public R lightBrightnessSettings(@RequestBody DeviceInstructDto params) { appDeviceService.lightBrightnessSettings(params); @@ -102,18 +110,10 @@ public class AppDeviceBJQController extends BaseController { * */ @PostMapping("/laserModeSettings") +// @FunctionAccessAnnotation("laserModeSettings") public R laserModeSettings(@RequestBody DeviceInstructDto params) { appDeviceService.laserModeSettings(params); return R.ok(); } - /** - * 地图逆解析 - * - */ - @PostMapping("/mapReverseGeocoding") - public R mapReverseGeocoding(@RequestBody DeviceInstructDto params) { - String mapJson = appDeviceService.mapReverseGeocoding(params); - return R.ok(mapJson); - } } 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 76dc5e2..26db3c1 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 @@ -8,6 +8,7 @@ public class AppDeviceLogoUploadDto { private Long deviceId; + private String deviceImei; /** * 文件 */ diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppRealTimeStatusDto.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppRealTimeStatusDto.java new file mode 100644 index 0000000..01a13d3 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppRealTimeStatusDto.java @@ -0,0 +1,30 @@ +package com.fuyuanshen.app.domain.dto; + +import lombok.Data; + +/** + * 设备实时状态 + */ +@Data +public class AppRealTimeStatusDto { + + /** + * 设备IMEI + */ + private String deviceImei; + + /** + * 设备类型 + */ + private String typeName; + + /** + * 功能类型 + */ + private String functionMode; + + /** + * 批次号 + */ + private String batchId; +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java deleted file mode 100644 index 80e74f1..0000000 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java +++ /dev/null @@ -1,605 +0,0 @@ -package com.fuyuanshen.app.service; - -import cn.hutool.core.collection.CollectionUtil; -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.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.fuyuanshen.app.domain.AppDeviceBindRecord; -import com.fuyuanshen.app.domain.AppPersonnelInfo; -import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo; -import com.fuyuanshen.app.domain.dto.APPReNameDTO; -import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto; -import com.fuyuanshen.app.domain.dto.DeviceInstructDto; -import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo; -import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo; -import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo; -import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper; -import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; -import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper; -import com.fuyuanshen.common.core.constant.GlobalConstants; -import com.fuyuanshen.common.core.exception.ServiceException; -import com.fuyuanshen.common.core.utils.*; -import com.fuyuanshen.common.mybatis.core.page.PageQuery; -import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; -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.AppDeviceBo; -import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; -import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria; -import com.fuyuanshen.equipment.domain.vo.AppDeviceVo; -import com.fuyuanshen.equipment.enums.BindingStatusEnum; -import com.fuyuanshen.equipment.enums.CommunicationModeEnum; -import com.fuyuanshen.equipment.mapper.DeviceMapper; -import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; -import com.fuyuanshen.equipment.utils.c.ReliableTextToBitmap; -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.IOException; -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 AppDeviceBizService { - - private final APPDeviceMapper appDeviceMapper; - private final DeviceMapper deviceMapper; - private final AppPersonnelInfoMapper appPersonnelInfoMapper; - private final DeviceTypeMapper deviceTypeMapper; - private final MqttGateway mqttGateway; - private final AppDeviceBindRecordMapper appDeviceBindRecordMapper; - - - public List getTypeList() { - Long userId = AppLoginHelper.getUserId(); - return appDeviceMapper.getTypeList(userId); - } - - public void reName(APPReNameDTO reNameDTO) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("id", reNameDTO.getId()) - .eq("binding_user_id", AppLoginHelper.getUserId()) - .set("device_name", reNameDTO.getDeviceName()); - deviceMapper.update(updateWrapper); - } - - - 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); - } - - try { - ClassPathResource resource = new ClassPathResource("image/background.png"); - InputStream inputStream = resource.getInputStream(); - -// String backgroundImagePath = "D:\\background.png"; // 替换为实际背景图片路径 - byte[] largeData = ImageWithTextGenerate.generate160x80ImageWithText2(bo.getSendMsg(), inputStream, 25600); - int[] ints = convertHexToDecimal(largeData); - RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_SEND_MESSAGE_KEY_PREFIX , Arrays.toString(ints), Duration.ofSeconds(30 * 60L)); - - String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_SEND_MESSAGE_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(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) - .eq("binding_user_id", AppLoginHelper.getUserId()) - .set("send_msg", bo.getSendMsg()); - deviceMapper.update(updateWrapper); - } catch (Exception e) { - log.info("发送信息设备发送信息失败:{}" ,deviceId); - } - - } - return 1; - } - - - public TableDataInfo queryAppDeviceList(DeviceQueryCriteria bo, PageQuery pageQuery) { - if (bo.getBindingUserId() == null) { - Long userId = AppLoginHelper.getUserId(); - bo.setBindingUserId(userId); - } - Page result = deviceMapper.queryAppBindDeviceList(pageQuery.build(), bo); - List records = result.getRecords(); - if(records != null && !records.isEmpty()){ - records.forEach(item -> { - 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(StringUtils.isNotBlank(onlineStatus)){ - - item.setOnlineStatus(1); - }else{ - item.setOnlineStatus(0); - } - String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); - // 获取电量 - if(StringUtils.isNotBlank(deviceStatus)){ - JSONObject jsonObject = JSONObject.parseObject(deviceStatus); - item.setBattery(jsonObject.getString("batteryPercentage")); - }else{ - item.setBattery("0"); - } - - 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)){ - item.setAlarmStatus(alarmStatus); - } - } - }); - } - return TableDataInfo.build(result); - } - - public int bindDevice(AppDeviceBo bo) { - Integer mode = bo.getCommunicationMode(); - Long userId = AppLoginHelper.getUserId(); - if (mode == CommunicationModeEnum.FOUR_G.getValue()) { - - String deviceImei = bo.getDeviceImei(); - QueryWrapper qw = new QueryWrapper() - .eq("device_imei", deviceImei); - List devices = deviceMapper.selectList(qw); - if (devices.isEmpty()) { - throw new RuntimeException("请先将设备入库!!!"); - } - Device device = devices.get(0); - if (device.getBindingStatus() != null && device.getBindingStatus() == BindingStatusEnum.BOUND.getCode()) { - throw new RuntimeException("设备已绑定"); - } - - QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); - bindRecordQueryWrapper.eq("device_id", device.getId()); - AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); - if (appDeviceBindRecord != null) { - UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); - deviceUpdateWrapper.eq("device_id", device.getId()) - .set("binding_status", BindingStatusEnum.BOUND.getCode()) - .set("binding_user_id", userId) - .set("update_time", new Date()) - .set("binding_time", new Date()); - return appDeviceBindRecordMapper.update(null, deviceUpdateWrapper); - } else { - AppDeviceBindRecord bindRecord = new AppDeviceBindRecord(); - bindRecord.setDeviceId(device.getId()); - bindRecord.setBindingUserId(userId); - bindRecord.setBindingTime(new Date()); - bindRecord.setCreateBy(userId); - appDeviceBindRecordMapper.insert(bindRecord); - } - - UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); - deviceUpdateWrapper.eq("id", device.getId()) - .set("binding_status", BindingStatusEnum.BOUND.getCode()) - .set("binding_user_id", userId) - .set("binding_time", new Date()); - return deviceMapper.update(null, deviceUpdateWrapper); - } else if (mode == CommunicationModeEnum.BLUETOOTH.getValue()) { - String deviceMac = bo.getDeviceMac(); - QueryWrapper qw = new QueryWrapper() - .eq("device_mac", deviceMac); - List devices = deviceMapper.selectList(qw); - if (devices.isEmpty()) { - throw new RuntimeException("请先将设备入库!!!"); - } - Device device = devices.get(0); - - QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); - bindRecordQueryWrapper.eq("device_id", device.getId()); - bindRecordQueryWrapper.eq("binding_user_id", userId); - AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); - if (appDeviceBindRecord != null) { - UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); - deviceUpdateWrapper.eq("device_id", device.getId()) - .eq("binding_user_id", userId) - .set("binding_user_id", userId) - .set("binding_time", new Date()); - return appDeviceBindRecordMapper.update(null, deviceUpdateWrapper); - } else { - AppDeviceBindRecord bindRecord = new AppDeviceBindRecord(); - bindRecord.setDeviceId(device.getId()); - bindRecord.setBindingUserId(userId); - bindRecord.setBindingTime(new Date()); - bindRecord.setCreateBy(userId); - appDeviceBindRecordMapper.insert(bindRecord); - } - - UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); - deviceUpdateWrapper.eq("id", device.getId()) - .set("binding_status", BindingStatusEnum.BOUND.getCode()) - .set("binding_user_id", userId) - .set("binding_time", new Date()); - return deviceMapper.update(null, deviceUpdateWrapper); - } else { - throw new RuntimeException("通讯方式错误"); - } - - } - - - public int unBindDevice(Long id) { - return unBindDevice(id, null, 1); - } - - public int unBindDevice(Long id, Long userId, int type) { - Device device = deviceMapper.selectById(id); - if (device == null) { - throw new RuntimeException("请先将设备入库!!!"); - } - UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); - deviceUpdateWrapper.eq("id", device.getId()) - .set("binding_user_id", null) - .set("binding_status", BindingStatusEnum.UNBOUND.getCode()) - .set("binding_time", null); - deviceMapper.update(null, deviceUpdateWrapper); - - if (userId == null) { - userId = AppLoginHelper.getUserId(); - } - QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); - bindRecordQueryWrapper.eq("device_id", device.getId()); - // 设备端解绑 0:设备端解绑 1:web端解绑 - if (type == 1) { - bindRecordQueryWrapper.eq("binding_user_id", userId); - } - - // AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); - // if (appDeviceBindRecord != null) { - // return appDeviceBindRecordMapper.deleteById(appDeviceBindRecord.getId()); - // } - - List appDeviceBindRecordList = appDeviceBindRecordMapper.selectList(bindRecordQueryWrapper); - if (CollectionUtil.isNotEmpty(appDeviceBindRecordList)) { - appDeviceBindRecordList.forEach(appDeviceBindRecord -> - appDeviceBindRecordMapper.deleteById(appDeviceBindRecord.getId())); - } - - return 1; - } - - - public AppDeviceDetailVo getInfo(Long id) { - Device device = deviceMapper.selectById(id); - if (device == null) { - throw new RuntimeException("请先将设备入库!!!"); - } - AppDeviceDetailVo vo = new AppDeviceDetailVo(); - 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(StringUtils.isNotBlank(onlineStatus)){ - vo.setOnlineStatus(1); - }else{ - vo.setOnlineStatus(0); - } - String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_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 locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + 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")); - } - - return vo; - } - - - public boolean registerPersonInfo(AppPersonnelInfoBo bo) { - Long deviceId = bo.getDeviceId(); - Device deviceObj = deviceMapper.selectById(deviceId); - if (deviceObj == null) { - throw new RuntimeException("请先将设备入库!!!"); - } - 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(position), intData); - buildArr(convertHexToDecimal(name), 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); - - if (ObjectUtils.length(appPersonnelInfoVos) == 0) { - AppPersonnelInfo appPersonnelInfo = MapstructUtils.convert(bo, AppPersonnelInfo.class); - return appPersonnelInfoMapper.insertOrUpdate(appPersonnelInfo); - } 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()); - return appPersonnelInfoMapper.update(null, uw) > 0; - } - - - } - - public static void main(String[] args) throws IOException { - byte[] largeData = ImageToCArrayConverter.convertImageToCArray("E:\\workspace\\demo.png", 160, 80, 25600); - System.out.println("长度:" + largeData.length); - - System.out.println("原始数据大小: " + largeData.length + " 字节"); - - int[] ints = convertHexToDecimal(largeData); - System.out.println("转换后的数据: " + Arrays.toString(ints)); - } - - public void uploadDeviceLogo(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); - - 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(30 * 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)); - } catch (Exception e){ - e.printStackTrace(); - } - } - - /** - * 灯光模式 - * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) - */ - public void lightModeSettings(DeviceInstructDto params) { - try { - Long deviceId = params.getDeviceId(); - Device device = deviceMapper.selectById(deviceId); - if(device == null){ - throw new ServiceException("设备不存在"); - } - 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)); - } catch (Exception e){ - e.printStackTrace(); - } - } - - //灯光亮度设置 - public void lightBrightnessSettings(DeviceInstructDto params) { - try { - Long deviceId = params.getDeviceId(); - Device device = deviceMapper.selectById(deviceId); - if(device == null){ - throw new ServiceException("设备不存在"); - } - 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(); - } - } - - //激光模式设置 - public void laserModeSettings(DeviceInstructDto params) { - try { - Long deviceId = params.getDeviceId(); - Device device = deviceMapper.selectById(deviceId); - if(device == null){ - throw new ServiceException("设备不存在"); - } - 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)); - } catch (Exception e){ - e.printStackTrace(); - } - } - - public String mapReverseGeocoding(DeviceInstructDto params) { -// Long deviceId = params.getDeviceId(); -// Device device = deviceMapper.selectById(deviceId); - 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()); - } - - 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); - } - - 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) - .eq("binding_user_id", AppLoginHelper.getUserId()) - .set("send_msg", bo.getSendMsg()); - deviceMapper.update(updateWrapper); - } catch (Exception e) { - log.info("设备发送信息失败:{}" ,deviceId); - } - - } - } catch (Exception e){ - e.printStackTrace(); - } - return 1; - } -} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceShareService.java b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceShareService.java deleted file mode 100644 index 996c97c..0000000 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceShareService.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.fuyuanshen.app.service; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.fuyuanshen.app.domain.AppDeviceShare; -import com.fuyuanshen.app.domain.AppPersonnelInfo; -import com.fuyuanshen.app.domain.bo.AppDeviceShareBo; -import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo; -import com.fuyuanshen.app.domain.vo.AppDeviceShareVo; -import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo; -import com.fuyuanshen.app.mapper.AppDeviceShareMapper; -import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; -import com.fuyuanshen.common.core.constant.Constants; -import com.fuyuanshen.common.core.constant.GlobalConstants; -import com.fuyuanshen.common.core.exception.ServiceException; -import com.fuyuanshen.common.core.exception.user.CaptchaExpireException; -import com.fuyuanshen.common.core.utils.MessageUtils; -import com.fuyuanshen.common.core.utils.StringUtils; -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.mapper.DeviceMapper; -import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.Arrays; -import java.util.Date; -import java.util.List; - - -@RequiredArgsConstructor -@Slf4j -@Service -public class AppDeviceShareService { - - private final AppDeviceShareMapper appDeviceShareMapper; - - private final DeviceMapper deviceMapper; - - private final DeviceTypeMapper deviceTypeMapper; - - private final AppPersonnelInfoMapper appPersonnelInfoMapper; - - public AppDeviceShareDetailVo getInfo(Long id) { - - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(AppDeviceShare::getDeviceId, id); - List appDeviceShareVos = appDeviceShareMapper.selectVoList(queryWrapper); - if(appDeviceShareVos==null || appDeviceShareVos.isEmpty()){ - return null; - } - - AppDeviceShareVo shareVo = appDeviceShareVos.get(0); - AppDeviceShareDetailVo shareDetailVo = new AppDeviceShareDetailVo(); - shareDetailVo.setId(shareVo.getId()); - shareDetailVo.setDeviceId(shareVo.getDeviceId()); - shareDetailVo.setPhonenumber(shareVo.getPhonenumber()); - shareDetailVo.setPermission(shareVo.getPermission()); - - Device device = deviceMapper.selectById(shareVo.getDeviceId()); - shareDetailVo.setDeviceName(device.getDeviceName()); - shareDetailVo.setDeviceImei(device.getDeviceImei()); - shareDetailVo.setDeviceMac(device.getDeviceMac()); - - DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType()); - if(deviceType!=null){ - shareDetailVo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode())); - } - shareDetailVo.setDevicePic(device.getDevicePic()); - shareDetailVo.setTypeName(deviceType.getTypeName()); - shareDetailVo.setBluetoothName(device.getBluetoothName()); - shareDetailVo.setDeviceStatus(device.getDeviceStatus()); - shareDetailVo.setSendMsg(device.getSendMsg()); - - LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); - qw.eq(AppPersonnelInfo::getDeviceId, device.getId()); - List appPersonnelInfoVos = appPersonnelInfoMapper.selectVoList(qw); - if(appPersonnelInfoVos!=null && !appPersonnelInfoVos.isEmpty()){ - shareDetailVo.setPersonnelInfo(appPersonnelInfoVos.get(0)); - } - - return shareDetailVo; - } - /** - * 校验短信验证码 - */ - private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { - String code = RedisUtils.getCacheObject(GlobalConstants.DEVICE_SHARE_CODES_KEY + phonenumber); - if (StringUtils.isBlank(code)) { - throw new ServiceException("验证码失效"); - } - return code.equals(smsCode); - } - public int deviceShare(AppDeviceShareBo bo) { - boolean flag = validateSmsCode(AppLoginHelper.getTenantId(), bo.getPhonenumber(), bo.getSmsCode()); - if(!flag){ - throw new ServiceException("验证码错误"); - } - - Device device = deviceMapper.selectById(bo.getDeviceId()); - if(device==null){ - throw new ServiceException("设备不存在"); - } - Long userId = AppLoginHelper.getUserId(); - LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); - lqw.eq(AppDeviceShare::getDeviceId, bo.getDeviceId()); - lqw.eq(AppDeviceShare::getPhonenumber, bo.getPhonenumber()); - Long count = appDeviceShareMapper.selectCount(lqw); - if(count>0){ - - UpdateWrapper uw = new UpdateWrapper<>(); - uw.eq("device_id", bo.getDeviceId()); - uw.eq("phonenumber", bo.getPhonenumber()); - uw.set("permission", bo.getPermission()); - uw.set("update_by", userId); - uw.set("update_time", new Date()); - - return appDeviceShareMapper.update(uw); - }else { - AppDeviceShare appDeviceShare = new AppDeviceShare(); - appDeviceShare.setDeviceId(bo.getDeviceId()); - appDeviceShare.setPhonenumber(bo.getPhonenumber()); - appDeviceShare.setPermission(bo.getPermission()); - appDeviceShare.setCreateBy(userId); - return appDeviceShareMapper.insert(appDeviceShare); - } - } - - public int remove(Long[] ids) { - return appDeviceShareMapper.deleteByIds(Arrays.asList(ids)); - } -} 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 66ea4dc..b27d57a 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 @@ -1,5 +1,9 @@ package com.fuyuanshen.global.mqtt.base; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import java.util.Comparator; @@ -11,7 +15,10 @@ import java.util.List; */ @Component public class MqttRuleEngine { - + + @Autowired + @Qualifier("threadPoolTaskExecutor") + private ThreadPoolTaskExecutor threadPoolTaskExecutor; private final LinkedHashMap rulesMap = new LinkedHashMap<>(); public MqttRuleEngine(List rules) { @@ -30,7 +37,7 @@ public class MqttRuleEngine { int commandType = context.getCommandType(); MqttMessageRule mqttMessageRule = rulesMap.get("Light_"+commandType); if (mqttMessageRule != null) { - mqttMessageRule.execute(context); + threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context)); return true; } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/LightingCommandTypeConstants.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/LightingCommandTypeConstants.java index c0f1ee7..de4e6b3 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/LightingCommandTypeConstants.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/LightingCommandTypeConstants.java @@ -35,6 +35,12 @@ public class LightingCommandTypeConstants { * 设备发送消息 */ public static final String SEND_MESSAGE = "Light_6"; + + + /** + * 报警模式 + */ + public static final String ALARM_MESSAGE = "Light_7"; /** * 定位数据 (Location Data) diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/RedisKeyExpirationListener.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/RedisKeyExpirationListener.java new file mode 100644 index 0000000..86e669a --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/RedisKeyExpirationListener.java @@ -0,0 +1,38 @@ +package com.fuyuanshen.global.mqtt.listener; + +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_TIMEOUT_KEY; + +@Component +@Slf4j +public class RedisKeyExpirationListener implements MessageListener { + + @Override + public void onMessage(Message message, byte[] pattern) { + String expiredKey = new String(message.getBody()); + + if (expiredKey.startsWith(FUNCTION_ACCESS_KEY)) { + String element = expiredKey.substring(FUNCTION_ACCESS_KEY.length()); + handleFunctionAccessExpired(element); + } + } + + /** + * 访问key过期事件 + * @param element 批次ID + */ + private void handleFunctionAccessExpired(String element) { + RedisUtils.setCacheObject(FUNCTION_ACCESS_TIMEOUT_KEY + element, FunctionAccessStatus.TIMEOUT.getCode(), Duration.ofSeconds(30L)); + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/config/RedisListenerConfig.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/config/RedisListenerConfig.java new file mode 100644 index 0000000..e6cea5b --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/config/RedisListenerConfig.java @@ -0,0 +1,25 @@ +package com.fuyuanshen.global.mqtt.listener.config; + +import com.fuyuanshen.global.mqtt.listener.RedisKeyExpirationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; + +@Configuration +public class RedisListenerConfig { + + @Bean + RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory, + RedisKeyExpirationListener redisKeyExpirationListener) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + + // 监听过期事件 + container.addMessageListener(redisKeyExpirationListener, new PatternTopic("__keyevent@*__:expired")); + return container; + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/domain/FunctionAccessResult.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/domain/FunctionAccessResult.java new file mode 100644 index 0000000..8e60962 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/domain/FunctionAccessResult.java @@ -0,0 +1,96 @@ +package com.fuyuanshen.global.mqtt.listener.domain; + +import lombok.Data; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +/** + * 功能访问状态对象 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FunctionAccessResult { + + /** + * 状态码 + */ + private String status; + + /** + * 消息描述 + */ + private String message; + + /** + * 时间戳 + */ + private Long timestamp; + + /** + * 设备IMEI(可选) + */ + private String deviceImei; + + /** + * 批次ID(可选) + */ + private String batchId; + + public FunctionAccessResult(String status, String message) { + this.status = status; + this.message = message; + this.timestamp = System.currentTimeMillis(); + } + + /** + * 创建失败状态对象 + * @param message 消息 + * @return FunctionAccessResult + */ + public static FunctionAccessResult failed(String message) { + return new FunctionAccessResult("FAILED", message); + } + + /** + * 创建成功状态对象 + * @param message 消息 + * @return FunctionAccessResult + */ + public static FunctionAccessResult ok(String message) { + return new FunctionAccessResult("OK", message); + } + + /** + * 创建超时状态对象 + * @param message 消息 + * @return FunctionAccessResult + */ + public static FunctionAccessResult timeout(String message) { + return new FunctionAccessResult("TIMEOUT", message); + } + + /** + * 判断是否为失败状态 + * @return boolean + */ + public boolean isFailed() { + return "FAILED".equals(this.status); + } + + /** + * 判断是否为成功状态 + * @return boolean + */ + public boolean isOk() { + return "OK".equals(this.status); + } + + /** + * 判断是否为超时状态 + * @return boolean + */ + public boolean isTimeout() { + return "TIMEOUT".equals(this.status); + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/domain/FunctionAccessStatus.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/domain/FunctionAccessStatus.java new file mode 100644 index 0000000..3359684 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/listener/domain/FunctionAccessStatus.java @@ -0,0 +1,62 @@ +package com.fuyuanshen.global.mqtt.listener.domain; + +/** + * 功能访问状态枚举 + */ +public enum FunctionAccessStatus { + + /** + * 失败状态 + */ + FAILED("FAILED", "失败"), + + /** + * 成功状态 + */ + OK("OK", "成功"), + + /** + * 激活中状态 + */ + ACTIVE("ACTIVE", "处理中"), + + /** + * 超时状态 + */ + TIMEOUT("TIMEOUT", "超时"); + + private final String code; + private final String description; + + FunctionAccessStatus(String code, String description) { + this.code = code; + this.description = description; + } + + public String getCode() { + return code; + } + + public String getDescription() { + return description; + } + + /** + * 根据代码获取状态枚举 + * @param code 状态代码 + * @return 对应的状态枚举 + */ + public static FunctionAccessStatus fromCode(String code) { + for (FunctionAccessStatus status : FunctionAccessStatus.values()) { + if (status.getCode().equals(code)) { + return status; + } + } + throw new IllegalArgumentException("未知的状态代码: " + code); + } + + @Override + public String toString() { + return code; + } +} 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 618758f..811acd5 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 @@ -49,7 +49,7 @@ public class ReceiverMessageHandler implements MessageHandler { if(StringUtils.isNotBlank(deviceImei)){ //在线状态 String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ; - RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(60*15)); + RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(62)); } String state = payloadDict.getStr("state"); diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqActiveReportingDeviceDataRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqActiveReportingDeviceDataRule.java index eacbcdb..bdc8237 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqActiveReportingDeviceDataRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqActiveReportingDeviceDataRule.java @@ -7,14 +7,17 @@ import com.fuyuanshen.global.mqtt.base.MqttMessageRule; import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX; /** @@ -44,16 +47,16 @@ public class BjqActiveReportingDeviceDataRule implements MqttMessageRule { String chargeState = convertArr[4].toString(); String batteryRemainingTime = convertArr[5].toString(); - // 异步发送设备状态和位置信息到Redis + // 发送设备状态和位置信息到Redis asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(), mainLightMode, laserLightMode, batteryPercentage, chargeState, batteryRemainingTime); } catch (Exception e) { - log.error("处理定位数据命令时出错", e); + log.error("处理上报数据命令时出错", e); } } /** - * 异步发送设备状态信息和位置信息到Redis(使用CompletableFuture) + * 发送设备状态信息和位置信息到Redis * * @param deviceImei 设备IMEI * @param mainLightMode 主灯档位 diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqAlarmRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqAlarmRule.java index 49c1af5..759f15b 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqAlarmRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqAlarmRule.java @@ -7,12 +7,15 @@ import com.fuyuanshen.global.mqtt.base.MqttMessageRule; import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.concurrent.CompletableFuture; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; /** @@ -25,45 +28,29 @@ public class BjqAlarmRule implements MqttMessageRule { @Override public String getCommandType() { - return LightingCommandTypeConstants.LIGHT_MODE; + return LightingCommandTypeConstants.ALARM_MESSAGE; } @Override public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); try { Object[] convertArr = context.getConvertArr(); - String mainLightMode = convertArr[1].toString(); - if(StringUtils.isNotBlank(mainLightMode)){ - // 异步发送设备状态和位置信息到Redis - asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode); - } + String convertValue = convertArr[1].toString(); + if(StringUtils.isNotBlank(convertValue)){ + // 将设备状态信息存储到Redis中 + String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX; + // 存储到Redis + RedisUtils.setCacheObject(deviceRedisKey, convertValue); + } + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); } catch (Exception e) { - log.error("处理灯光模式命令时出错", e); + log.error("处理告警命令时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); } } - /** - * 异步发送设备状态信息和位置信息到Redis(使用CompletableFuture) - * - * @param deviceImei 设备IMEI - */ - public void asyncSendDeviceDataToRedisWithFuture(String deviceImei,Object convertValue) { - CompletableFuture.runAsync(() -> { - try { - // 将设备状态信息存储到Redis中 - String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_ALARM_KEY_PREFIX; - - // 存储到Redis - RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString()); - - } catch (Exception e) { - log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e); - } - }); - } - - } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqBootLogoRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqBootLogoRule.java index 97fd0f3..2a95db7 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqBootLogoRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqBootLogoRule.java @@ -9,21 +9,24 @@ import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.config.MqttGateway; import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; import com.fuyuanshen.global.mqtt.constants.MqttConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_BOOT_LOGO_KEY_PREFIX; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; /** - * 人员信息命令处理 + * 上传开机图片命令处理 */ @Component @RequiredArgsConstructor @@ -39,9 +42,11 @@ public class BjqBootLogoRule implements MqttMessageRule { @Override public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); try { Byte val2 = (Byte) context.getConvertArr()[1]; if (val2 == 100) { + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); return; } @@ -53,7 +58,6 @@ public class BjqBootLogoRule implements MqttMessageRule { byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data); byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, (val2 - 1), 512); log.info("第{}块数据大小: {} 字节", val2, specificChunk.length); -// System.out.println("第" + val2 + "块数据: " + Arrays.toString(specificChunk)); ArrayList intData = new ArrayList<>(); intData.add(3); @@ -71,8 +75,10 @@ public class BjqBootLogoRule implements MqttMessageRule { log.info("发送开机LOGO点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), JsonUtils.toJsonString(map)); + } catch (Exception e) { log.error("处理开机LOGO时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); } } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLaserModeSettingsRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLaserModeSettingsRule.java new file mode 100644 index 0000000..b2bb339 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLaserModeSettingsRule.java @@ -0,0 +1,80 @@ +package com.fuyuanshen.global.mqtt.rule.bjq; + +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.global.mqtt.base.MqttMessageRule; +import com.fuyuanshen.global.mqtt.base.MqttRuleContext; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX; + +/** + * 灯光模式订阅设备回传消息 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class BjqLaserModeSettingsRule implements MqttMessageRule { + + @Override + public String getCommandType() { + return LightingCommandTypeConstants.LASER_LIGHT; + } + + @Override + public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); + try { + Object[] convertArr = context.getConvertArr(); + + String mainLightMode = convertArr[1].toString(); + if(StringUtils.isNotBlank(mainLightMode)){ + if("0".equals(mainLightMode)){ + String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ context.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ; + RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "0", Duration.ofSeconds(60*15)); + } + // 发送设备状态和位置信息到Redis + syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode); + } + + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30)); + } catch (Exception e) { + log.error("处理激光模式命令时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(30)); + } + } + + /** + * 发送设备状态信息和位置信息到Redis + * + * @param deviceImei 设备IMEI + */ + public void syncSendDeviceDataToRedisWithFuture(String deviceImei,Object convertValue) { +// CompletableFuture.runAsync(() -> { +// +// }); + try { + // 将设备状态信息存储到Redis中 + String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_LIGHT_MODE_KEY_PREFIX; + + // 存储到Redis + RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString()); + + } catch (Exception e) { + log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e); + } + } + + + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLightBrightnessRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLightBrightnessRule.java new file mode 100644 index 0000000..0fc6dd8 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLightBrightnessRule.java @@ -0,0 +1,51 @@ +package com.fuyuanshen.global.mqtt.rule.bjq; + +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.global.mqtt.base.MqttMessageRule; +import com.fuyuanshen.global.mqtt.base.MqttRuleContext; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; + +/** + * 灯光模式订阅设备回传消息 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class BjqLightBrightnessRule implements MqttMessageRule { + + @Override + public String getCommandType() { + return LightingCommandTypeConstants.MAIN_LIGHT_BRIGHTNESS; + } + + @Override + public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); + try { + Object[] convertArr = context.getConvertArr(); + + String convertValue = convertArr[1].toString(); + // 将设备状态信息存储到Redis中 + String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX; + + // 存储到Redis + RedisUtils.setCacheObject(deviceRedisKey, convertValue); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); + } catch (Exception e) { + log.error("处理灯光亮度命令时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); + } + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLocationDataRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLocationDataRule.java index b528a00..0c3bda1 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLocationDataRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqLocationDataRule.java @@ -13,16 +13,19 @@ import com.fuyuanshen.global.mqtt.config.MqttGateway; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; import com.fuyuanshen.global.mqtt.constants.MqttConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX; @@ -44,6 +47,7 @@ public class BjqLocationDataRule implements MqttMessageRule { @Override public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); try { Object[] convertArr = context.getConvertArr(); // Latitude, longitude @@ -58,8 +62,10 @@ public class BjqLocationDataRule implements MqttMessageRule { log.info("发送定位数据到设备=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), JsonUtils.toJsonString(map)); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); } catch (Exception e) { log.error("处理定位数据命令时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqModeRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqModeRule.java index 09aeacc..f16b77e 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqModeRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqModeRule.java @@ -7,6 +7,7 @@ import com.fuyuanshen.global.mqtt.base.MqttMessageRule; import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -14,8 +15,8 @@ import org.springframework.stereotype.Component; import java.time.Duration; import java.util.concurrent.CompletableFuture; -import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; -import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; /** * 灯光模式订阅设备回传消息 @@ -32,42 +33,50 @@ public class BjqModeRule implements MqttMessageRule { @Override public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); try { Object[] convertArr = context.getConvertArr(); String mainLightMode = convertArr[1].toString(); + String batteryRemainingTime = convertArr[2].toString(); if(StringUtils.isNotBlank(mainLightMode)){ if("0".equals(mainLightMode)){ String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ context.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ; RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "0", Duration.ofSeconds(60*15)); } - // 异步发送设备状态和位置信息到Redis - asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode); - } + // 发送设备状态和位置信息到Redis + syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode); + String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX; + // 存储到Redis + RedisUtils.setCacheObject(deviceRedisKey, batteryRemainingTime); + } + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); } catch (Exception e) { log.error("处理灯光模式命令时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); } } /** - * 异步发送设备状态信息和位置信息到Redis(使用CompletableFuture) + * 发送设备状态信息和位置信息到Redis * * @param deviceImei 设备IMEI */ - public void asyncSendDeviceDataToRedisWithFuture(String deviceImei,Object convertValue) { - CompletableFuture.runAsync(() -> { - try { - // 将设备状态信息存储到Redis中 - String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_LIGHT_MODE_KEY_PREFIX; + public void syncSendDeviceDataToRedisWithFuture(String deviceImei,Object convertValue) { +// CompletableFuture.runAsync(() -> { +// +// }); + try { + // 将设备状态信息存储到Redis中 + String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_LIGHT_MODE_KEY_PREFIX; - // 存储到Redis - RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString()); + // 存储到Redis + RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString()); - } catch (Exception e) { - log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e); - } - }); + } catch (Exception e) { + log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e); + } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqPersonnelInfoDataRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqPersonnelInfoDataRule.java new file mode 100644 index 0000000..2a1b6d6 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqPersonnelInfoDataRule.java @@ -0,0 +1,58 @@ +package com.fuyuanshen.global.mqtt.rule.bjq; + +import com.alibaba.fastjson2.JSONObject; +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.json.utils.JsonUtils; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil; +import com.fuyuanshen.equipment.utils.map.LngLonUtil; +import com.fuyuanshen.global.mqtt.base.MqttMessageRule; +import com.fuyuanshen.global.mqtt.base.MqttRuleContext; +import com.fuyuanshen.global.mqtt.config.MqttGateway; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; +import com.fuyuanshen.global.mqtt.constants.MqttConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; + +/** + * 定位数据命令处理 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class BjqPersonnelInfoDataRule implements MqttMessageRule { + + private final MqttGateway mqttGateway; + + + @Override + public String getCommandType() { + return LightingCommandTypeConstants.PERSONNEL_INFO; + } + + @Override + public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); + try { + Object[] convertArr = context.getConvertArr(); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30)); + } catch (Exception e) { + log.error("处理定位数据命令时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(30)); + } + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqSendMessageRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqSendMessageRule.java index c9b50e1..7dc5093 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqSendMessageRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/bjq/BjqSendMessageRule.java @@ -9,14 +9,17 @@ import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.config.MqttGateway; import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; import com.fuyuanshen.global.mqtt.constants.MqttConstants; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; @@ -38,9 +41,11 @@ public class BjqSendMessageRule implements MqttMessageRule { @Override public void execute(MqttRuleContext context) { + String functionAccess = FUNCTION_ACCESS_KEY + context.getDeviceImei(); try { Byte val2 = (Byte) context.getConvertArr()[1]; if (val2 == 100) { + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); return; } @@ -70,8 +75,10 @@ public class BjqSendMessageRule implements MqttMessageRule { log.info("发送设备信息数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + context.getDeviceImei(), JsonUtils.toJsonString(map)); + } catch (Exception e) { log.error("处理发送设备信息时出错", e); + RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); } } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/ChineseVCardGenerator.java b/fys-admin/src/main/java/com/fuyuanshen/web/ChineseVCardGenerator.java new file mode 100644 index 0000000..d856a73 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/ChineseVCardGenerator.java @@ -0,0 +1,64 @@ +package com.fuyuanshen.web; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class ChineseVCardGenerator { + public static void main(String[] args) { + // 定义江西上饶的134号段(共22个) + String[] prefixes = { + "1340703", "1340793", "1342650", "1342651", "1342663", + "1342664", "1342665", "1343703", "1343793", "1347901", + "1347902", "1347903", "1347930", "1347931", "1347932", + "1347933", "1347934", "1347935", "1347936", "1347937", + "1347938", "1347939" + }; + + // 创建.vcf文件 + String filename = "上饶联系人.vcf"; + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true))) { + // 添加文件头信息(包含中文) + writer.write("BEGIN:VCARD"); + writer.newLine(); + writer.write("VERSION:3.0"); + writer.newLine(); + writer.write("X-GENERATOR:Java VCard Generator"); + writer.newLine(); + writer.write("PRODID:-//Apple Inc.//iPhone OS 15.6//EN"); + writer.newLine(); + writer.newLine(); + + // 生成所有联系人 + int count = 0; + for (String prefix : prefixes) { + for (int i = 0; i < 100; i++) { + String middle = String.format("%02d", i); + String phoneNumber = prefix + middle + "51"; + + // 写入单个联系人(使用中文) + writer.write("FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:用户" + (count + 1)); // 中文姓名 + writer.newLine(); + writer.write("TEL;TYPE=CELL;CHARSET=UTF-8:" + phoneNumber); // 手机号 + writer.newLine(); + writer.write("NOTE;CHARSET=UTF-8:生成时间 " + new SimpleDateFormat("yyyy-MM-dd").format(new Date())); + writer.newLine(); + writer.write("END:VCARD"); + writer.newLine(); + writer.newLine(); + + count++; + } + } + + System.out.println("成功生成 " + count + " 个中文联系人"); + System.out.println("文件已保存为: " + filename); + + } catch (IOException e) { + System.err.println("文件写入错误: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/PhoneNumberGenerator.java b/fys-admin/src/main/java/com/fuyuanshen/web/PhoneNumberGenerator.java new file mode 100644 index 0000000..56536d8 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/PhoneNumberGenerator.java @@ -0,0 +1,41 @@ +package com.fuyuanshen.web; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +public class PhoneNumberGenerator { + public static void main(String[] args) { + // 定义江西上饶的134号段(共22个) + String[] prefixes = { + "1340703", "1340793", "1342650", "1342651", "1342663", + "1342664", "1342665", "1343703", "1343793", "1347901", + "1347902", "1347903", "1347930", "1347931", "1347932", + "1347933", "1347934", "1347935", "1347936", "1347937", + "1347938", "1347939" + }; + + // 输出到控制台 + System.out.println("江西上饶134号段完整手机号码(共2200个):"); + for (String prefix : prefixes) { + for (int i = 0; i < 100; i++) { + String middle = String.format("%02d", i); // 生成00-99的中间数字 + System.out.println(prefix + middle + "51"); + } + } + + // 同时输出到文件(可选) + try (BufferedWriter writer = new BufferedWriter(new FileWriter("shangrao_phones.txt"))) { + for (String prefix : prefixes) { + for (int i = 0; i < 100; i++) { + String middle = String.format("%02d", i); + writer.write(prefix + middle + "51"); + writer.newLine(); + } + } + System.out.println("\n同时已保存到文件:shangrao_phones.txt"); + } catch (IOException e) { + System.err.println("文件写入错误:" + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/VCardGenerator.java b/fys-admin/src/main/java/com/fuyuanshen/web/VCardGenerator.java new file mode 100644 index 0000000..9a1f507 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/VCardGenerator.java @@ -0,0 +1,59 @@ +package com.fuyuanshen.web; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +public class VCardGenerator { + public static void main(String[] args) { + // 定义江西上饶的134号段(共22个) + String[] prefixes = { + "1340703", "1340793", "1342650", "1342651", "1342663", + "1342664", "1342665", "1343703", "1343793", "1347901", + "1347902", "1347903", "1347930", "1347931", "1347932", + "1347933", "1347934", "1347935", "1347936", "1347937", + "1347938", "1347939" + }; + + // 创建.vcf文件 + String filename = "shangrao_contacts.vcf"; + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) { + // 写入文件头 + writer.write("BEGIN:VCARD"); + writer.newLine(); + writer.write("VERSION:3.0"); + writer.newLine(); + writer.newLine(); + + // 生成所有联系人 + int count = 0; + for (String prefix : prefixes) { + for (int i = 0; i < 100; i++) { + String middle = String.format("%02d", i); + String phoneNumber = prefix + middle + "51"; + + // 写入单个联系人 + writer.write("FN:" + phoneNumber); // 姓名字段使用手机号 + writer.newLine(); + writer.write("TEL;TYPE=CELL:" + phoneNumber); // 电话字段使用手机号 + writer.newLine(); + writer.write("END:VCARD"); + writer.newLine(); + writer.newLine(); + + count++; + } + } + + // 写入文件尾 + writer.write("END:VCARD"); + + System.out.println("成功生成 " + count + " 个联系人"); + System.out.println("文件已保存为: " + filename); + + } catch (IOException e) { + System.err.println("文件写入错误: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/config/CustomMqttInboundConfiguration.java b/fys-admin/src/main/java/com/fuyuanshen/web/config/CustomMqttInboundConfiguration.java index faa8cb5..afefa34 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/config/CustomMqttInboundConfiguration.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/config/CustomMqttInboundConfiguration.java @@ -1,61 +1,61 @@ -package com.fuyuanshen.web.config; - -import cn.hutool.core.lang.UUID; -import com.fuyuanshen.global.mqtt.config.MqttPropertiesConfig; -import com.fuyuanshen.web.handler.mqtt.DeviceReceiverMessageHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.integration.annotation.ServiceActivator; -import org.springframework.integration.channel.DirectChannel; -import org.springframework.integration.core.MessageProducer; -import org.springframework.integration.mqtt.core.MqttPahoClientFactory; -import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; -import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.MessageHandler; - -/** - * @author: 默苍璃 - * @date: 2025-08-0110:46 - */ -@Configuration -public class CustomMqttInboundConfiguration { - - @Autowired - private MqttPropertiesConfig mqttPropertiesConfig; - @Autowired - private MqttPahoClientFactory mqttPahoClientFactory; - @Autowired - private DeviceReceiverMessageHandler deviceReceiverMessageHandler; - - - @Bean - public MessageChannel customMqttChannel(){ - return new DirectChannel(); - } - - - @Bean - public MessageProducer customMessageProducer(){ - String clientId = "custom_client_" + UUID.fastUUID(); - MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter( - mqttPropertiesConfig.getUrl(), - clientId, - mqttPahoClientFactory, - "A/#", "B/#" // 直接指定这两个主题 - ); - adapter.setQos(1); - adapter.setConverter(new DefaultPahoMessageConverter()); - adapter.setOutputChannel(customMqttChannel()); - return adapter; - } - - - @Bean - @ServiceActivator(inputChannel = "customMqttChannel") - public MessageHandler customMessageHandler(){ - return deviceReceiverMessageHandler; - } - -} +//package com.fuyuanshen.web.config; +// +//import cn.hutool.core.lang.UUID; +//import com.fuyuanshen.global.mqtt.config.MqttPropertiesConfig; +//import com.fuyuanshen.web.handler.mqtt.DeviceReceiverMessageHandler; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.integration.annotation.ServiceActivator; +//import org.springframework.integration.channel.DirectChannel; +//import org.springframework.integration.core.MessageProducer; +//import org.springframework.integration.mqtt.core.MqttPahoClientFactory; +//import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; +//import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; +//import org.springframework.messaging.MessageChannel; +//import org.springframework.messaging.MessageHandler; +// +///** +// * @author: 默苍璃 +// * @date: 2025-08-0110:46 +// */ +//@Configuration +//public class CustomMqttInboundConfiguration { +// +// @Autowired +// private MqttPropertiesConfig mqttPropertiesConfig; +// @Autowired +// private MqttPahoClientFactory mqttPahoClientFactory; +// @Autowired +// private DeviceReceiverMessageHandler deviceReceiverMessageHandler; +// +// +// @Bean +// public MessageChannel customMqttChannel(){ +// return new DirectChannel(); +// } +// +// +// @Bean +// public MessageProducer customMessageProducer(){ +// String clientId = "custom_client_" + UUID.fastUUID(); +// MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter( +// mqttPropertiesConfig.getUrl(), +// clientId, +// mqttPahoClientFactory, +// "A/#", "B/#" // 直接指定这两个主题 +// ); +// adapter.setQos(1); +// adapter.setConverter(new DefaultPahoMessageConverter()); +// adapter.setOutputChannel(customMqttChannel()); +// return adapter; +// } +// +// +// @Bean +// @ServiceActivator(inputChannel = "customMqttChannel") +// public MessageHandler customMessageHandler(){ +// return deviceReceiverMessageHandler; +// } +// +//} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceHBYController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java similarity index 72% rename from fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceHBYController.java rename to fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java index 93a2204..d42d522 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceHBYController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java @@ -1,14 +1,16 @@ -package com.fuyuanshen.app.controller.device; +package com.fuyuanshen.web.controller.device; 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.app.service.AppDeviceBizService; 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; @@ -16,16 +18,15 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; /** - * HBY210设备控制类 + * BJQ6170设备控制类 */ @Validated @RequiredArgsConstructor @RestController -@RequestMapping("/app/hby/device") -public class AppDeviceHBYController extends BaseController { - - private final AppDeviceBizService appDeviceService; +@RequestMapping("/api/bjq/device") +public class DeviceBJQController extends BaseController { + private final DeviceBJQBizService appDeviceService; /** * 获取设备详细信息 @@ -42,6 +43,7 @@ public class AppDeviceHBYController extends BaseController { * 人员信息登记 */ @PostMapping(value = "/registerPersonInfo") +// @FunctionAccessAnnotation("registerPersonInfo") public R registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) { return toAjax(appDeviceService.registerPersonInfo(bo)); } @@ -50,14 +52,25 @@ public class AppDeviceHBYController extends BaseController { * 发送信息 */ @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(); @@ -73,6 +86,7 @@ public class AppDeviceHBYController extends BaseController { * 灯光模式 * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) */ +// @FunctionAccessAnnotation("lightModeSettings") @PostMapping("/lightModeSettings") public R lightModeSettings(@RequestBody DeviceInstructDto params) { // params 转 JSONObject @@ -84,6 +98,7 @@ public class AppDeviceHBYController extends BaseController { * 灯光亮度设置 * */ +// @FunctionAccessAnnotation("lightBrightnessSettings") @PostMapping("/lightBrightnessSettings") public R lightBrightnessSettings(@RequestBody DeviceInstructDto params) { appDeviceService.lightBrightnessSettings(params); @@ -95,18 +110,10 @@ public class AppDeviceHBYController extends BaseController { * */ @PostMapping("/laserModeSettings") +// @FunctionAccessAnnotation("laserModeSettings") public R laserModeSettings(@RequestBody DeviceInstructDto params) { appDeviceService.laserModeSettings(params); return R.ok(); } - /** - * 地图逆解析 - * - */ - @PostMapping("/mapReverseGeocoding") - public R mapReverseGeocoding(@RequestBody DeviceInstructDto params) { - String mapJson = appDeviceService.mapReverseGeocoding(params); - return R.ok(mapJson); - } } 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 new file mode 100644 index 0000000..13b3471 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceControlCenterController.java @@ -0,0 +1,210 @@ +package com.fuyuanshen.web.controller.device; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author: 默苍璃 + * @date: 2025-08-0810:40 + */ +@Slf4j +@Tag(name = "web后台:设备控制中心", description = "web后台:设备控制中心") +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/device/controlCenter") +public class DeviceControlCenterController { + + /** + * 获取设备基本信息 + * @param deviceId 设备ID + * @return 设备基本信息 + */ + @GetMapping("/info/{deviceId}") + public ResponseEntity> getDeviceInfo(@PathVariable String deviceId) { + // 实际应用中这里会从数据库查询设备信息 + Map deviceInfo = new HashMap<>(); + deviceInfo.put("deviceName", "6170零零一"); + deviceInfo.put("deviceModel", "BJQ6170"); + deviceInfo.put("deviceId", deviceId); + deviceInfo.put("status", "在线"); + deviceInfo.put("batteryLevel", 85); + + return ResponseEntity.ok(deviceInfo); + } + + /** + * 设置灯光模式 + * @param lightModeRequest 灯光模式请求 + * @return 操作结果 + */ + @PostMapping("/light-mode") + public ResponseEntity> setLightMode(@RequestBody LightModeRequest lightModeRequest) { + // 实际应用中这里会控制设备灯光 + Map response = new HashMap<>(); + response.put("code", 200); + // response.put("message", "灯光模式已设置为: " + lightModeRequest.getMode()); + // response.put("deviceId", lightModeRequest.getDeviceId()); + // response.put("mode", lightModeRequest.getMode()); + + return ResponseEntity.ok(response); + } + + /** + * 更新人员信息 + * @param personInfo 人员信息 + * @return 操作结果 + */ + @PostMapping("/person-info") + public ResponseEntity> updatePersonInfo(@RequestBody PersonInfo personInfo) { + // 实际应用中这里会更新数据库 + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "人员信息已更新"); + // response.put("unit", personInfo.getUnit()); + // response.put("position", personInfo.getPosition()); + + return ResponseEntity.ok(response); + } + + /** + * 管理开机画面内容 + * @param bootScreenRequest 开机画面请求 + * @return 操作结果 + */ + @PostMapping("/boot-screen") + public ResponseEntity> manageBootScreen(@RequestBody BootScreenRequest bootScreenRequest) { + // 实际应用中这里会更新设备开机画面 + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "开机画面内容已更新"); + // response.put("deviceId", bootScreenRequest.getDeviceId()); + // response.put("screens", bootScreenRequest.getScreens()); + + return ResponseEntity.ok(response); + } + + /** + * 设置灯光亮度 + * @param brightnessRequest 亮度请求 + * @return 操作结果 + */ + @PostMapping("/brightness") + public ResponseEntity> setBrightness(@RequestBody BrightnessRequest brightnessRequest) { + // 实际应用中这里会控制设备亮度 + Map response = new HashMap<>(); + response.put("code", 200); + // response.put("message", "灯光亮度已设置为: " + brightnessRequest.getBrightness() + "%"); + // response.put("deviceId", brightnessRequest.getDeviceId()); + // response.put("brightness", brightnessRequest.getBrightness()); + // response.put("forceAlarm", brightnessRequest.isForceAlarm()); + + return ResponseEntity.ok(response); + } + + /** + * 获取设备位置信息 + * @param deviceId 设备ID + * @return 位置信息 + */ + @GetMapping("/location/{deviceId}") + public ResponseEntity> getLocation(@PathVariable String deviceId) { + // 实际应用中这里会从设备获取实时位置 + Map locationInfo = new HashMap<>(); + locationInfo.put("deviceId", deviceId); + locationInfo.put("longitude", "114°7'E"); + locationInfo.put("latitude", "30'28'N"); + locationInfo.put("address", "湖北省武汉市洪山区光谷大道国际企业中心"); + locationInfo.put("timestamp", new Date()); + + return ResponseEntity.ok(locationInfo); + } + + /** + * 发送紧急消息 + * @param messageRequest 消息请求 + * @return 操作结果 + */ + @PostMapping("/send-message") + public ResponseEntity> sendMessage(@RequestBody MessageRequest messageRequest) { + // 实际应用中这里会向设备发送消息 + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "消息已发送"); + // response.put("deviceId", messageRequest.getDeviceId()); + // response.put("content", messageRequest.getContent()); + response.put("timestamp", new Date()); + + return ResponseEntity.ok(response); + } + + /** + * 管理操作视频 + * @param videoRequest 视频请求 + * @return 操作结果 + */ + @PostMapping("/operation-video") + public ResponseEntity> manageOperationVideo(@RequestBody VideoRequest videoRequest) { + // 实际应用中这里会更新设备操作视频 + Map response = new HashMap<>(); + response.put("code", 200); + response.put("message", "操作视频已更新"); + // response.put("deviceId", videoRequest.getDeviceId()); + // response.put("videoUrl", videoRequest.getVideoUrl()); + + return ResponseEntity.ok(response); + } + + // 请求对象类定义 + public static class LightModeRequest { + private String deviceId; + private String mode; // 强光、弱光、爆闪、泛光、激光 + + // Getters and Setters + } + + public static class PersonInfo { + private String deviceId; + private String unit; // 单位 + private String position; // 职位 + + // Getters and Setters + } + + public static class BootScreenRequest { + private String deviceId; + private List screens; // 产品参数、操作说明等 + + // Getters and Setters + } + + public static class BrightnessRequest { + private String deviceId; + private int brightness; // 0-100 + private boolean forceAlarm; // 强制报警 + + // Getters and Setters + } + + public static class MessageRequest { + private String deviceId; + private String content; // 消息内容 + + // Getters and Setters + } + + public static class VideoRequest { + private String deviceId; + private String videoUrl; // 视频链接 + + // Getters and Setters + } + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceGroupController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceGroupController.java new file mode 100644 index 0000000..0f0eafa --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceGroupController.java @@ -0,0 +1,109 @@ +package com.fuyuanshen.web.controller.device; + +import java.util.List; + +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit; +import com.fuyuanshen.common.log.annotation.Log; +import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.common.log.enums.BusinessType; +import com.fuyuanshen.common.excel.utils.ExcelUtil; +import com.fuyuanshen.equipment.domain.vo.DeviceGroupVo; +import com.fuyuanshen.equipment.domain.bo.DeviceGroupBo; +import com.fuyuanshen.equipment.service.IDeviceGroupService; + +/** + * 设备分组 + * + * @author Lion Li + * @date 2025-08-08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/device/group") +public class DeviceGroupController extends BaseController { + + private final IDeviceGroupService deviceGroupService; + + + /** + * 查询设备分组列表 + */ + @SaCheckPermission("fys-equipment:group:list") + @GetMapping("/list") + public R> list(DeviceGroupBo bo) { + List list = deviceGroupService.queryList(bo); + return R.ok(list); + } + + + /** + * 导出设备分组列表 + */ + @SaCheckPermission("fys-equipment:group:export") + @Log(title = "设备分组", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DeviceGroupBo bo, HttpServletResponse response) { + List list = deviceGroupService.queryList(bo); + ExcelUtil.exportExcel(list, "设备分组", DeviceGroupVo.class, response); + } + + + /** + * 获取设备分组详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("fys-equipment:group:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(deviceGroupService.queryById(id)); + } + + + /** + * 新增设备分组 + */ + @SaCheckPermission("fys-equipment:group:add") + @Log(title = "设备分组", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DeviceGroupBo bo) { + return toAjax(deviceGroupService.insertByBo(bo)); + } + + + /** + * 修改设备分组 + */ + @SaCheckPermission("fys-equipment:group:edit") + @Log(title = "设备分组", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DeviceGroupBo bo) { + return toAjax(deviceGroupService.updateByBo(bo)); + } + + /** + * 删除设备分组 + * + * @param ids 主键串 + */ + @SaCheckPermission("fys-equipment:group:remove") + @Log(title = "设备分组", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { + return toAjax(deviceGroupService.deleteWithValidByIds(List.of(ids), true)); + } + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/WEBDeviceController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/WEBDeviceController.java index eadb157..0d19676 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/WEBDeviceController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/WEBDeviceController.java @@ -1,16 +1,27 @@ package com.fuyuanshen.web.controller.device; +import com.fuyuanshen.app.domain.dto.APPReNameDTO; +import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto; +import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo; import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.equipment.domain.dto.AppDeviceBo; +import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria; +import com.fuyuanshen.equipment.domain.vo.AppDeviceVo; import com.fuyuanshen.web.service.WEBDeviceService; +import com.fuyuanshen.web.service.device.DeviceBizService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; /** * @Description: @@ -25,7 +36,7 @@ import org.springframework.web.bind.annotation.RestController; public class WEBDeviceController extends BaseController { private final WEBDeviceService deviceService; - + private final DeviceBizService appDeviceService; /** * @param id @@ -41,6 +52,67 @@ public class WEBDeviceController extends BaseController { } + + + /** + * 查询设备列表 + */ + @GetMapping("/list") + public TableDataInfo list(DeviceQueryCriteria bo, PageQuery pageQuery) { + return appDeviceService.queryAppDeviceList(bo,pageQuery); + } + + /** + * 绑定设备 + */ + @PostMapping("/bind") + public R bind(@RequestBody AppDeviceBo bo) { + return toAjax(appDeviceService.bindDevice(bo)); + } + + + /** + * 解绑设备 + */ + @DeleteMapping("/unBind") + public R unBind(Long id) { + return toAjax(appDeviceService.unBindDevice(id)); + } + + /** + * 查询设备类型列表 + */ + @GetMapping(value = "/typeList") + public R> getTypeList() { + List typeList = appDeviceService.getTypeList(); + return R.ok(typeList); + } + + /** + * 重命名设备 + * @param reNameDTO + * @return + */ + @PostMapping(value = "/reName") + public R reName(@Validated @RequestBody APPReNameDTO reNameDTO) { + appDeviceService.reName(reNameDTO); + return R.ok("重命名成功!!!"); + } + + + @GetMapping("/realTimeStatus") + public R> getRealTimeStatus(AppRealTimeStatusDto statusDto) { + Map status = appDeviceService.getRealTimeStatus(statusDto); + return R.ok(status); + } + + /** + * 根据mac查询设备信息 + */ + @GetMapping("/getDeviceInfoByDeviceMac") + public R getDeviceInfo(String deviceMac) { + return R.ok(appDeviceService.getDeviceInfo(deviceMac)); + } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/handler/mqtt/DeviceReceiverMessageHandler.java b/fys-admin/src/main/java/com/fuyuanshen/web/handler/mqtt/DeviceReceiverMessageHandler.java index b43d75f..ad080ac 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/handler/mqtt/DeviceReceiverMessageHandler.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/handler/mqtt/DeviceReceiverMessageHandler.java @@ -1,318 +1,318 @@ -package com.fuyuanshen.web.handler.mqtt; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fuyuanshen.common.satoken.utils.LoginHelper; -import com.fuyuanshen.equipment.domain.Device; -import com.fuyuanshen.equipment.domain.DeviceLog; -import com.fuyuanshen.equipment.mapper.DeviceLogMapper; -import com.fuyuanshen.equipment.mapper.DeviceMapper; -import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil; -import com.fuyuanshen.equipment.utils.map.LngLonUtil; -import com.fuyuanshen.global.mqtt.constants.TenantsConstant; -import com.fuyuanshen.web.enums.InstructType6170; -import com.fuyuanshen.web.enums.LightModeEnum6170; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHandler; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.MessagingException; -import org.springframework.stereotype.Component; - -/** - * 定义监听主题消息的处理器 - * - * @author: 默苍璃 - * @date: 2025-08-0110:19 - */ -@Component -@Data -@AllArgsConstructor -@Slf4j -public class DeviceReceiverMessageHandler implements MessageHandler { - - private final DeviceMapper deviceMapper; - private final DeviceLogMapper deviceLogMapper; - - // 使用Jackson解析JSON - private static final ObjectMapper objectMapper = new ObjectMapper(); - - - /** - * 处理接收的消息 - * - * @param message - * @throws MessagingException - */ - @Override - public void handleMessage(Message message) throws MessagingException { - // System.out.println("接收到的消息:" + message.getPayload()); - MessageHeaders headers = message.getHeaders(); - String receivedTopicName = (String) headers.get("mqtt_receivedTopic"); - System.out.println("消息来自主题:" + receivedTopicName); - - // String tenantId = LoginHelper.getTenantId(); - String tenantId = TenantsConstant.FU_YUAN_SHENG; - String payload = message.getPayload().toString(); - - if (receivedTopicName != null) { - // 1. 提取设备ID (从主题中获取) - String deviceImei = extractDeviceId(receivedTopicName); - Device device = deviceMapper.selectOne(new QueryWrapper() - .eq("tenant_id", tenantId) - .eq("device_imei", deviceImei)); - if (device == null) { - log.info("不存在的设备IMEI: {}", deviceImei); - } else { - - try { - JsonNode root = objectMapper.readTree(payload); - - DeviceLog record = new DeviceLog(); - // 手动设置租户ID - record.setTenantId(device.getTenantId()); // 从设备信息中获取租户ID - // 设备ID - record.setDeviceId(device.getId()); - // 设备名称 - record.setDeviceName(device.getDeviceName()); - - // 2. 处理instruct消息 - if (root.has("instruct")) { - JsonNode instructNode = root.get("instruct"); - if (instructNode.isArray()) { - boolean b = receivedTopicName.startsWith("B/"); - record = parseInstruct(device, instructNode, b); - // 根据不同主题进行不同处理 - if (receivedTopicName.startsWith("A/")) { - // 处理A主题的消息(设备上传) - record.setDataSource("设备上报"); - } else if (receivedTopicName.startsWith("B/")) { - // 处理B主题的消息 (手动上传) - record.setDataSource("客户端操作"); - } - } - // 确保在插入前设置tenantId和deviceId - record.setTenantId(device.getTenantId()); - record.setDeviceId(device.getId()); - deviceLogMapper.insert(record); - } - - // 2. 处理 state 消息 - if (root.has("state")) { - JsonNode instructNode = root.get("state"); - if (instructNode.isArray()) { - boolean b = receivedTopicName.startsWith("B/"); - record = parseState(device, instructNode, b); - // 根据不同主题进行不同处理 - if (receivedTopicName.startsWith("A/")) { - // 处理A主题的消息(设备上传) - record.setDataSource("设备上报"); - } else if (receivedTopicName.startsWith("B/")) { - // 处理B主题的消息 (手动上传) - record.setDataSource("客户端操作"); - } - } - // 确保在插入前设置tenantId和deviceId - record.setTenantId(device.getTenantId()); - record.setDeviceId(device.getId()); - deviceLogMapper.insert(record); - } - - if (root.has("imei")) { - // 设备行为 - record.setDeviceAction(InstructType6170.fromCode(0).getDescription()); - record.setDataSource("设备上报"); - record.setContent("设备启动"); - // 确保在插入前设置tenantId和deviceId - record.setTenantId(device.getTenantId()); - record.setDeviceId(device.getId()); - deviceLogMapper.insert(record); - } - - - // 3. 处理state消息 - // else if (root.has("state")) { - // JsonNode stateNode = root.get("state"); - // if (stateNode.isArray()) { - // StateRecord record = parseState(device, stateNode); - // stateRepo.save(record); - // } - // } - } catch (Exception e) { - log.error("消息解析失败: {}", payload, e); - } - - } - - } - } - - - /** - * 从主题中提取设备ID(IMEI) - * - * @param topic - * @return - */ - private String extractDeviceId(String topic) { - // 处理 A/# 或 B/# 格式的主题,例如 B/861556078765285 或 A/861556078765285 - String[] segments = topic.split("/"); - if (segments.length >= 2) { - // 返回第二个段,即 / 后面的部分 - return segments[1]; - } - // 如果格式不符合预期,返回原主题 - return topic; - } - - - /** - * 解析instruct消息 - * - * @param device - * @param array - * @param b - * @return - */ - private DeviceLog parseInstruct(Device device, JsonNode array, boolean b) { - DeviceLog record = new DeviceLog(); - record.setDeviceName(device.getDeviceName()); - // 设备行为 - record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription()); - - switch (array.get(0).asInt()) { - case 1: // 灯光模式 - LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt()); - record.setContent(lightModeEnum6170.getDescription()); - break; - - case 2: // 单位/姓名/职位 - byte[] unitBytes = new byte[480]; - for (int i = 1; i <= 480; i++) { - unitBytes[i - 1] = (byte) array.get(i).asInt(); - } - // record.setUnitData(unitBytes); - break; - - case 3: // 开机图片 - // record.setImagePage(array.get(1).asInt()); - byte[] imageBytes = new byte[512]; - for (int i = 2; i <= 513; i++) { - imageBytes[i - 2] = (byte) array.get(i).asInt(); - } - // record.setImageData(imageBytes); - break; - - case 4: // 激光灯 - int anInt = array.get(1).asInt(); - if (anInt == 0) { - record.setContent("关闭激光灯"); - } else if (anInt == 1) { - record.setContent("开启激光灯"); - } else { - record.setContent("未知操作"); - } - break; - - case 5: // 亮度调节 - record.setContent(+array.get(1).asInt() + "%"); - break; - - case 11: // 定位数据 - if (b) { - break; - } - int i1 = array.get(1).asInt(); - int i2 = array.get(2).asInt(); - int i3 = array.get(3).asInt(); - int i4 = array.get(4).asInt(); - - // 优雅的转换方式 Longitude and latitude - double latitude = i1 + i2 / 10.0; - double Longitude = i3 + i4 / 10.0; - // 84 ==》 高德 - double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude); - String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0])); - record.setContent(address); - break; - } - return record; - } - - - /** - * 解析 state 消息 - * - * @param device - * @param array - * @return - */ - private DeviceLog parseState(Device device, JsonNode array, boolean b) { - DeviceLog record = new DeviceLog(); - record.setDeviceName(device.getDeviceName()); - // 设备行为 - record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription()); - - switch (array.get(0).asInt()) { - case 1: // 灯光模式 - LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt()); - record.setContent(lightModeEnum6170.getDescription()); - break; - - case 2: // 单位/姓名/职位 - byte[] unitBytes = new byte[480]; - for (int i = 1; i <= 480; i++) { - unitBytes[i - 1] = (byte) array.get(i).asInt(); - } - // record.setUnitData(unitBytes); - break; - - case 3: // 开机图片 - // record.setImagePage(array.get(1).asInt()); - byte[] imageBytes = new byte[512]; - for (int i = 2; i <= 513; i++) { - imageBytes[i - 2] = (byte) array.get(i).asInt(); - } - // record.setImageData(imageBytes); - break; - - case 4: // 激光灯 - int anInt = array.get(1).asInt(); - if (anInt == 0) { - record.setContent("关闭激光灯"); - } else if (anInt == 1) { - record.setContent("开启激光灯"); - } else { - record.setContent("未知操作"); - } - break; - - case 5: // 亮度调节 - record.setContent(+array.get(1).asInt() + "%"); - break; - - case 11: // 定位数据 - if (b) { - break; - } - int i1 = array.get(1).asInt(); - int i2 = array.get(2).asInt(); - int i3 = array.get(3).asInt(); - int i4 = array.get(4).asInt(); - - // 优雅的转换方式 Longitude and latitude - double latitude = i1 + i2 / 10.0; - double Longitude = i3 + i4 / 10.0; - // 84 ==》 高德 - double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude); - String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0])); - record.setContent(address); - break; - } - return record; - } - -} +//package com.fuyuanshen.web.handler.mqtt; +// +//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +//import com.fasterxml.jackson.databind.JsonNode; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.fuyuanshen.common.satoken.utils.LoginHelper; +//import com.fuyuanshen.equipment.domain.Device; +//import com.fuyuanshen.equipment.domain.DeviceLog; +//import com.fuyuanshen.equipment.mapper.DeviceLogMapper; +//import com.fuyuanshen.equipment.mapper.DeviceMapper; +//import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil; +//import com.fuyuanshen.equipment.utils.map.LngLonUtil; +//import com.fuyuanshen.global.mqtt.constants.TenantsConstant; +//import com.fuyuanshen.web.enums.InstructType6170; +//import com.fuyuanshen.web.enums.LightModeEnum6170; +//import lombok.AllArgsConstructor; +//import lombok.Data; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.messaging.Message; +//import org.springframework.messaging.MessageHandler; +//import org.springframework.messaging.MessageHeaders; +//import org.springframework.messaging.MessagingException; +//import org.springframework.stereotype.Component; +// +///** +// * 定义监听主题消息的处理器 +// * +// * @author: 默苍璃 +// * @date: 2025-08-0110:19 +// */ +//@Component +//@Data +//@AllArgsConstructor +//@Slf4j +//public class DeviceReceiverMessageHandler implements MessageHandler { +// +// private final DeviceMapper deviceMapper; +// private final DeviceLogMapper deviceLogMapper; +// +// // 使用Jackson解析JSON +// private static final ObjectMapper objectMapper = new ObjectMapper(); +// +// +// /** +// * 处理接收的消息 +// * +// * @param message +// * @throws MessagingException +// */ +// @Override +// public void handleMessage(Message message) throws MessagingException { +// // System.out.println("接收到的消息:" + message.getPayload()); +// MessageHeaders headers = message.getHeaders(); +// String receivedTopicName = (String) headers.get("mqtt_receivedTopic"); +// System.out.println("消息来自主题:" + receivedTopicName); +// +// // String tenantId = LoginHelper.getTenantId(); +// String tenantId = TenantsConstant.FU_YUAN_SHENG; +// String payload = message.getPayload().toString(); +// +// if (receivedTopicName != null) { +// // 1. 提取设备ID (从主题中获取) +// String deviceImei = extractDeviceId(receivedTopicName); +// Device device = deviceMapper.selectOne(new QueryWrapper() +// .eq("tenant_id", tenantId) +// .eq("device_imei", deviceImei)); +// if (device == null) { +// log.info("不存在的设备IMEI: {}", deviceImei); +// } else { +// +// try { +// JsonNode root = objectMapper.readTree(payload); +// +// DeviceLog record = new DeviceLog(); +// // 手动设置租户ID +// record.setTenantId(device.getTenantId()); // 从设备信息中获取租户ID +// // 设备ID +// record.setDeviceId(device.getId()); +// // 设备名称 +// record.setDeviceName(device.getDeviceName()); +// +// // 2. 处理instruct消息 +// if (root.has("instruct")) { +// JsonNode instructNode = root.get("instruct"); +// if (instructNode.isArray()) { +// boolean b = receivedTopicName.startsWith("B/"); +// record = parseInstruct(device, instructNode, b); +// // 根据不同主题进行不同处理 +// if (receivedTopicName.startsWith("A/")) { +// // 处理A主题的消息(设备上传) +// record.setDataSource("设备上报"); +// } else if (receivedTopicName.startsWith("B/")) { +// // 处理B主题的消息 (手动上传) +// record.setDataSource("客户端操作"); +// } +// } +// // 确保在插入前设置tenantId和deviceId +// record.setTenantId(device.getTenantId()); +// record.setDeviceId(device.getId()); +// deviceLogMapper.insert(record); +// } +// +// // 2. 处理 state 消息 +// if (root.has("state")) { +// JsonNode instructNode = root.get("state"); +// if (instructNode.isArray()) { +// boolean b = receivedTopicName.startsWith("B/"); +// record = parseState(device, instructNode, b); +// // 根据不同主题进行不同处理 +// if (receivedTopicName.startsWith("A/")) { +// // 处理A主题的消息(设备上传) +// record.setDataSource("设备上报"); +// } else if (receivedTopicName.startsWith("B/")) { +// // 处理B主题的消息 (手动上传) +// record.setDataSource("客户端操作"); +// } +// } +// // 确保在插入前设置tenantId和deviceId +// record.setTenantId(device.getTenantId()); +// record.setDeviceId(device.getId()); +// deviceLogMapper.insert(record); +// } +// +// if (root.has("imei")) { +// // 设备行为 +// record.setDeviceAction(InstructType6170.fromCode(0).getDescription()); +// record.setDataSource("设备上报"); +// record.setContent("设备启动"); +// // 确保在插入前设置tenantId和deviceId +// record.setTenantId(device.getTenantId()); +// record.setDeviceId(device.getId()); +// deviceLogMapper.insert(record); +// } +// +// +// // 3. 处理state消息 +// // else if (root.has("state")) { +// // JsonNode stateNode = root.get("state"); +// // if (stateNode.isArray()) { +// // StateRecord record = parseState(device, stateNode); +// // stateRepo.save(record); +// // } +// // } +// } catch (Exception e) { +// log.error("消息解析失败: {}", payload, e); +// } +// +// } +// +// } +// } +// +// +// /** +// * 从主题中提取设备ID(IMEI) +// * +// * @param topic +// * @return +// */ +// private String extractDeviceId(String topic) { +// // 处理 A/# 或 B/# 格式的主题,例如 B/861556078765285 或 A/861556078765285 +// String[] segments = topic.split("/"); +// if (segments.length >= 2) { +// // 返回第二个段,即 / 后面的部分 +// return segments[1]; +// } +// // 如果格式不符合预期,返回原主题 +// return topic; +// } +// +// +// /** +// * 解析instruct消息 +// * +// * @param device +// * @param array +// * @param b +// * @return +// */ +// private DeviceLog parseInstruct(Device device, JsonNode array, boolean b) { +// DeviceLog record = new DeviceLog(); +// record.setDeviceName(device.getDeviceName()); +// // 设备行为 +// record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription()); +// +// switch (array.get(0).asInt()) { +// case 1: // 灯光模式 +// LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt()); +// record.setContent(lightModeEnum6170.getDescription()); +// break; +// +// case 2: // 单位/姓名/职位 +// byte[] unitBytes = new byte[480]; +// for (int i = 1; i <= 480; i++) { +// unitBytes[i - 1] = (byte) array.get(i).asInt(); +// } +// // record.setUnitData(unitBytes); +// break; +// +// case 3: // 开机图片 +// // record.setImagePage(array.get(1).asInt()); +// byte[] imageBytes = new byte[512]; +// for (int i = 2; i <= 513; i++) { +// imageBytes[i - 2] = (byte) array.get(i).asInt(); +// } +// // record.setImageData(imageBytes); +// break; +// +// case 4: // 激光灯 +// int anInt = array.get(1).asInt(); +// if (anInt == 0) { +// record.setContent("关闭激光灯"); +// } else if (anInt == 1) { +// record.setContent("开启激光灯"); +// } else { +// record.setContent("未知操作"); +// } +// break; +// +// case 5: // 亮度调节 +// record.setContent(+array.get(1).asInt() + "%"); +// break; +// +// case 11: // 定位数据 +// if (b) { +// break; +// } +// int i1 = array.get(1).asInt(); +// int i2 = array.get(2).asInt(); +// int i3 = array.get(3).asInt(); +// int i4 = array.get(4).asInt(); +// +// // 优雅的转换方式 Longitude and latitude +// double latitude = i1 + i2 / 10.0; +// double Longitude = i3 + i4 / 10.0; +// // 84 ==》 高德 +// double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude); +// String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0])); +// record.setContent(address); +// break; +// } +// return record; +// } +// +// +// /** +// * 解析 state 消息 +// * +// * @param device +// * @param array +// * @return +// */ +// private DeviceLog parseState(Device device, JsonNode array, boolean b) { +// DeviceLog record = new DeviceLog(); +// record.setDeviceName(device.getDeviceName()); +// // 设备行为 +// record.setDeviceAction(InstructType6170.fromCode(array.get(0).asInt()).getDescription()); +// +// switch (array.get(0).asInt()) { +// case 1: // 灯光模式 +// LightModeEnum6170 lightModeEnum6170 = LightModeEnum6170.fromCode(array.get(1).asInt()); +// record.setContent(lightModeEnum6170.getDescription()); +// break; +// +// case 2: // 单位/姓名/职位 +// byte[] unitBytes = new byte[480]; +// for (int i = 1; i <= 480; i++) { +// unitBytes[i - 1] = (byte) array.get(i).asInt(); +// } +// // record.setUnitData(unitBytes); +// break; +// +// case 3: // 开机图片 +// // record.setImagePage(array.get(1).asInt()); +// byte[] imageBytes = new byte[512]; +// for (int i = 2; i <= 513; i++) { +// imageBytes[i - 2] = (byte) array.get(i).asInt(); +// } +// // record.setImageData(imageBytes); +// break; +// +// case 4: // 激光灯 +// int anInt = array.get(1).asInt(); +// if (anInt == 0) { +// record.setContent("关闭激光灯"); +// } else if (anInt == 1) { +// record.setContent("开启激光灯"); +// } else { +// record.setContent("未知操作"); +// } +// break; +// +// case 5: // 亮度调节 +// record.setContent(+array.get(1).asInt() + "%"); +// break; +// +// case 11: // 定位数据 +// if (b) { +// break; +// } +// int i1 = array.get(1).asInt(); +// int i2 = array.get(2).asInt(); +// int i3 = array.get(3).asInt(); +// int i4 = array.get(4).asInt(); +// +// // 优雅的转换方式 Longitude and latitude +// double latitude = i1 + i2 / 10.0; +// double Longitude = i3 + i4 / 10.0; +// // 84 ==》 高德 +// double[] doubles = LngLonUtil.gps84_To_Gcj02(latitude, Longitude); +// String address = GetAddressFromLatUtil.getAdd(String.valueOf(doubles[1]), String.valueOf(doubles[0])); +// record.setContent(address); +// break; +// } +// return record; +// } +// +//} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/listener/UserActionListener.java b/fys-admin/src/main/java/com/fuyuanshen/web/listener/UserActionListener.java index 9105a5d..49762cb 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/listener/UserActionListener.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/listener/UserActionListener.java @@ -1,163 +1,163 @@ -package com.fuyuanshen.web.listener; - -import cn.dev33.satoken.listener.SaTokenListener; -import cn.dev33.satoken.stp.StpUtil; -import cn.dev33.satoken.stp.parameter.SaLoginParameter; -import cn.hutool.core.convert.Convert; -import cn.hutool.http.useragent.UserAgent; -import cn.hutool.http.useragent.UserAgentUtil; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import com.fuyuanshen.common.core.constant.CacheConstants; -import com.fuyuanshen.common.core.constant.Constants; -import com.fuyuanshen.common.core.domain.dto.UserOnlineDTO; -import com.fuyuanshen.common.core.utils.MessageUtils; -import com.fuyuanshen.common.core.utils.ServletUtils; -import com.fuyuanshen.common.core.utils.SpringUtils; -import com.fuyuanshen.common.core.utils.ip.AddressUtils; -import com.fuyuanshen.common.log.event.LogininforEvent; -import com.fuyuanshen.common.redis.utils.RedisUtils; -import com.fuyuanshen.common.satoken.utils.LoginHelper; -import com.fuyuanshen.common.tenant.helper.TenantHelper; -import com.fuyuanshen.web.service.SysLoginService; -import org.springframework.stereotype.Component; - -import java.time.Duration; - -/** - * 用户行为 侦听器的实现 - * - * @author Lion Li - */ -@RequiredArgsConstructor -@Component -@Slf4j -public class UserActionListener implements SaTokenListener { - - private final SysLoginService loginService; - - /** - * 每次登录时触发 - */ - @Override - public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) { - UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); - String ip = ServletUtils.getClientIP(); - UserOnlineDTO dto = new UserOnlineDTO(); - dto.setIpaddr(ip); - dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); - dto.setBrowser(userAgent.getBrowser().getName()); - dto.setOs(userAgent.getOs().getName()); - dto.setLoginTime(System.currentTimeMillis()); - dto.setTokenId(tokenValue); - String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY); - String tenantId = (String) loginParameter.getExtra(LoginHelper.TENANT_KEY); - dto.setUserName(username); - dto.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY)); - dto.setDeviceType(loginParameter.getDeviceType()); - dto.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY)); - TenantHelper.dynamic(tenantId, () -> { - if(loginParameter.getTimeout() == -1) { - RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); - } else { - RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(loginParameter.getTimeout())); - } - }); - // 记录登录日志 - LogininforEvent logininforEvent = new LogininforEvent(); - logininforEvent.setTenantId(tenantId); - logininforEvent.setUsername(username); - logininforEvent.setStatus(Constants.LOGIN_SUCCESS); - logininforEvent.setMessage(MessageUtils.message("user.login.success")); - logininforEvent.setRequest(ServletUtils.getRequest()); - SpringUtils.context().publishEvent(logininforEvent); - // 更新登录信息 - loginService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip); - log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); - } - - /** - * 每次注销时触发 - */ - @Override - public void doLogout(String loginType, Object loginId, String tokenValue) { - String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); - TenantHelper.dynamic(tenantId, () -> { - RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); - }); - log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); - } - - /** - * 每次被踢下线时触发 - */ - @Override - public void doKickout(String loginType, Object loginId, String tokenValue) { - String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); - TenantHelper.dynamic(tenantId, () -> { - RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); - }); - log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); - } - - /** - * 每次被顶下线时触发 - */ - @Override - public void doReplaced(String loginType, Object loginId, String tokenValue) { - String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); - TenantHelper.dynamic(tenantId, () -> { - RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); - }); - log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); - } - - /** - * 每次被封禁时触发 - */ - @Override - public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { - } - - /** - * 每次被解封时触发 - */ - @Override - public void doUntieDisable(String loginType, Object loginId, String service) { - } - - /** - * 每次打开二级认证时触发 - */ - @Override - public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { - } - - /** - * 每次创建Session时触发 - */ - @Override - public void doCloseSafe(String loginType, String tokenValue, String service) { - } - - /** - * 每次创建Session时触发 - */ - @Override - public void doCreateSession(String id) { - } - - /** - * 每次注销Session时触发 - */ - @Override - public void doLogoutSession(String id) { - } - - /** - * 每次Token续期时触发 - */ - @Override - public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { - } -} +//package com.fuyuanshen.web.listener; +// +//import cn.dev33.satoken.listener.SaTokenListener; +//import cn.dev33.satoken.stp.StpUtil; +//import cn.dev33.satoken.stp.parameter.SaLoginParameter; +//import cn.hutool.core.convert.Convert; +//import cn.hutool.http.useragent.UserAgent; +//import cn.hutool.http.useragent.UserAgentUtil; +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import com.fuyuanshen.common.core.constant.CacheConstants; +//import com.fuyuanshen.common.core.constant.Constants; +//import com.fuyuanshen.common.core.domain.dto.UserOnlineDTO; +//import com.fuyuanshen.common.core.utils.MessageUtils; +//import com.fuyuanshen.common.core.utils.ServletUtils; +//import com.fuyuanshen.common.core.utils.SpringUtils; +//import com.fuyuanshen.common.core.utils.ip.AddressUtils; +//import com.fuyuanshen.common.log.event.LogininforEvent; +//import com.fuyuanshen.common.redis.utils.RedisUtils; +//import com.fuyuanshen.common.satoken.utils.LoginHelper; +//import com.fuyuanshen.common.tenant.helper.TenantHelper; +//import com.fuyuanshen.web.service.SysLoginService; +//import org.springframework.stereotype.Component; +// +//import java.time.Duration; +// +///** +// * 用户行为 侦听器的实现 +// * +// * @author Lion Li +// */ +//@RequiredArgsConstructor +//@Component +//@Slf4j +//public class UserActionListener implements SaTokenListener { +// +// private final SysLoginService loginService; +// +// /** +// * 每次登录时触发 +// */ +// @Override +// public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) { +// UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); +// String ip = ServletUtils.getClientIP(); +// UserOnlineDTO dto = new UserOnlineDTO(); +// dto.setIpaddr(ip); +// dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); +// dto.setBrowser(userAgent.getBrowser().getName()); +// dto.setOs(userAgent.getOs().getName()); +// dto.setLoginTime(System.currentTimeMillis()); +// dto.setTokenId(tokenValue); +// String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY); +// String tenantId = (String) loginParameter.getExtra(LoginHelper.TENANT_KEY); +// dto.setUserName(username); +// dto.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY)); +// dto.setDeviceType(loginParameter.getDeviceType()); +// dto.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY)); +// TenantHelper.dynamic(tenantId, () -> { +// if(loginParameter.getTimeout() == -1) { +// RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); +// } else { +// RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(loginParameter.getTimeout())); +// } +// }); +// // 记录登录日志 +// LogininforEvent logininforEvent = new LogininforEvent(); +// logininforEvent.setTenantId(tenantId); +// logininforEvent.setUsername(username); +// logininforEvent.setStatus(Constants.LOGIN_SUCCESS); +// logininforEvent.setMessage(MessageUtils.message("user.login.success")); +// logininforEvent.setRequest(ServletUtils.getRequest()); +// SpringUtils.context().publishEvent(logininforEvent); +// // 更新登录信息 +// loginService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip); +// log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); +// } +// +// /** +// * 每次注销时触发 +// */ +// @Override +// public void doLogout(String loginType, Object loginId, String tokenValue) { +// String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); +// TenantHelper.dynamic(tenantId, () -> { +// RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); +// }); +// log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); +// } +// +// /** +// * 每次被踢下线时触发 +// */ +// @Override +// public void doKickout(String loginType, Object loginId, String tokenValue) { +// String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); +// TenantHelper.dynamic(tenantId, () -> { +// RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); +// }); +// log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); +// } +// +// /** +// * 每次被顶下线时触发 +// */ +// @Override +// public void doReplaced(String loginType, Object loginId, String tokenValue) { +// String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); +// TenantHelper.dynamic(tenantId, () -> { +// RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); +// }); +// log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); +// } +// +// /** +// * 每次被封禁时触发 +// */ +// @Override +// public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { +// } +// +// /** +// * 每次被解封时触发 +// */ +// @Override +// public void doUntieDisable(String loginType, Object loginId, String service) { +// } +// +// /** +// * 每次打开二级认证时触发 +// */ +// @Override +// public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { +// } +// +// /** +// * 每次创建Session时触发 +// */ +// @Override +// public void doCloseSafe(String loginType, String tokenValue, String service) { +// } +// +// /** +// * 每次创建Session时触发 +// */ +// @Override +// public void doCreateSession(String id) { +// } +// +// /** +// * 每次注销Session时触发 +// */ +// @Override +// public void doLogoutSession(String id) { +// } +// +// /** +// * 每次Token续期时触发 +// */ +// @Override +// public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { +// } +//} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/DeviceShareService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/DeviceShareService.java new file mode 100644 index 0000000..d73eaa7 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/DeviceShareService.java @@ -0,0 +1,235 @@ +package com.fuyuanshen.web.service; + +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuyuanshen.app.domain.AppDeviceShare; +import com.fuyuanshen.app.domain.AppPersonnelInfo; +import com.fuyuanshen.app.domain.bo.AppDeviceShareBo; +import com.fuyuanshen.app.domain.vo.AppDeviceShareDetailVo; +import com.fuyuanshen.app.domain.vo.AppDeviceShareVo; +import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo; +import com.fuyuanshen.app.mapper.AppDeviceShareMapper; +import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +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.mapper.DeviceMapper; +import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; + + +@RequiredArgsConstructor +@Slf4j +@Service +public class DeviceShareService { + + private final AppDeviceShareMapper appDeviceShareMapper; + + private final DeviceMapper deviceMapper; + + private final DeviceTypeMapper deviceTypeMapper; + + private final AppPersonnelInfoMapper appPersonnelInfoMapper; + + public TableDataInfo queryPageList(AppDeviceShareBo bo, PageQuery pageQuery) { + Long userId = AppLoginHelper.getUserId(); + bo.setCreateBy(userId); + Page page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()); + Page result = appDeviceShareMapper.selectAppDeviceShareList(bo, page); + List records = result.getRecords(); + records.forEach(DeviceShareService::buildDeviceStatus); + return TableDataInfo.build(result); + } + + private static void buildDeviceStatus(AppDeviceShareVo item) { + //设备在线状态 + String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); + if(StringUtils.isNotBlank(onlineStatus)){ + + item.setOnlineStatus(1); + }else{ + item.setOnlineStatus(0); + } + String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); + // 获取电量 + if(StringUtils.isNotBlank(deviceStatus)){ + JSONObject jsonObject = JSONObject.parseObject(deviceStatus); + item.setBattery(jsonObject.getString("batteryPercentage")); + }else{ + item.setBattery("0"); + } + + 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)){ + item.setAlarmStatus(alarmStatus); + } + } + + public AppDeviceShareDetailVo getInfo(Long id) { + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(AppDeviceShare::getId, id); + List appDeviceShareVos = appDeviceShareMapper.selectVoList(queryWrapper); + if(appDeviceShareVos==null || appDeviceShareVos.isEmpty()){ + return null; + } + + AppDeviceShareVo shareVo = appDeviceShareVos.get(0); + AppDeviceShareDetailVo shareDetailVo = new AppDeviceShareDetailVo(); + shareDetailVo.setId(shareVo.getId()); + shareDetailVo.setDeviceId(shareVo.getDeviceId()); + shareDetailVo.setPhonenumber(shareVo.getPhonenumber()); + shareDetailVo.setPermission(shareVo.getPermission()); + + Device device = deviceMapper.selectById(shareVo.getDeviceId()); + shareDetailVo.setDeviceName(device.getDeviceName()); + shareDetailVo.setDeviceImei(device.getDeviceImei()); + shareDetailVo.setDeviceMac(device.getDeviceMac()); + + DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType()); + if(deviceType!=null){ + shareDetailVo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode())); + } + shareDetailVo.setDevicePic(device.getDevicePic()); + shareDetailVo.setTypeName(deviceType.getTypeName()); + shareDetailVo.setBluetoothName(device.getBluetoothName()); + shareDetailVo.setDeviceStatus(device.getDeviceStatus()); + shareDetailVo.setSendMsg(device.getSendMsg()); + + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(AppPersonnelInfo::getDeviceId, device.getId()); + List appPersonnelInfoVos = appPersonnelInfoMapper.selectVoList(qw); + if(appPersonnelInfoVos!=null && !appPersonnelInfoVos.isEmpty()){ + shareDetailVo.setPersonnelInfo(appPersonnelInfoVos.get(0)); + } + //设备在线状态 + String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei()+ DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); + if(StringUtils.isNotBlank(onlineStatus)){ + shareDetailVo.setOnlineStatus(1); + }else{ + shareDetailVo.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); + shareDetailVo.setMainLightMode(jsonObject.getString("mainLightMode")); + shareDetailVo.setLaserLightMode(jsonObject.getString("laserLightMode")); + shareDetailVo.setBatteryPercentage(jsonObject.getString("batteryPercentage")); + shareDetailVo.setChargeState(jsonObject.getString("chargeState")); + shareDetailVo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime")); + }else{ + shareDetailVo.setBatteryPercentage("0"); + } + + // 获取经度纬度 + 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); + shareDetailVo.setLongitude(jsonObject.get("longitude").toString()); + shareDetailVo.setLatitude(jsonObject.get("latitude").toString()); + shareDetailVo.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)){ + shareDetailVo.setAlarmStatus(alarmStatus); + } + + String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ device.getDeviceImei()+ DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); + if(StringUtils.isNotBlank(lightBrightness)){ + shareDetailVo.setLightBrightness(lightBrightness); + } + + return shareDetailVo; + } + /** + * 校验短信验证码 + */ + private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.DEVICE_SHARE_CODES_KEY + phonenumber); + if (StringUtils.isBlank(code)) { + throw new ServiceException("验证码失效"); + } + return code.equals(smsCode); + } + public int deviceShare(AppDeviceShareBo bo) { + boolean flag = validateSmsCode(AppLoginHelper.getTenantId(), bo.getPhonenumber(), bo.getSmsCode()); + if(!flag){ + throw new ServiceException("验证码错误"); + } + + Device device = deviceMapper.selectById(bo.getDeviceId()); + if(device==null){ + throw new ServiceException("设备不存在"); + } + Long userId = AppLoginHelper.getUserId(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + lqw.eq(AppDeviceShare::getDeviceId, bo.getDeviceId()); + lqw.eq(AppDeviceShare::getPhonenumber, bo.getPhonenumber()); + Long count = appDeviceShareMapper.selectCount(lqw); + if(count>0){ + + UpdateWrapper uw = new UpdateWrapper<>(); + uw.eq("device_id", bo.getDeviceId()); + uw.eq("phonenumber", bo.getPhonenumber()); + uw.set("permission", bo.getPermission()); + uw.set("update_by", userId); + uw.set("update_time", new Date()); + + return appDeviceShareMapper.update(uw); + }else { + AppDeviceShare appDeviceShare = new AppDeviceShare(); + appDeviceShare.setDeviceId(bo.getDeviceId()); + appDeviceShare.setPhonenumber(bo.getPhonenumber()); + appDeviceShare.setPermission(bo.getPermission()); + appDeviceShare.setCreateBy(userId); + return appDeviceShareMapper.insert(appDeviceShare); + } + } + + public int remove(Long[] ids) { + return appDeviceShareMapper.deleteByIds(Arrays.asList(ids)); + } + + public TableDataInfo otherDeviceShareList(AppDeviceShareBo bo, PageQuery pageQuery) { + String username = AppLoginHelper.getUsername(); + bo.setPhonenumber(username); + Page page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()); + IPage result = appDeviceShareMapper.otherDeviceShareList(bo, page); + List records = result.getRecords(); + + records.forEach(DeviceShareService::buildDeviceStatus); + return TableDataInfo.build(result); + } + + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/device/AppDeviceBJQBizService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java similarity index 76% rename from fys-admin/src/main/java/com/fuyuanshen/app/service/device/AppDeviceBJQBizService.java rename to fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java index 8dd1a96..60c80d7 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/device/AppDeviceBJQBizService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java @@ -1,4 +1,4 @@ -package com.fuyuanshen.app.service.device; +package com.fuyuanshen.web.service.device; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; @@ -19,6 +19,8 @@ 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; @@ -38,19 +40,19 @@ import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_K 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.DEVICE_BOOT_LOGO_KEY_PREFIX; -import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; @Slf4j @Service @RequiredArgsConstructor -public class AppDeviceBJQBizService { +public class DeviceBJQBizService { private final DeviceMapper deviceMapper; private final AppPersonnelInfoMapper appPersonnelInfoMapper; private final DeviceTypeMapper deviceTypeMapper; private final MqttGateway mqttGateway; + private final DeviceLogMapper deviceLogMapper; public int sendMessage(AppDeviceSendMsgBo bo) { List deviceIds = bo.getDeviceIds(); @@ -62,22 +64,22 @@ public class AppDeviceBJQBizService { 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(); -// String backgroundImagePath = "D:\\background.png"; // 替换为实际背景图片路径 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(30 * 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"); 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(6); @@ -97,19 +99,50 @@ public class AppDeviceBJQBizService { .eq("binding_user_id", AppLoginHelper.getUserId()) .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("发送指令失败"); } } + + return 1; } + /** + * 记录设备操作日志 + * @param deviceId 设备ID + * @param content 日志内容 + * @param 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(); + 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); + } + } + + public AppDeviceDetailVo getInfo(Long id) { Device device = deviceMapper.selectById(id); if (device == null) { throw new RuntimeException("请先将设备入库!!!"); } + AppDeviceDetailVo vo = new AppDeviceDetailVo(); vo.setDeviceId(device.getId()); vo.setDeviceName(device.getDeviceName()); @@ -134,13 +167,13 @@ public class AppDeviceBJQBizService { vo.setPersonnelInfo(personnelInfoVo); } //设备在线状态 - String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX + device.getDeviceImei()); + String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei()+ DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); if(StringUtils.isNotBlank(onlineStatus)){ vo.setOnlineStatus(1); }else{ vo.setOnlineStatus(0); } - String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX + device.getDeviceImei()); + 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); @@ -154,7 +187,7 @@ public class AppDeviceBJQBizService { } // 获取经度纬度 - String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX + device.getDeviceImei(); + 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); @@ -163,16 +196,30 @@ public class AppDeviceBJQBizService { 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; } + 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); @@ -196,6 +243,7 @@ public class AppDeviceBJQBizService { mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), 1, JSON.toJSONString(map)); log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), bo); + recordDeviceLog(deviceId, deviceObj.getDeviceName(), "人员信息登记", JSON.toJSONString(bo), AppLoginHelper.getUserId()); if (ObjectUtils.length(appPersonnelInfoVos) == 0) { AppPersonnelInfo appPersonnelInfo = MapstructUtils.convert(bo, AppPersonnelInfo.class); return appPersonnelInfoMapper.insertOrUpdate(appPersonnelInfo); @@ -208,8 +256,6 @@ public class AppDeviceBJQBizService { .set("code", bo.getCode()); return appPersonnelInfoMapper.update(null, uw) > 0; } - - } public void uploadDeviceLogo(AppDeviceLogoUploadDto bo) { @@ -218,6 +264,9 @@ public class AppDeviceBJQBizService { if (device == null) { throw new ServiceException("设备不存在"); } + if(getDeviceStatus(device.getDeviceImei())){ + throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + } MultipartFile file = bo.getFile(); byte[] largeData = ImageToCArrayConverter.convertImageToCArray(file.getInputStream(), 160, 80, 25600); @@ -226,7 +275,7 @@ public class AppDeviceBJQBizService { 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(30 * 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); @@ -247,8 +296,11 @@ public class AppDeviceBJQBizService { 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("发送指令失败"); } } @@ -256,6 +308,7 @@ public class AppDeviceBJQBizService { * 灯光模式 * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) */ + public void lightModeSettings(DeviceInstructDto params) { try { Long deviceId = params.getDeviceId(); @@ -263,6 +316,9 @@ public class AppDeviceBJQBizService { 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); @@ -274,8 +330,11 @@ public class AppDeviceBJQBizService { 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("发送指令失败"); } } @@ -287,6 +346,9 @@ public class AppDeviceBJQBizService { 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); @@ -306,8 +368,10 @@ public class AppDeviceBJQBizService { 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("发送指令失败"); } } @@ -319,6 +383,9 @@ public class AppDeviceBJQBizService { 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); @@ -330,8 +397,15 @@ public class AppDeviceBJQBizService { 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("发送指令失败"); } } @@ -351,13 +425,17 @@ public class AppDeviceBJQBizService { 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())); @@ -375,14 +453,22 @@ public class AppDeviceBJQBizService { .eq("binding_user_id", AppLoginHelper.getUserId()) .set("send_msg", bo.getSendMsg()); deviceMapper.update(updateWrapper); + recordDeviceLog(device.getId(), device.getDeviceName(), "发送告警信息", bo.getSendMsg(), AppLoginHelper.getUserId()); } catch (Exception e) { - log.info("设备发送信息失败:{}" ,deviceId); + log.info("设备发送告警信息信息失败:{}" ,deviceId); + throw new ServiceException("设备发送告警信息信息失败"); } } } catch (Exception e){ e.printStackTrace(); + throw new ServiceException("发送告警信息指令失败"); } return 1; } + + private boolean getDeviceStatus(String deviceImei) { + String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ; + return StringUtils.isBlank(deviceOnlineStatusRedisKey); + } } 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 new file mode 100644 index 0000000..3c0d9be --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBizService.java @@ -0,0 +1,293 @@ +package com.fuyuanshen.web.service.device; + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuyuanshen.app.domain.AppDeviceBindRecord; +import com.fuyuanshen.app.domain.AppDeviceShare; +import com.fuyuanshen.app.domain.dto.APPReNameDTO; +import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto; +import com.fuyuanshen.app.domain.dto.DeviceInstructDto; +import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo; +import com.fuyuanshen.app.domain.vo.AppUserVo; +import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper; +import com.fuyuanshen.app.mapper.AppDeviceShareMapper; +import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; +import com.fuyuanshen.app.mapper.AppUserMapper; +import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper; +import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.ObjectUtils; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +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.dto.AppDeviceBo; +import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria; +import com.fuyuanshen.equipment.domain.vo.AppDeviceVo; +import com.fuyuanshen.equipment.enums.BindingStatusEnum; +import com.fuyuanshen.equipment.enums.CommunicationModeEnum; +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.web.service.device.status.base.DeviceStatusRule; +import com.fuyuanshen.web.service.device.status.base.RealTimeStatusEngine; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceBizService { + + private final APPDeviceMapper appDeviceMapper; + private final DeviceMapper deviceMapper; + private final AppDeviceBindRecordMapper appDeviceBindRecordMapper; + private final RealTimeStatusEngine realTimeStatusEngine; + private final DeviceLogMapper deviceLogMapper; + private final AppDeviceShareMapper appDeviceShareMapper; + private final AppUserMapper appUserMapper;; + + + + public List getTypeList() { + Long userId = AppLoginHelper.getUserId(); + return appDeviceMapper.getTypeList(userId); + } + + public void reName(APPReNameDTO reNameDTO) { + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", reNameDTO.getId()) + .eq("binding_user_id", AppLoginHelper.getUserId()) + .set("device_name", reNameDTO.getDeviceName()); + deviceMapper.update(updateWrapper); + } + + + public TableDataInfo queryAppDeviceList(DeviceQueryCriteria bo, PageQuery pageQuery) { + if (bo.getBindingUserId() == null) { + Long userId = AppLoginHelper.getUserId(); + bo.setBindingUserId(userId); + } + Page result = deviceMapper.queryAppBindDeviceList(pageQuery.build(), bo); + List records = result.getRecords(); + if(records != null && !records.isEmpty()){ + records.forEach(item -> { + 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(StringUtils.isNotBlank(onlineStatus)){ + + item.setOnlineStatus(1); + }else{ + item.setOnlineStatus(0); + } + String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); + // 获取电量 + if(StringUtils.isNotBlank(deviceStatus)){ + JSONObject jsonObject = JSONObject.parseObject(deviceStatus); + item.setBattery(jsonObject.getString("batteryPercentage")); + }else{ + item.setBattery("0"); + } + + 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)){ + item.setAlarmStatus(alarmStatus); + } + } + }); + } + return TableDataInfo.build(result); + } + + public int bindDevice(AppDeviceBo bo) { + Integer mode = bo.getCommunicationMode(); + Long userId = AppLoginHelper.getUserId(); + if (mode == CommunicationModeEnum.FOUR_G.getValue()) { + + String deviceImei = bo.getDeviceImei(); + QueryWrapper qw = new QueryWrapper() + .eq("device_imei", deviceImei); + List devices = deviceMapper.selectList(qw); + if (devices.isEmpty()) { + throw new RuntimeException("请先将设备入库!!!"); + } + Device device = devices.get(0); + if (device.getBindingStatus() != null && device.getBindingStatus() == BindingStatusEnum.BOUND.getCode()) { + throw new RuntimeException("设备已绑定"); + } + + QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); + bindRecordQueryWrapper.eq("device_id", device.getId()); + AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); + if (appDeviceBindRecord != null) { + UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); + deviceUpdateWrapper.eq("device_id", device.getId()) + .set("binding_status", BindingStatusEnum.BOUND.getCode()) + .set("binding_user_id", userId) + .set("update_time", new Date()) + .set("binding_time", new Date()); + return appDeviceBindRecordMapper.update(null, deviceUpdateWrapper); + } else { + AppDeviceBindRecord bindRecord = new AppDeviceBindRecord(); + bindRecord.setDeviceId(device.getId()); + bindRecord.setBindingUserId(userId); + bindRecord.setBindingTime(new Date()); + bindRecord.setCreateBy(userId); + appDeviceBindRecordMapper.insert(bindRecord); + } + + UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); + deviceUpdateWrapper.eq("id", device.getId()) + .set("binding_status", BindingStatusEnum.BOUND.getCode()) + .set("binding_user_id", userId) + .set("binding_time", new Date()); + return deviceMapper.update(null, deviceUpdateWrapper); + } else if (mode == CommunicationModeEnum.BLUETOOTH.getValue()) { + String deviceMac = bo.getDeviceMac(); + QueryWrapper qw = new QueryWrapper() + .eq("device_mac", deviceMac); + List devices = deviceMapper.selectList(qw); + if (devices.isEmpty()) { + throw new RuntimeException("请先将设备入库!!!"); + } + Device device = devices.get(0); + + QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); + bindRecordQueryWrapper.eq("device_id", device.getId()); + bindRecordQueryWrapper.eq("binding_user_id", userId); + AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); + if (appDeviceBindRecord != null) { + UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); + deviceUpdateWrapper.eq("device_id", device.getId()) + .eq("binding_user_id", userId) + .set("binding_user_id", userId) + .set("binding_time", new Date()); + return appDeviceBindRecordMapper.update(null, deviceUpdateWrapper); + } else { + AppDeviceBindRecord bindRecord = new AppDeviceBindRecord(); + bindRecord.setDeviceId(device.getId()); + bindRecord.setBindingUserId(userId); + bindRecord.setBindingTime(new Date()); + bindRecord.setCreateBy(userId); + appDeviceBindRecordMapper.insert(bindRecord); + } + + UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); + deviceUpdateWrapper.eq("id", device.getId()) + .set("binding_status", BindingStatusEnum.BOUND.getCode()) + .set("binding_user_id", userId) + .set("binding_time", new Date()); + return deviceMapper.update(null, deviceUpdateWrapper); + } else { + throw new RuntimeException("通讯方式错误"); + } + + } + + + public int unBindDevice(Long id) { + return unBindDevice(id, null, 1); + } + + public int unBindDevice(Long id, Long userId, int type) { + Device device = deviceMapper.selectById(id); + if (device == null) { + throw new RuntimeException("请先将设备入库!!!"); + } + UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); + deviceUpdateWrapper.eq("id", device.getId()) + .set("binding_user_id", null) + .set("binding_status", BindingStatusEnum.UNBOUND.getCode()) + .set("binding_time", null); + deviceMapper.update(null, deviceUpdateWrapper); + + if (userId == null) { + userId = AppLoginHelper.getUserId(); + } + QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); + bindRecordQueryWrapper.eq("device_id", device.getId()); + // 设备端解绑 0:设备端解绑 1:web端解绑 + if (type == 1) { + bindRecordQueryWrapper.eq("binding_user_id", userId); + } + + // AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); + // if (appDeviceBindRecord != null) { + // return appDeviceBindRecordMapper.deleteById(appDeviceBindRecord.getId()); + // } + + List appDeviceBindRecordList = appDeviceBindRecordMapper.selectList(bindRecordQueryWrapper); + if (CollectionUtil.isNotEmpty(appDeviceBindRecordList)) { + appDeviceBindRecordList.forEach(appDeviceBindRecord -> + appDeviceBindRecordMapper.deleteById(appDeviceBindRecord.getId())); + } + + AppUserVo appUserVo = appUserMapper.selectVoById(userId); + QueryWrapper appDeviceShareQueryWrapper = new QueryWrapper<>(); + appDeviceShareQueryWrapper.eq("device_id", device.getId()); + appDeviceShareQueryWrapper.eq("phonenumber", appUserVo.getPhonenumber()); + List appDeviceShareList = appDeviceShareMapper.selectList(appDeviceShareQueryWrapper); + if (CollectionUtil.isNotEmpty(appDeviceShareList)) { + appDeviceShareList.forEach(appDeviceShare -> + appDeviceShareMapper.deleteById(appDeviceShare.getId())); + } + return 1; + } + + public String mapReverseGeocoding(DeviceInstructDto params) { +// Long deviceId = params.getDeviceId(); +// Device device = deviceMapper.selectById(deviceId); + 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()); + } + + public Map getRealTimeStatus(AppRealTimeStatusDto statusDto) { + try { + String commandType = statusDto.getTypeName()+"_" + statusDto.getFunctionMode(); + DeviceStatusRule rule = realTimeStatusEngine.getDeviceStatusRule(commandType); + if(rule == null){ + throw new ServiceException("未匹配到处理命令"); + } + return rule.getStatus(statusDto); + } catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + public AppDeviceVo getDeviceInfo(String deviceMac) { +// QueryWrapper queryWrapper = new QueryWrapper<>(); +// queryWrapper.eq("device_mac", deviceMac); +// List devices = deviceMapper.selectList(queryWrapper); + return deviceMapper.getDeviceInfo(deviceMac); + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/FunctionAccessBatchStatusRule.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/FunctionAccessBatchStatusRule.java new file mode 100644 index 0000000..116b5c9 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/FunctionAccessBatchStatusRule.java @@ -0,0 +1,75 @@ +package com.fuyuanshen.web.service.device.status; + +import cn.hutool.json.JSONUtil; +import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import com.fuyuanshen.web.service.device.status.base.DeviceStatusRule; +import com.fuyuanshen.web.service.device.status.constants.DeviceTypeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; + + +@Slf4j +@Component +public class FunctionAccessBatchStatusRule implements DeviceStatusRule { + @Override + public String getCommandType() { + return DeviceTypeConstants.TYPE_BJQ6170+"_2"; + } + + @Override + public boolean supports(String deviceType) { + return true; // 适用于所有设备类型 + } + + @Override + public Map getStatus(AppRealTimeStatusDto dto) { + Map status = new HashMap<>(); + String functionAccess = RedisUtils.getCacheObject( + FUNCTION_ACCESS_KEY + dto.getBatchId()); + log.info("FunctionAccessBatchStatusRule:{}",functionAccess); + if(StringUtils.isBlank(functionAccess)){ + status.put("functionAccess", FunctionAccessStatus.OK.getCode()); + return status; + } + List cachedDeviceImeiList = JSONUtil.toList(functionAccess, String.class); + if(cachedDeviceImeiList.isEmpty()){ + status.put("functionAccess", FunctionAccessStatus.OK.getCode()); + return status; + } + for (String key : cachedDeviceImeiList) { + String item = RedisUtils.getCacheObject(FUNCTION_ACCESS_KEY + key); + if("ACTIVE".equals(item)){ + status.put("functionAccess", FunctionAccessStatus.ACTIVE.getCode()); + break; + }else { + status.put("functionAccess", FunctionAccessStatus.OK.getCode()); + } +// if (StringUtils.isBlank(item)) { +// String timeOut = RedisUtils.getCacheObject(FUNCTION_ACCESS_TIMEOUT_KEY + dto.getDeviceImei()); +// if ("TIMEOUT".equals(timeOut)) { +// status.put("functionAccess", FunctionAccessStatus.TIMEOUT.getCode()); +// break; +// } else { +// status.put("functionAccess", FunctionAccessStatus.OK.getCode()); +// } +// } else { +// if (!FunctionAccessStatus.OK.getCode().equals(item)) { +// status.put("functionAccess", FunctionAccessStatus.FAILED.getCode()); +// break; +// } else { +// status.put("functionAccess", FunctionAccessStatus.OK.getCode()); +// } +// } + } + return status; + } +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/FunctionAccessStatusRule.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/FunctionAccessStatusRule.java new file mode 100644 index 0000000..6b6f094 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/FunctionAccessStatusRule.java @@ -0,0 +1,51 @@ +package com.fuyuanshen.web.service.device.status; + +import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import com.fuyuanshen.web.service.device.status.base.DeviceStatusRule; +import com.fuyuanshen.web.service.device.status.constants.DeviceTypeConstants; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_TIMEOUT_KEY; + +// 上传开机图片 +@Slf4j +@Component +public class FunctionAccessStatusRule implements DeviceStatusRule { + @Override + public String getCommandType() { + return DeviceTypeConstants.TYPE_BJQ6170+"_1"; + } + + @Override + public boolean supports(String deviceType) { + return true; // 适用于所有设备类型 + } + + @Override + public Map getStatus(AppRealTimeStatusDto dto) { + Map status = new HashMap<>(); + String functionAccess = RedisUtils.getCacheObject( + FUNCTION_ACCESS_KEY + dto.getDeviceImei()); + log.info("FunctionAccessStatusRule:{}",functionAccess); + if(StringUtils.isBlank(functionAccess)){ + String timeOut = RedisUtils.getCacheObject(FUNCTION_ACCESS_TIMEOUT_KEY + dto.getDeviceImei()); + if("TIMEOUT".equals(timeOut)){ + status.put("functionAccess", FunctionAccessStatus.TIMEOUT.getCode()); + RedisUtils.deleteObject(FUNCTION_ACCESS_TIMEOUT_KEY + dto.getDeviceImei()); + }else{ + status.put("functionAccess", FunctionAccessStatus.OK.getCode()); + } + }else{ + status.put("functionAccess", functionAccess); + } + return status; + } +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/base/DeviceStatusRule.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/base/DeviceStatusRule.java new file mode 100644 index 0000000..57e1fd8 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/base/DeviceStatusRule.java @@ -0,0 +1,19 @@ +package com.fuyuanshen.web.service.device.status.base; + +import com.fuyuanshen.app.domain.dto.AppRealTimeStatusDto; + +import java.util.Map; + +// 规则接口 +public interface DeviceStatusRule { + + /** + * 获取命令类型 + * @return 命令类型 + */ + String getCommandType(); + + boolean supports(String deviceType); + + Map getStatus(AppRealTimeStatusDto statusDto); +} \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/base/RealTimeStatusEngine.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/base/RealTimeStatusEngine.java new file mode 100644 index 0000000..d374eb5 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/base/RealTimeStatusEngine.java @@ -0,0 +1,23 @@ +package com.fuyuanshen.web.service.device.status.base; + +import org.springframework.stereotype.Component; + +import java.util.LinkedHashMap; +import java.util.List; + + +@Component +public class RealTimeStatusEngine { + + + private final LinkedHashMap rulesMap = new LinkedHashMap<>(); + public RealTimeStatusEngine(List rules) { + rules.forEach(rule -> rulesMap.put(rule.getCommandType(), rule) + ); + } + + + public DeviceStatusRule getDeviceStatusRule(String commandType) { + return rulesMap.get(commandType); + } +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/constants/DeviceTypeConstants.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/constants/DeviceTypeConstants.java new file mode 100644 index 0000000..1e0f0cc --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/status/constants/DeviceTypeConstants.java @@ -0,0 +1,6 @@ +package com.fuyuanshen.web.service.device.status.constants; + +public class DeviceTypeConstants { + public static final String TYPE_BJQ6170 = "BJQ6170"; + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/WEBDeviceServiceImpl.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/WEBDeviceServiceImpl.java index 9f8e041..f38a2e8 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/WEBDeviceServiceImpl.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/WEBDeviceServiceImpl.java @@ -1,12 +1,12 @@ package com.fuyuanshen.web.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.fuyuanshen.app.service.AppDeviceBizService; import com.fuyuanshen.equipment.domain.Device; import com.fuyuanshen.equipment.domain.DeviceAssignments; import com.fuyuanshen.equipment.mapper.DeviceAssignmentsMapper; import com.fuyuanshen.equipment.mapper.DeviceMapper; import com.fuyuanshen.web.service.WEBDeviceService; +import com.fuyuanshen.web.service.device.DeviceBizService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -21,7 +21,7 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class WEBDeviceServiceImpl extends ServiceImpl implements WEBDeviceService { - private final AppDeviceBizService appDeviceService; + private final DeviceBizService appDeviceService; private final DeviceAssignmentsMapper deviceAssignmentsMapper; diff --git a/fys-admin/src/main/resources/application-dev.yml b/fys-admin/src/main/resources/application-dev.yml index 4e922bc..e27d051 100644 --- a/fys-admin/src/main/resources/application-dev.yml +++ b/fys-admin/src/main/resources/application-dev.yml @@ -303,6 +303,6 @@ mqtt: password: fys123456 url: tcp://47.107.152.87:1883 subClientId: fys_subClient - subTopic: A/#,B/#,worker/location/# + subTopic: worker/location/# pubTopic: B/# pubClientId: fys_pubClient \ 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 8f210fb..67cca4f 100644 --- a/fys-admin/src/main/resources/application-prod.yml +++ b/fys-admin/src/main/resources/application-prod.yml @@ -4,7 +4,7 @@ spring.servlet.multipart.location: /fys/server/temp --- # 监控中心配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false url: http://localhost:9090/admin instance: service-host-type: IP @@ -16,7 +16,7 @@ spring.boot.admin.client: --- # snail-job 配置 snail-job: - enabled: true + enabled: false # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 group: "fys_group" # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表 @@ -52,9 +52,9 @@ spring: driverClassName: com.mysql.cj.jdbc.Driver # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) - url: jdbc:mysql://localhost:3306/fys_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + 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: Jz_5623_cl1 + password: Jq_123456# # # 从库数据源 # slave: # lazy: true @@ -101,7 +101,7 @@ spring: spring.data: redis: # 地址 - host: localhost + host: 47.120.79.150 # 端口,默认为6379 port: 6379 # 数据库索引 @@ -177,11 +177,14 @@ sms: # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 supplier: alibaba # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 - access-key-id: 您的accessKey + access-key-id: LTAI5tJdDNpZootsPQ5hdELx # 称为accessSecret有些称之为apiSecret - access-key-secret: 您的accessKeySecret - signature: 您的短信签名 - sdk-app-id: 您的sdkAppId + access-key-secret: mU4WtffcCXpHPz5tLwQpaGtLsJXONt + #模板ID 非必须配置,如果使用sendMessage的快速发送需此配置 + template-id: SMS_322180518 + #模板变量 上述模板的变量 + templateName: code + signature: 湖北星汉研创科技 config2: # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 supplier: tencent diff --git a/fys-admin/src/main/resources/application.yml b/fys-admin/src/main/resources/application.yml index b586213..83731fe 100644 --- a/fys-admin/src/main/resources/application.yml +++ b/fys-admin/src/main/resources/application.yml @@ -232,7 +232,7 @@ xss: # 如使用JDK21请直接使用虚拟线程 不要开启此配置 thread-pool: # 是否开启线程池 - enabled: false + enabled: true # 队列最大长度 queueCapacity: 128 # 线程池维护线程所允许的空闲时间 diff --git a/fys-admin/src/main/resources/image/background.png b/fys-admin/src/main/resources/image/background.png index 1670e7f..f7c168d 100644 Binary files a/fys-admin/src/main/resources/image/background.png and b/fys-admin/src/main/resources/image/background.png differ diff --git a/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/constant/GlobalConstants.java b/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/constant/GlobalConstants.java index 47f80b1..7a875ea 100644 --- a/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/constant/GlobalConstants.java +++ b/fys-common/fys-common-core/src/main/java/com/fuyuanshen/common/core/constant/GlobalConstants.java @@ -41,4 +41,9 @@ public interface GlobalConstants { * 三方认证 redis key */ String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; + + + String FUNCTION_ACCESS_KEY = GLOBAL_REDIS_KEY + "device:function_access:"; + + String FUNCTION_ACCESS_TIMEOUT_KEY = GLOBAL_REDIS_KEY + "device:function_access_timeout:"; } diff --git a/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/annotation/FunctionAccessAnnotation.java b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/annotation/FunctionAccessAnnotation.java new file mode 100644 index 0000000..ab211b2 --- /dev/null +++ b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/annotation/FunctionAccessAnnotation.java @@ -0,0 +1,12 @@ +package com.fuyuanshen.common.ratelimiter.annotation;// DeviceRedisKeyAnnotation.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface FunctionAccessAnnotation { + String value() default ""; + long timeOut() default 30; +} diff --git a/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/annotation/FunctionAccessBatcAnnotation.java b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/annotation/FunctionAccessBatcAnnotation.java new file mode 100644 index 0000000..ef0934e --- /dev/null +++ b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/annotation/FunctionAccessBatcAnnotation.java @@ -0,0 +1,13 @@ +package com.fuyuanshen.common.ratelimiter.annotation;// DeviceRedisKeyAnnotation.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface FunctionAccessBatcAnnotation { + String value() default ""; + long timeOut() default 30; + long batchMaxTimeOut() default 40; +} diff --git a/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/aspectj/FunctionAccessAspect.java b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/aspectj/FunctionAccessAspect.java new file mode 100644 index 0000000..41ecd7e --- /dev/null +++ b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/aspectj/FunctionAccessAspect.java @@ -0,0 +1,104 @@ +package com.fuyuanshen.common.ratelimiter.aspectj;// DeviceRedisKeyAspect.java +import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_TIMEOUT_KEY; + +@Slf4j +@Aspect +@Component +public class FunctionAccessAspect { + + // 定义切点,拦截带有DeviceRedisKeyAnnotation注解的方法 + @Around("@annotation(functionAccessAnnotation)") + public Object addDeviceRedisKey(ProceedingJoinPoint joinPoint, FunctionAccessAnnotation functionAccessAnnotation) throws Throwable { + Object result; + String deviceImei = null; + + // 获取方法参数,查找设备ID + Object[] args = joinPoint.getArgs(); + deviceImei = extractDeviceImei(args); + long timeout = functionAccessAnnotation.timeOut(); + + if (StringUtils.isNotBlank(deviceImei)) { + // 生成全局Redis key + String redisKey = generateDeviceRedisKey(deviceImei); + String cacheKey = RedisUtils.getCacheObject(redisKey); + if(StringUtils.isNotBlank(cacheKey) && "ACTIVE".equals(cacheKey)){ + throw new ServiceException("设备已存在访问限制,请稍后再试", 500); + } + // + RedisUtils.setCacheObject(redisKey, "ACTIVE", Duration.ofSeconds(timeout)); + } + + // 执行原方法 + result = joinPoint.proceed(); + + return result; + } + + /** + * 从方法参数中提取设备ID + */ + private String extractDeviceImei(Object[] args) { + if (args == null || args.length == 0) { + return null; + } + + for (Object arg : args) { + if (arg == null) continue; + + // 如果参数本身就是设备ID (Long类型) + if (arg instanceof Long) { + return arg.toString(); + } + + // 如果参数是对象,尝试获取deviceId字段 + try { + // 使用反射获取deviceId字段 + java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields(); + for (java.lang.reflect.Field field : fields) { + if ("deviceImei".equalsIgnoreCase(field.getName()) || + "device_imei".equalsIgnoreCase(field.getName())) { + field.setAccessible(true); + Object value = field.get(arg); + if (value != null) { + return value.toString(); + } + } + } + + // 尝试获取getId方法 + try { + java.lang.reflect.Method getIdMethod = arg.getClass().getMethod("getDeviceImei"); + Object value = getIdMethod.invoke(arg); + if (value != null) { + return value.toString(); + } + } catch (Exception ignored) {} + + } catch (Exception e) { + log.debug("从参数中提取设备ID时出错: {}", e.getMessage()); + } + } + + return null; + } + + /** + * 生成设备的全局Redis key + */ + private String generateDeviceRedisKey(String deviceImei) { + return FUNCTION_ACCESS_KEY + deviceImei; + } +} diff --git a/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/aspectj/FunctionAccessBatchAspect.java b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/aspectj/FunctionAccessBatchAspect.java new file mode 100644 index 0000000..5a901ff --- /dev/null +++ b/fys-common/fys-common-ratelimiter/src/main/java/com/fuyuanshen/common/ratelimiter/aspectj/FunctionAccessBatchAspect.java @@ -0,0 +1,183 @@ +package com.fuyuanshen.common.ratelimiter.aspectj;// DeviceRedisKeyAspect.java + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.List; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; + +@Slf4j +@Aspect +@Component +public class FunctionAccessBatchAspect { + + // 定义切点,拦截带有DeviceRedisKeyAnnotation注解的方法 + @Around("@annotation(functionAccessBatchAspect)") + public Object addDeviceRedisKey(ProceedingJoinPoint joinPoint, FunctionAccessBatcAnnotation functionAccessBatchAspect) throws Throwable { + Object result; + String batchId = null; + List deviceImeiList = null; + + // 获取方法参数,查找设备ID + Object[] args = joinPoint.getArgs(); + batchId = extractDeviceBatchId(args); + deviceImeiList = extractDeviceImeiList(args); + if (StringUtils.isNotBlank(batchId)) { + // 生成全局Redis key + String redisKey = generateDeviceRedisKey(batchId); + String cacheKey = RedisUtils.getCacheObject(redisKey); + if(StringUtils.isNotBlank(cacheKey) && "ACTIVE".equals(cacheKey)){ + throw new ServiceException("设备已存在访问限制,请稍后再试", 500); + } + deviceImeiList.forEach(item->{ + RedisUtils.setCacheObject(FUNCTION_ACCESS_KEY + item, "ACTIVE", Duration.ofSeconds(functionAccessBatchAspect.timeOut())); + }); + String deviceImeiListStr = JSONUtil.toJsonStr(deviceImeiList); + RedisUtils.setCacheObject(redisKey, deviceImeiListStr , Duration.ofSeconds(functionAccessBatchAspect.batchMaxTimeOut())); + } + + // 执行原方法 + result = joinPoint.proceed(); + + return result; + } + + /** + * 从方法参数中提取设备IMEI列表 + */ + private List extractDeviceImeiList(Object[] args) { + if (args == null || args.length == 0) { + return null; + } + + for (Object arg : args) { + if (arg == null) continue; + + // 如果参数本身就是List类型 + if (arg instanceof List) { + List list = (List) arg; + if (!list.isEmpty() && list.get(0) instanceof String) { + // 检查是否为deviceImeiList + return (List) list; + } + } + + // 如果参数是对象,尝试获取deviceImeiList字段 + try { + // 使用反射获取deviceImeiList字段 + java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields(); + for (java.lang.reflect.Field field : fields) { + if ("deviceImeiList".equalsIgnoreCase(field.getName()) || + "device_imei_list".equalsIgnoreCase(field.getName()) || + "deviceImeis".equalsIgnoreCase(field.getName()) || + "device_imeis".equalsIgnoreCase(field.getName())) { + field.setAccessible(true); + Object value = field.get(arg); + if (value instanceof List) { + List list = (List) value; + if (!list.isEmpty() && list.get(0) instanceof String) { + return (List) list; + } + } + } + } + + // 尝试获取getDeviceImeiList方法 + try { + java.lang.reflect.Method getDeviceImeiListMethod = arg.getClass().getMethod("getDeviceImeiList"); + Object value = getDeviceImeiListMethod.invoke(arg); + if (value instanceof List) { + List list = (List) value; + if (!list.isEmpty() && list.get(0) instanceof String) { + return (List) list; + } + } + } catch (Exception ignored) {} + + // 尝试获取getDeviceImeis方法 + try { + java.lang.reflect.Method getDeviceImeisMethod = arg.getClass().getMethod("getDeviceImeis"); + Object value = getDeviceImeisMethod.invoke(arg); + if (value instanceof List) { + List list = (List) value; + if (!list.isEmpty() && list.get(0) instanceof String) { + return (List) list; + } + } + } catch (Exception ignored) {} + + } catch (Exception e) { + log.debug("从参数中提取设备IMEI列表时出错: {}", e.getMessage()); + } + } + + return null; + } + + + /** + * 从方法参数中提取设备ID + */ + private String extractDeviceBatchId(Object[] args) { + if (args == null || args.length == 0) { + return null; + } + + for (Object arg : args) { + if (arg == null) continue; + + // 如果参数本身就是设备ID (Long类型) + if (arg instanceof Long) { + return arg.toString(); + } + + // 如果参数是对象,尝试获取deviceId字段 + try { + // 使用反射获取deviceId字段 + java.lang.reflect.Field[] fields = arg.getClass().getDeclaredFields(); + for (java.lang.reflect.Field field : fields) { + if ("batchId".equalsIgnoreCase(field.getName()) || + "batch_id".equalsIgnoreCase(field.getName())) { + field.setAccessible(true); + Object value = field.get(arg); + if (value != null) { + return value.toString(); + } + } + } + + // 尝试获取getId方法 + try { + java.lang.reflect.Method getIdMethod = arg.getClass().getMethod("batchId"); + Object value = getIdMethod.invoke(arg); + if (value != null) { + return value.toString(); + } + } catch (Exception ignored) {} + + } catch (Exception e) { + log.debug("从参数中提取批次号时出错: {}", e.getMessage()); + } + } + + return null; + } + + /** + * 生成设备的全局Redis key + */ + private String generateDeviceRedisKey(String batchId) { + return FUNCTION_ACCESS_KEY + batchId; + } +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppPersonnelInfoBo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppPersonnelInfoBo.java index da469ac..70a7918 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppPersonnelInfoBo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppPersonnelInfoBo.java @@ -25,6 +25,11 @@ public class AppPersonnelInfoBo extends BaseEntity { */ private Long id; + /** + * 设备IMEI + */ + private String deviceImei; + /** * 设备id */ diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceDetailVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceDetailVo.java index 230a2c4..c172809 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceDetailVo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceDetailVo.java @@ -104,4 +104,7 @@ public class AppDeviceDetailVo { * 告警状态(0解除告警,1告警) */ private String alarmStatus; + + // 灯光亮度 + private String lightBrightness; } 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 d11d657..f9e8483 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 @@ -104,4 +104,41 @@ public class AppDeviceShareDetailVo implements Serializable { * 发送信息 */ private String sendMsg; + + //设备主灯档位 + 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; } diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareVo.java index b9ea67d..224ca8c 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareVo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareVo.java @@ -57,6 +57,12 @@ public class AppDeviceShareVo implements Serializable { @ExcelProperty(value = "手机号") private String phonenumber; + /** + * 他人分享手机号 + */ + @ExcelProperty(value = "手机号") + private String otherPhonenumber; + /** * 功能权限(1:灯光模式;2:激光模式;3:开机画面;4:人员信息登记;5:发送信息;6:产品信息) 以逗号分隔 @@ -65,6 +71,11 @@ public class AppDeviceShareVo implements Serializable { @ExcelDictFormat(readConverterExp = "1=:灯光模式;2:激光模式;3:开机画面;4:人员信息登记;5:发送信息;6:产品信息") private String permission; + /** + * 设备类型 + */ + private String typeName; + /** * 备注 */ @@ -73,4 +84,29 @@ public class AppDeviceShareVo implements Serializable { // 设备图片 private String devicePic; + + /** + * 在线状态(0离线,1在线) + */ + private Integer onlineStatus; + + /** + * 电量 百分比 + */ + private String battery; + + /** + * 纬度 + */ + private String latitude; + + /** + * 经度 + */ + private String longitude; + + /** + * 告警状态(0解除告警,1告警) + */ + private String alarmStatus; } diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceShareMapper.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceShareMapper.java index 01dbf1a..1de4c14 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceShareMapper.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceShareMapper.java @@ -1,5 +1,6 @@ package com.fuyuanshen.app.mapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fuyuanshen.app.domain.AppDeviceShare; @@ -16,4 +17,6 @@ import org.apache.ibatis.annotations.Param; */ public interface AppDeviceShareMapper extends BaseMapperPlus { IPage otherDeviceShareList(@Param("bo") AppDeviceShareBo bo, Page page); + + Page selectAppDeviceShareList(@Param("bo") AppDeviceShareBo bo,Page page); } diff --git a/fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceShareMapper.xml b/fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceShareMapper.xml index 2202eae..39033bc 100644 --- a/fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceShareMapper.xml +++ b/fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceShareMapper.xml @@ -5,6 +5,46 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceRepairRecordsController.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceRepairRecordsController.java new file mode 100644 index 0000000..1304daa --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/controller/DeviceRepairRecordsController.java @@ -0,0 +1,105 @@ +package com.fuyuanshen.equipment.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit; +import com.fuyuanshen.common.log.annotation.Log; +import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.common.log.enums.BusinessType; +import com.fuyuanshen.common.excel.utils.ExcelUtil; +import com.fuyuanshen.equipment.domain.vo.DeviceRepairRecordsVo; +import com.fuyuanshen.equipment.domain.bo.DeviceRepairRecordsBo; +import com.fuyuanshen.equipment.service.IDeviceRepairRecordsService; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; + +/** + * 设备维修记录 + * + * @author Lion Li + * @date 2025-08-08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/equipment/repairRecords") +public class DeviceRepairRecordsController extends BaseController { + + private final IDeviceRepairRecordsService deviceRepairRecordsService; + + /** + * 查询设备维修记录列表 + */ + @SaCheckPermission("equipment:repairRecords:list") + @GetMapping("/list") + public TableDataInfo list(DeviceRepairRecordsBo bo, PageQuery pageQuery) { + return deviceRepairRecordsService.queryPageList(bo, pageQuery); + } + + /** + * 导出设备维修记录列表 + */ + @SaCheckPermission("equipment:repairRecords:export") + @Log(title = "设备维修记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DeviceRepairRecordsBo bo, HttpServletResponse response) { + List list = deviceRepairRecordsService.queryList(bo); + ExcelUtil.exportExcel(list, "设备维修记录", DeviceRepairRecordsVo.class, response); + } + + /** + * 获取设备维修记录详细信息 + * + * @param recordId 主键 + */ + @SaCheckPermission("equipment:repairRecords:query") + @GetMapping("/{recordId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long recordId) { + return R.ok(deviceRepairRecordsService.queryById(recordId)); + } + + /** + * 新增设备维修记录 + */ + @SaCheckPermission("equipment:repairRecords:add") + @Log(title = "设备维修记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DeviceRepairRecordsBo bo) { + return toAjax(deviceRepairRecordsService.insertByBo(bo)); + } + + /** + * 修改设备维修记录 + */ + @SaCheckPermission("equipment:repairRecords:edit") + @Log(title = "设备维修记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DeviceRepairRecordsBo bo) { + return toAjax(deviceRepairRecordsService.updateByBo(bo)); + } + + /** + * 删除设备维修记录 + * + * @param recordIds 主键串 + */ + @SaCheckPermission("equipment:repairRecords:remove") + @Log(title = "设备维修记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{recordIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] recordIds) { + return toAjax(deviceRepairRecordsService.deleteWithValidByIds(List.of(recordIds), true)); + } +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGroup.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGroup.java new file mode 100644 index 0000000..16f8414 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceGroup.java @@ -0,0 +1,56 @@ +package com.fuyuanshen.equipment.domain; + +import com.fuyuanshen.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 设备分组对象 device_group + * + * @author Lion Li + * @date 2025-08-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("device_group") +public class DeviceGroup extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 分组名称 + */ + private String groupName; + + /** + * 状态:0-禁用,1-正常 + */ + private Long status; + + /** + * 父分组ID + */ + private Long parentId; + + /** + * 完整分组路径 + */ + private String fullPath; + + /** + * 删除标记:0-未删除,1-已删除 + */ + private Long isDeleted; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceRepairRecords.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceRepairRecords.java new file mode 100644 index 0000000..3fca3c4 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceRepairRecords.java @@ -0,0 +1,58 @@ +package com.fuyuanshen.equipment.domain; + +import com.fuyuanshen.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 设备维修记录对象 device_repair_records + * + * @author Lion Li + * @date 2025-08-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("device_repair_records") +public class DeviceRepairRecords extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 维修记录ID + */ + @TableId(value = "record_id") + private Long recordId; + + /** + * 设备ID + */ + private String deviceId; + + /** + * 维修时间 + */ + private Date repairTime; + + /** + * 维修部位 + */ + private String repairPart; + + /** + * 维修原因 + */ + private String repairReason; + + /** + * 维修人员 + */ + private String repairPerson; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceType.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceType.java index 76e554e..32bd32e 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceType.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/DeviceType.java @@ -65,4 +65,11 @@ public class DeviceType extends TenantEntity { BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true)); } + /** + * 型号字典用于APP页面跳转 + */ + @Schema(name = "型号字典用于APP页面跳转") + private String modelDictionary; + + } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGroupBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGroupBo.java new file mode 100644 index 0000000..37cff3b --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceGroupBo.java @@ -0,0 +1,65 @@ +package com.fuyuanshen.equipment.domain.bo; + +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.equipment.domain.DeviceGroup; +import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMapper; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 设备分组业务对象 device_group + * + * @author Lion Li + * @date 2025-08-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DeviceGroup.class, reverseConvertGenerate = false) +public class DeviceGroupBo extends BaseEntity { + + /** + * 主键ID + */ + // @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 分组名称 + */ + @NotBlank(message = "分组名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String groupName; + + /** + * 状态:0-禁用,1-正常 + */ + // @NotNull(message = "状态:0-禁用,1-正常不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long status; + + /** + * 父分组ID + */ + private Long parentId; + + /** + * 完整分组路径 + */ + private String fullPath; + + /** + * 删除标记:0-未删除,1-已删除 + */ + // @NotNull(message = "删除标记:0-未删除,1-已删除不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long isDeleted; + + + @Schema(name = "页码", example = "1") + private Integer pageNum = 1; + + @Schema(name = "每页数据量", example = "10") + private Integer pageSize = 10; + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java new file mode 100644 index 0000000..b40b975 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java @@ -0,0 +1,62 @@ +package com.fuyuanshen.equipment.domain.bo; + +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.core.validate.EditGroup; +import com.fuyuanshen.equipment.domain.DeviceRepairRecords; +import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 设备维修记录业务对象 device_repair_records + * + * @author Lion Li + * @date 2025-08-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DeviceRepairRecords.class, reverseConvertGenerate = false) +public class DeviceRepairRecordsBo extends BaseEntity { + + /** + * 维修记录ID + */ + @NotNull(message = "维修记录ID不能为空", groups = { EditGroup.class }) + private Long recordId; + + /** + * 设备ID + */ + @NotBlank(message = "设备ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private String deviceId; + + /** + * 维修时间 + */ + @NotNull(message = "维修时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date repairTime; + + /** + * 维修部位 + */ + @NotBlank(message = "维修部位不能为空", groups = { AddGroup.class, EditGroup.class }) + private String repairPart; + + /** + * 维修原因 + */ + @NotBlank(message = "维修原因不能为空", groups = { AddGroup.class, EditGroup.class }) + private String repairReason; + + /** + * 维修人员 + */ + @NotBlank(message = "维修人员不能为空", groups = { AddGroup.class, EditGroup.class }) + private String repairPerson; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceSendMsgBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceSendMsgBo.java index 1b57ec6..4010c05 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceSendMsgBo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceSendMsgBo.java @@ -14,9 +14,16 @@ public class AppDeviceSendMsgBo { private List deviceIds; + private List deviceImeiList; + /** * 下发指令 */ private String instructValue; + /** + * 批次号 + */ + private String batchId; + } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/form/DeviceTypeForm.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/form/DeviceTypeForm.java index d416718..7fc8a10 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/form/DeviceTypeForm.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/form/DeviceTypeForm.java @@ -1,13 +1,6 @@ package com.fuyuanshen.equipment.domain.form; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.bean.copier.CopyOptions; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.fuyuanshen.common.tenant.core.TenantEntity; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; import lombok.Data; /** @@ -36,4 +29,10 @@ public class DeviceTypeForm { @Schema(name = "通讯方式", example = "0:4G;1:蓝牙") private String communicationMode; + /** + * 型号字典用于APP页面跳转 + */ + @Schema(name = "型号字典用于APP页面跳转") + private String modelDictionary; + } 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 1d0ec23..aafc6fc 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 @@ -81,4 +81,9 @@ public class AppDeviceVo implements Serializable { * 告警状态(0解除告警,1告警) */ private String alarmStatus; + + /** + * 设备详情页面 + */ + private String detailPageUrl; } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGroupVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGroupVo.java new file mode 100644 index 0000000..58f6450 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceGroupVo.java @@ -0,0 +1,79 @@ +package com.fuyuanshen.equipment.domain.vo; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fuyuanshen.equipment.domain.DeviceGroup; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import com.fuyuanshen.common.excel.annotation.ExcelDictFormat; +import com.fuyuanshen.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + + +/** + * 设备分组视图对象 device_group + * + * @author Lion Li + * @date 2025-08-08 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DeviceGroup.class) +public class DeviceGroupVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 分组名称 + */ + @ExcelProperty(value = "分组名称") + private String groupName; + + /** + * 状态:0-禁用,1-正常 + */ + @ExcelProperty(value = "状态:0-禁用,1-正常") + private String status; + + /** + * 父分组ID + */ + @ExcelProperty(value = "父分组ID") + private Long parentId; + + /** + * 完整分组路径 + */ + @ExcelProperty(value = "完整分组路径") + private String fullPath; + + /** + * 删除标记:0-未删除,1-已删除 + */ + @ExcelProperty(value = "删除标记:0-未删除,1-已删除") + private Long isDeleted; + + /** + * 嵌套子分组 + */ + private List children; + + /** + * 创建时间 + */ + private String createTime; + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceRepairRecordsVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceRepairRecordsVo.java new file mode 100644 index 0000000..f66bb67 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DeviceRepairRecordsVo.java @@ -0,0 +1,70 @@ +package com.fuyuanshen.equipment.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fuyuanshen.equipment.domain.DeviceRepairRecords; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import com.fuyuanshen.common.excel.annotation.ExcelDictFormat; +import com.fuyuanshen.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 设备维修记录视图对象 device_repair_records + * + * @author Lion Li + * @date 2025-08-08 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DeviceRepairRecords.class) +public class DeviceRepairRecordsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 维修记录ID + */ + @ExcelProperty(value = "维修记录ID") + private Long recordId; + + /** + * 设备ID + */ + @ExcelProperty(value = "设备ID") + private String deviceId; + + /** + * 维修时间 + */ + @ExcelProperty(value = "维修时间") + private Date repairTime; + + /** + * 维修部位 + */ + @ExcelProperty(value = "维修部位") + private String repairPart; + + /** + * 维修原因 + */ + @ExcelProperty(value = "维修原因") + private String repairReason; + + /** + * 维修人员 + */ + @ExcelProperty(value = "维修人员") + private String repairPerson; + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/enums/LightModeEnum.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/enums/LightModeEnum.java new file mode 100644 index 0000000..7394a08 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/enums/LightModeEnum.java @@ -0,0 +1,72 @@ +package com.fuyuanshen.equipment.enums; + +/** + * 灯光模式枚举 + */ +public enum LightModeEnum { + + /** + * 关灯模式 + */ + OFF(0, "关灯"), + + /** + * 强光模式 + */ + HIGH_BEAM(1, "开启强光模式"), + + /** + * 弱光模式 + */ + LOW_BEAM(2, "开启弱光模式"), + + /** + * 爆闪模式 + */ + STROBE(3, "开启爆闪模式"), + + /** + * 泛光模式 + */ + FLOOD(4, "开启泛光模式"); + + private final Integer code; + private final String name; + + LightModeEnum(Integer code, String name) { + this.code = code; + this.name = name; + } + + public Integer getCode() { + return code; + } + + public String getName() { + return name; + } + + /** + * 根据编号获取枚举 + * @param code 编号 + * @return 对应的枚举值 + */ + public static LightModeEnum getByCode(Integer code) { + for (LightModeEnum mode : LightModeEnum.values()) { + if (mode.getCode().equals(code)) { + return mode; + } + } + return null; + } + + /** + * 根据编号获取名称 + * @param code 编号 + * @return 对应的名称 + */ + public static String getNameByCode(Integer code) { + LightModeEnum mode = getByCode(code); + return mode != null ? mode.getName() : null; + } +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGroupMapper.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGroupMapper.java new file mode 100644 index 0000000..a681455 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceGroupMapper.java @@ -0,0 +1,38 @@ +package com.fuyuanshen.equipment.mapper; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuyuanshen.equipment.domain.Device; +import com.fuyuanshen.equipment.domain.DeviceGroup; +import com.fuyuanshen.equipment.domain.bo.DeviceGroupBo; +import com.fuyuanshen.equipment.domain.vo.DeviceGroupVo; +import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 设备分组Mapper接口 + * + * @author Lion Li + * @date 2025-08-08 + */ +public interface DeviceGroupMapper extends BaseMapperPlus { + + /** + * 查询设备分组列表 + * + * @param bo 设备分组 + * @return 设备分组 + */ + IPage selectRootGroups(@Param("bo") DeviceGroupBo bo, Page page); + + /** + * 查询子分组 + * + * @param id + * @return + */ + List selectByParentId(Long id); + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceMapper.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceMapper.java index 57cbd4e..96bbfce 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceMapper.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceMapper.java @@ -66,4 +66,6 @@ public interface DeviceMapper extends BaseMapper { * @return */ List findByOriginalDeviceId(Long originalDeviceId); + + AppDeviceVo getDeviceInfo(@Param("deviceMac") String deviceMac); } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceRepairRecordsMapper.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceRepairRecordsMapper.java new file mode 100644 index 0000000..eb3cec2 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/mapper/DeviceRepairRecordsMapper.java @@ -0,0 +1,15 @@ +package com.fuyuanshen.equipment.mapper; + +import com.fuyuanshen.equipment.domain.DeviceRepairRecords; +import com.fuyuanshen.equipment.domain.vo.DeviceRepairRecordsVo; +import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设备维修记录Mapper接口 + * + * @author Lion Li + * @date 2025-08-08 + */ +public interface DeviceRepairRecordsMapper extends BaseMapperPlus { + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGroupService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGroupService.java new file mode 100644 index 0000000..9662fef --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceGroupService.java @@ -0,0 +1,59 @@ +package com.fuyuanshen.equipment.service; + +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.equipment.domain.vo.DeviceGroupVo; +import com.fuyuanshen.equipment.domain.bo.DeviceGroupBo; + +import java.util.Collection; +import java.util.List; + +/** + * 设备分组Service接口 + * + * @author Lion Li + * @date 2025-08-08 + */ +public interface IDeviceGroupService { + + /** + * 查询设备分组 + * + * @param id 主键 + * @return 设备分组 + */ + DeviceGroupVo queryById(Long id); + + + /** + * 查询符合条件的设备分组列表 + * + * @param bo 查询条件 + * @return 设备分组列表 + */ + List queryList(DeviceGroupBo bo); + + /** + * 新增设备分组 + * + * @param bo 设备分组 + * @return 是否新增成功 + */ + Boolean insertByBo(DeviceGroupBo bo); + + /** + * 修改设备分组 + * + * @param bo 设备分组 + * @return 是否修改成功 + */ + Boolean updateByBo(DeviceGroupBo bo); + + /** + * 校验并批量删除设备分组信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceRepairRecordsService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceRepairRecordsService.java new file mode 100644 index 0000000..8fb838c --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/IDeviceRepairRecordsService.java @@ -0,0 +1,68 @@ +package com.fuyuanshen.equipment.service; + +import com.fuyuanshen.equipment.domain.vo.DeviceRepairRecordsVo; +import com.fuyuanshen.equipment.domain.bo.DeviceRepairRecordsBo; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 设备维修记录Service接口 + * + * @author Lion Li + * @date 2025-08-08 + */ +public interface IDeviceRepairRecordsService { + + /** + * 查询设备维修记录 + * + * @param recordId 主键 + * @return 设备维修记录 + */ + DeviceRepairRecordsVo queryById(Long recordId); + + /** + * 分页查询设备维修记录列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 设备维修记录分页列表 + */ + TableDataInfo queryPageList(DeviceRepairRecordsBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的设备维修记录列表 + * + * @param bo 查询条件 + * @return 设备维修记录列表 + */ + List queryList(DeviceRepairRecordsBo bo); + + /** + * 新增设备维修记录 + * + * @param bo 设备维修记录 + * @return 是否新增成功 + */ + Boolean insertByBo(DeviceRepairRecordsBo bo); + + /** + * 修改设备维修记录 + * + * @param bo 设备维修记录 + * @return 是否修改成功 + */ + Boolean updateByBo(DeviceRepairRecordsBo bo); + + /** + * 校验并批量删除设备维修记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGroupServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGroupServiceImpl.java new file mode 100644 index 0000000..51cf369 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceGroupServiceImpl.java @@ -0,0 +1,172 @@ +package com.fuyuanshen.equipment.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.utils.MapstructUtils; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.satoken.utils.LoginHelper; +import com.fuyuanshen.equipment.domain.Device; +import com.fuyuanshen.equipment.domain.DeviceTypeGrants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import com.fuyuanshen.equipment.domain.bo.DeviceGroupBo; +import com.fuyuanshen.equipment.domain.vo.DeviceGroupVo; +import com.fuyuanshen.equipment.domain.DeviceGroup; +import com.fuyuanshen.equipment.mapper.DeviceGroupMapper; +import com.fuyuanshen.equipment.service.IDeviceGroupService; + +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.stream.Collectors; + +/** + * 设备分组Service业务层处理 + * + * @author Lion Li + * @date 2025-08-08 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DeviceGroupServiceImpl implements IDeviceGroupService { + + private final DeviceGroupMapper baseMapper; + + + /** + * 查询设备分组 + * + * @param id 主键 + * @return 设备分组 + */ + @Override + public DeviceGroupVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + + /** + * 查询符合条件的设备分组列表 + * + * @param bo 查询条件 + * @return 设备分组列表 + */ + @Override + public List queryList(DeviceGroupBo bo) { + Page page = new Page<>(bo.getPageNum(), bo.getPageSize()); + // 1. 查询顶级分组(parent_id为null) + IPage rootGroups = baseMapper.selectRootGroups(bo, page); + List records = rootGroups.getRecords(); + + // 2. 递归构建树形结构 + return records.stream() + .map(this::buildGroupTree) + .collect(Collectors.toList()); + } + + private DeviceGroupVo buildGroupTree(DeviceGroup group) { + DeviceGroupVo vo = convertToVO(group); + // 递归查询子分组 + List children = baseMapper.selectByParentId(group.getId()); + vo.setChildren(children.stream() + .map(this::buildGroupTree) + .collect(Collectors.toList())); + return vo; + } + + private DeviceGroupVo convertToVO(DeviceGroup group) { + DeviceGroupVo vo = new DeviceGroupVo(); + vo.setId(group.getId()); + vo.setGroupName(group.getGroupName()); + vo.setStatus(group.getStatus() == 1 ? "正常" : "禁用"); + vo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(group.getCreateTime())); + return vo; + } + + private LambdaQueryWrapper buildQueryWrapper(DeviceGroupBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(DeviceGroup::getId); + lqw.like(StringUtils.isNotBlank(bo.getGroupName()), DeviceGroup::getGroupName, bo.getGroupName()); + lqw.eq(bo.getStatus() != null, DeviceGroup::getStatus, bo.getStatus()); + lqw.eq(bo.getParentId() != null, DeviceGroup::getParentId, bo.getParentId()); + lqw.eq(StringUtils.isNotBlank(bo.getFullPath()), DeviceGroup::getFullPath, bo.getFullPath()); + lqw.eq(bo.getIsDeleted() != null, DeviceGroup::getIsDeleted, bo.getIsDeleted()); + return lqw; + } + + + /** + * 新增设备分组 + * + * @param bo 设备分组 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(DeviceGroupBo bo) { + + // 验证分组名称唯一性 + DeviceGroup deviceGroup = baseMapper.selectOne(new QueryWrapper().eq("group_name", bo.getGroupName())); + if (deviceGroup != null) { + throw new RuntimeException("分组名称已存在,请勿重复添加!!!"); + } + + // 验证父分组是否存在(如果提供了parentId) + DeviceGroup pDeviceGroup = baseMapper.selectById(bo.getParentId()); + if (bo.getParentId() != null && pDeviceGroup == null) { + throw new RuntimeException("父分组不存在!!!"); + } + + DeviceGroup add = MapstructUtils.convert(bo, DeviceGroup.class); + // validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + + /** + * 修改设备分组 + * + * @param bo 设备分组 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(DeviceGroupBo bo) { + DeviceGroup update = MapstructUtils.convert(bo, DeviceGroup.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DeviceGroup entity) { + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除设备分组信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} 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 new file mode 100644 index 0000000..5eb4f89 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java @@ -0,0 +1,136 @@ +package com.fuyuanshen.equipment.service.impl; + +import com.fuyuanshen.common.core.utils.MapstructUtils; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; +import com.fuyuanshen.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import com.fuyuanshen.equipment.domain.bo.DeviceRepairRecordsBo; +import com.fuyuanshen.equipment.domain.vo.DeviceRepairRecordsVo; +import com.fuyuanshen.equipment.domain.DeviceRepairRecords; +import com.fuyuanshen.equipment.mapper.DeviceRepairRecordsMapper; +import com.fuyuanshen.equipment.service.IDeviceRepairRecordsService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 设备维修记录Service业务层处理 + * + * @author Lion Li + * @date 2025-08-08 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DeviceRepairRecordsServiceImpl implements IDeviceRepairRecordsService { + + private final DeviceRepairRecordsMapper baseMapper; + + /** + * 查询设备维修记录 + * + * @param recordId 主键 + * @return 设备维修记录 + */ + @Override + public DeviceRepairRecordsVo queryById(Long recordId){ + return baseMapper.selectVoById(recordId); + } + + /** + * 分页查询设备维修记录列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 设备维修记录分页列表 + */ + @Override + public TableDataInfo queryPageList(DeviceRepairRecordsBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的设备维修记录列表 + * + * @param bo 查询条件 + * @return 设备维修记录列表 + */ + @Override + public List queryList(DeviceRepairRecordsBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(DeviceRepairRecordsBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(DeviceRepairRecords::getRecordId); + lqw.eq(StringUtils.isNotBlank(bo.getDeviceId()), DeviceRepairRecords::getDeviceId, bo.getDeviceId()); + lqw.eq(bo.getRepairTime() != null, DeviceRepairRecords::getRepairTime, bo.getRepairTime()); + lqw.eq(StringUtils.isNotBlank(bo.getRepairPart()), DeviceRepairRecords::getRepairPart, bo.getRepairPart()); + lqw.eq(StringUtils.isNotBlank(bo.getRepairReason()), DeviceRepairRecords::getRepairReason, bo.getRepairReason()); + lqw.eq(StringUtils.isNotBlank(bo.getRepairPerson()), DeviceRepairRecords::getRepairPerson, bo.getRepairPerson()); + return lqw; + } + + /** + * 新增设备维修记录 + * + * @param bo 设备维修记录 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(DeviceRepairRecordsBo bo) { + DeviceRepairRecords add = MapstructUtils.convert(bo, DeviceRepairRecords.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setRecordId(add.getRecordId()); + } + return flag; + } + + /** + * 修改设备维修记录 + * + * @param bo 设备维修记录 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(DeviceRepairRecordsBo bo) { + DeviceRepairRecords update = MapstructUtils.convert(bo, DeviceRepairRecords.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DeviceRepairRecords entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除设备维修记录信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGroupMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGroupMapper.xml new file mode 100644 index 0000000..95050b1 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceGroupMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + 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 8af7215..e5c95a3 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 @@ -148,6 +148,7 @@ dt.type_name, dt.communication_mode, d.bluetooth_name, + dt.model_dictionary detailPageUrl, c.binding_time from device d inner join device_type dt on d.device_type = dt.id @@ -177,6 +178,7 @@ d.device_pic, dt.type_name, dt.communication_mode, + dt.model_dictionary detailPageUrl, d.bluetooth_name from device d inner join device_type dt on d.device_type = dt.id @@ -210,5 +212,20 @@ FROM device WHERE original_device_id = #{originalDeviceId} + \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceRepairRecordsMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceRepairRecordsMapper.xml new file mode 100644 index 0000000..46af59f --- /dev/null +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceRepairRecordsMapper.xml @@ -0,0 +1,7 @@ + + + + +