From 5f4b12a3209c0c5ee540a7cb6a1d27ca3a248947 Mon Sep 17 00:00:00 2001 From: chenyouting <514333061@qq.com> Date: Fri, 1 Aug 2025 09:00:32 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/service/AppDeviceBizService.java | 64 ++++++++- .../web/service/AppRegisterService.java | 4 +- .../src/main/resources/application-prod.yml | 19 +-- .../AppDeviceBindRecordController.java | 105 ++++++++++++++ .../app/domain/AppDeviceBindRecord.java | 53 +++++++ .../app/domain/bo/AppDeviceBindRecordBo.java | 51 +++++++ .../app/domain/vo/AppDeviceBindRecordVo.java | 64 +++++++++ .../app/mapper/AppDeviceBindRecordMapper.java | 15 ++ .../service/IAppDeviceBindRecordService.java | 68 +++++++++ .../impl/AppDeviceBindRecordServiceImpl.java | 133 ++++++++++++++++++ .../mapper/app/AppDeviceBindRecordMapper.xml | 7 + .../mapper/equipment/DeviceMapper.xml | 3 +- 12 files changed, 569 insertions(+), 17 deletions(-) create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/controller/AppDeviceBindRecordController.java create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppDeviceBindRecordBo.java create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceBindRecordVo.java create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceBindRecordMapper.java create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppDeviceBindRecordService.java create mode 100644 fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/impl/AppDeviceBindRecordServiceImpl.java create mode 100644 fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceBindRecordMapper.xml 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 index 0f1a83d2..b5bc9e1a 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java @@ -4,12 +4,14 @@ import com.alibaba.fastjson2.JSON; 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.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.exception.ServiceException; @@ -51,7 +53,7 @@ public class AppDeviceBizService { private final AppPersonnelInfoMapper appPersonnelInfoMapper; private final DeviceTypeMapper deviceTypeMapper; private final MqttGateway mqttGateway; - + private final AppDeviceBindRecordMapper appDeviceBindRecordMapper; public List getTypeList() { Long userId = AppLoginHelper.getUserId(); @@ -120,13 +122,32 @@ public class AppDeviceBizService { 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(); @@ -137,9 +158,27 @@ public class AppDeviceBizService { 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()); + 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()) @@ -159,10 +198,21 @@ public class AppDeviceBizService { } UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); deviceUpdateWrapper.eq("id", device.getId()) - .set("binding_status", BindingStatusEnum.UNBOUND.getCode()) .set("binding_user_id", null) + .set("binding_status", BindingStatusEnum.UNBOUND.getCode()) .set("binding_time", null); - return deviceMapper.update(null, deviceUpdateWrapper); + deviceMapper.update(null, deviceUpdateWrapper); + + Long userId = AppLoginHelper.getUserId(); + QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); + bindRecordQueryWrapper.eq("device_id", device.getId()); + bindRecordQueryWrapper.eq("binding_user_id", userId); + AppDeviceBindRecord appDeviceBindRecord = appDeviceBindRecordMapper.selectOne(bindRecordQueryWrapper); + if (appDeviceBindRecord != null) { + return appDeviceBindRecordMapper.deleteById(appDeviceBindRecord.getId()); + } + + return 1; } public AppDeviceDetailVo getInfo(Long id) { diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/AppRegisterService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/AppRegisterService.java index 02708445..9b614259 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/AppRegisterService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/AppRegisterService.java @@ -7,6 +7,7 @@ import com.fuyuanshen.app.mapper.AppUserMapper; import com.fuyuanshen.common.core.constant.Constants; import com.fuyuanshen.common.core.constant.GlobalConstants; import com.fuyuanshen.common.core.domain.model.AppSmsRegisterBody; +import com.fuyuanshen.common.core.enums.UserType; import com.fuyuanshen.common.core.exception.BadRequestException; import com.fuyuanshen.common.core.exception.user.CaptchaException; import com.fuyuanshen.common.core.exception.user.CaptchaExpireException; @@ -47,6 +48,7 @@ public class AppRegisterService { String phoneNumber = registerBody.getPhoneNumber(); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(AppUser::getPhonenumber, phoneNumber); + wrapper.eq(AppUser::getUserType, UserType.APP_USER.getUserType()); AppUserVo appUserVo = appUserMapper.selectVoOne(wrapper); if (appUserVo != null) { throw new BadRequestException("该手机号已被注册"); @@ -67,7 +69,7 @@ public class AppRegisterService { appUser.setNickName(username); appUser.setPhonenumber(phoneNumber); appUser.setPassword(password); - appUser.setUserType("app_user"); + appUser.setUserType(UserType.APP_USER.getUserType()); appUser.setTenantId(tenantId); appUser.setLoginIp(ServletUtils.getClientIP()); appUser.setStatus("0"); diff --git a/fys-admin/src/main/resources/application-prod.yml b/fys-admin/src/main/resources/application-prod.yml index 1533e580..03a3b832 100644 --- a/fys-admin/src/main/resources/application-prod.yml +++ b/fys-admin/src/main/resources/application-prod.yml @@ -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 @@ -277,11 +280,11 @@ justauth: # MQTT配置 mqtt: username: admin - password: #YtvpSfCNG - url: tcp://47.120.79.150:2883 + password: fys123456 + url: tcp://47.107.152.87:1883 subClientId: fys_subClient - subTopic: worker/alert/#,worker/location/# - pubTopic: worker/location + subTopic: A/#,worker/location/# + pubTopic: B/# pubClientId: fys_pubClient diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/controller/AppDeviceBindRecordController.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/controller/AppDeviceBindRecordController.java new file mode 100644 index 00000000..fc5c9cd1 --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/controller/AppDeviceBindRecordController.java @@ -0,0 +1,105 @@ +package com.fuyuanshen.app.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.app.domain.vo.AppDeviceBindRecordVo; +import com.fuyuanshen.app.domain.bo.AppDeviceBindRecordBo; +import com.fuyuanshen.app.service.IAppDeviceBindRecordService; +import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; + +/** + * 设备绑定关系 + * + * @author Lion Li + * @date 2025-07-28 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/app/deviceBindRecord") +public class AppDeviceBindRecordController extends BaseController { + + private final IAppDeviceBindRecordService appDeviceBindRecordService; + + /** + * 查询设备绑定关系列表 + */ + @SaCheckPermission("app:deviceBindRecord:list") + @GetMapping("/list") + public TableDataInfo list(AppDeviceBindRecordBo bo, PageQuery pageQuery) { + return appDeviceBindRecordService.queryPageList(bo, pageQuery); + } + + /** + * 导出设备绑定关系列表 + */ + @SaCheckPermission("app:deviceBindRecord:export") + @Log(title = "设备绑定关系", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(AppDeviceBindRecordBo bo, HttpServletResponse response) { + List list = appDeviceBindRecordService.queryList(bo); + ExcelUtil.exportExcel(list, "设备绑定关系", AppDeviceBindRecordVo.class, response); + } + + /** + * 获取设备绑定关系详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("app:deviceBindRecord:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(appDeviceBindRecordService.queryById(id)); + } + + /** + * 新增设备绑定关系 + */ + @SaCheckPermission("app:deviceBindRecord:add") + @Log(title = "设备绑定关系", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody AppDeviceBindRecordBo bo) { + return toAjax(appDeviceBindRecordService.insertByBo(bo)); + } + + /** + * 修改设备绑定关系 + */ + @SaCheckPermission("app:deviceBindRecord:edit") + @Log(title = "设备绑定关系", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody AppDeviceBindRecordBo bo) { + return toAjax(appDeviceBindRecordService.updateByBo(bo)); + } + + /** + * 删除设备绑定关系 + * + * @param ids 主键串 + */ + @SaCheckPermission("app:deviceBindRecord:remove") + @Log(title = "设备绑定关系", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(appDeviceBindRecordService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java new file mode 100644 index 00000000..40698ce0 --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java @@ -0,0 +1,53 @@ +package com.fuyuanshen.app.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fuyuanshen.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.util.Date; + +/** + * 设备绑定关系对象 app_device_bind_record + * + * @author Lion Li + * @date 2025-07-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("app_device_bind_record") +public class AppDeviceBindRecord extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 设备id + */ + private Long deviceId; + + /** + * 绑定用户id + */ + private Long bindingUserId; + + /** + * 备注 + */ + private String remark; + + /** + * 绑定时间 + */ + private Date bindingTime; + + +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppDeviceBindRecordBo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppDeviceBindRecordBo.java new file mode 100644 index 00000000..4742933b --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/bo/AppDeviceBindRecordBo.java @@ -0,0 +1,51 @@ +package com.fuyuanshen.app.domain.bo; + +import com.fuyuanshen.app.domain.AppDeviceBindRecord; +import com.fuyuanshen.common.core.validate.EditGroup; +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; + +/** + * 设备绑定关系业务对象 app_device_bind_record + * + * @author Lion Li + * @date 2025-07-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = AppDeviceBindRecord.class, reverseConvertGenerate = false) +public class AppDeviceBindRecordBo extends BaseEntity { + + /** + * 主键ID + */ + @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 设备id + */ + private Long deviceId; + + /** + * 绑定用户id + */ + private Long bindingUserId; + + /** + * 备注 + */ + private String remark; + + /** + * 绑定时间 + */ + private Date bindingTime; + + +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceBindRecordVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceBindRecordVo.java new file mode 100644 index 00000000..206b3f9e --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceBindRecordVo.java @@ -0,0 +1,64 @@ +package com.fuyuanshen.app.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fuyuanshen.app.domain.AppDeviceBindRecord; +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; + + + +/** + * 设备绑定关系视图对象 app_device_bind_record + * + * @author Lion Li + * @date 2025-07-28 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = AppDeviceBindRecord.class) +public class AppDeviceBindRecordVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 设备id + */ + @ExcelProperty(value = "设备id") + private Long deviceId; + + /** + * 绑定用户id + */ + @ExcelProperty(value = "绑定用户id") + private Long bindingUserId; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 绑定时间 + */ + @ExcelProperty(value = "绑定时间") + private Date bindingTime; + + +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceBindRecordMapper.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceBindRecordMapper.java new file mode 100644 index 00000000..2fa66a8f --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/mapper/AppDeviceBindRecordMapper.java @@ -0,0 +1,15 @@ +package com.fuyuanshen.app.mapper; + +import com.fuyuanshen.app.domain.AppDeviceBindRecord; +import com.fuyuanshen.app.domain.vo.AppDeviceBindRecordVo; +import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 设备绑定关系Mapper接口 + * + * @author Lion Li + * @date 2025-07-28 + */ +public interface AppDeviceBindRecordMapper extends BaseMapperPlus { + +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppDeviceBindRecordService.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppDeviceBindRecordService.java new file mode 100644 index 00000000..2d3a2391 --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/IAppDeviceBindRecordService.java @@ -0,0 +1,68 @@ +package com.fuyuanshen.app.service; + +import com.fuyuanshen.app.domain.vo.AppDeviceBindRecordVo; +import com.fuyuanshen.app.domain.bo.AppDeviceBindRecordBo; +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-07-28 + */ +public interface IAppDeviceBindRecordService { + + /** + * 查询设备绑定关系 + * + * @param id 主键 + * @return 设备绑定关系 + */ + AppDeviceBindRecordVo queryById(Long id); + + /** + * 分页查询设备绑定关系列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 设备绑定关系分页列表 + */ + TableDataInfo queryPageList(AppDeviceBindRecordBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的设备绑定关系列表 + * + * @param bo 查询条件 + * @return 设备绑定关系列表 + */ + List queryList(AppDeviceBindRecordBo bo); + + /** + * 新增设备绑定关系 + * + * @param bo 设备绑定关系 + * @return 是否新增成功 + */ + Boolean insertByBo(AppDeviceBindRecordBo bo); + + /** + * 修改设备绑定关系 + * + * @param bo 设备绑定关系 + * @return 是否修改成功 + */ + Boolean updateByBo(AppDeviceBindRecordBo bo); + + /** + * 校验并批量删除设备绑定关系信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/impl/AppDeviceBindRecordServiceImpl.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/impl/AppDeviceBindRecordServiceImpl.java new file mode 100644 index 00000000..59c9fd9a --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/service/impl/AppDeviceBindRecordServiceImpl.java @@ -0,0 +1,133 @@ +package com.fuyuanshen.app.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.springframework.stereotype.Service; +import com.fuyuanshen.app.domain.bo.AppDeviceBindRecordBo; +import com.fuyuanshen.app.domain.vo.AppDeviceBindRecordVo; +import com.fuyuanshen.app.domain.AppDeviceBindRecord; +import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper; +import com.fuyuanshen.app.service.IAppDeviceBindRecordService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 设备绑定关系Service业务层处理 + * + * @author Lion Li + * @date 2025-07-28 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class AppDeviceBindRecordServiceImpl implements IAppDeviceBindRecordService { + + private final AppDeviceBindRecordMapper baseMapper; + + /** + * 查询设备绑定关系 + * + * @param id 主键 + * @return 设备绑定关系 + */ + @Override + public AppDeviceBindRecordVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询设备绑定关系列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 设备绑定关系分页列表 + */ + @Override + public TableDataInfo queryPageList(AppDeviceBindRecordBo 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(AppDeviceBindRecordBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(AppDeviceBindRecordBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(AppDeviceBindRecord::getId); + lqw.eq(bo.getDeviceId() != null, AppDeviceBindRecord::getDeviceId, bo.getDeviceId()); + lqw.eq(bo.getBindingUserId() != null, AppDeviceBindRecord::getBindingUserId, bo.getBindingUserId()); + lqw.eq(bo.getBindingTime() != null, AppDeviceBindRecord::getBindingTime, bo.getBindingTime()); + return lqw; + } + + /** + * 新增设备绑定关系 + * + * @param bo 设备绑定关系 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(AppDeviceBindRecordBo bo) { + AppDeviceBindRecord add = MapstructUtils.convert(bo, AppDeviceBindRecord.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改设备绑定关系 + * + * @param bo 设备绑定关系 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(AppDeviceBindRecordBo bo) { + AppDeviceBindRecord update = MapstructUtils.convert(bo, AppDeviceBindRecord.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(AppDeviceBindRecord 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-app/src/main/resources/mapper/app/AppDeviceBindRecordMapper.xml b/fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceBindRecordMapper.xml new file mode 100644 index 00000000..a523cece --- /dev/null +++ b/fys-modules/fys-app/src/main/resources/mapper/app/AppDeviceBindRecordMapper.xml @@ -0,0 +1,7 @@ + + + + + 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 9a683adb..e54ae783 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 @@ -151,7 +151,8 @@ d.binding_time from device d inner join device_type dt on d.device_type = dt.id - where d.binding_user_id = #{criteria.bindingUserId} + inner join app_device_bind_record c on d.id = c.device_id + where c.binding_user_id = #{criteria.bindingUserId} and d.device_type = #{criteria.deviceType} From 2cb4f5b83ea720e6e8054fccc19b624c253a4e0e Mon Sep 17 00:00:00 2001 From: chenyouting <514333061@qq.com> Date: Fri, 1 Aug 2025 09:07:27 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=BB=91=E5=AE=9A?= =?UTF-8?q?=E4=BC=98=E5=8C=962?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java index 5abebed0..40698ce0 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/AppDeviceBindRecord.java @@ -1,5 +1,7 @@ package com.fuyuanshen.app.domain; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import com.fuyuanshen.common.tenant.core.TenantEntity; import lombok.Data; import lombok.EqualsAndHashCode; From 4271085e7833adfc1e711a9f8a92835c816d5663 Mon Sep 17 00:00:00 2001 From: chenyouting <514333061@qq.com> Date: Fri, 1 Aug 2025 09:58:33 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=B3=A8=E9=94=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/controller/AppAuthController.java | 9 +- .../app/domain/dto/DeviceInstructDto.java | 2 +- .../app/service/AppDeviceBizService.java | 153 +++++++++++++++++- .../app/service/AppLoginService.java | 28 +++- 4 files changed, 178 insertions(+), 14 deletions(-) diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java index 521b3aec..884690a0 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java @@ -92,7 +92,14 @@ public class AppAuthController { } - + /** + * 用户注销 + */ + @DeleteMapping("/cancelAccount") + public R cancelAccount() { + loginService.cancelAccount(); + return R.ok("用户注销成功"); + } /** * 退出登录 diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java index f176699b..074bed33 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java @@ -11,6 +11,6 @@ public class DeviceInstructDto { /** * 下发指令 */ - private Object instructValue; + private String instructValue; } 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 index 00fa94ae..024f63b8 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppDeviceBizService.java @@ -9,6 +9,8 @@ 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; @@ -16,10 +18,13 @@ import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper; import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper; import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.ImageToCArrayConverter; import com.fuyuanshen.common.core.utils.MapstructUtils; 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.DeviceType; @@ -32,16 +37,18 @@ 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.system.mqtt.config.MqttGateway; -import com.fuyuanshen.system.mqtt.constants.MqttConstants; +import com.fuyuanshen.global.mqtt.config.MqttGateway; +import com.fuyuanshen.global.mqtt.constants.MqttConstants; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +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.ImageToCArrayConverter.convertHexToDecimal; @Slf4j @@ -283,5 +290,139 @@ public class AppDeviceBizService { } + 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); + System.out.println("长度:" + largeData.length); + + System.out.println("原始数据大小: " + largeData.length + " 字节"); + + int[] ints = convertHexToDecimal(largeData); + RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+"app_logo_data:" + device.getDeviceImei(), Arrays.toString(ints), Duration.ofSeconds(30 * 60L)); + + String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+"app_logo_data:" + device.getDeviceImei()); + + byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data); + byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512); + System.out.println("第0块数据大小: " + specificChunk.length + " 字节"); + System.out.println("第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()); + } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppLoginService.java b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppLoginService.java index a9aa5665..23b8d5b1 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AppLoginService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/service/AppLoginService.java @@ -28,10 +28,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.time.Duration; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; +import java.util.*; import java.util.function.Supplier; /** @@ -51,7 +48,7 @@ public class AppLoginService { private Integer lockTime; private final ISysTenantService tenantService; - private final IAppRoleService roleService; + private final IAppUserService appUserService; /** @@ -184,5 +181,24 @@ public class AppLoginService { throw new TenantException("tenant.expired"); } } - + public void cancelAccount() { + try { + AppLoginUser loginUser = AppLoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return; + } + appUserService.deleteWithValidByIds(Collections.singletonList(loginUser.getUserId()),true); + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 登出清除动态租户 + TenantHelper.clearDynamic(); + } + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, "用户注销成功"); + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } + } + } } From 6626a1a35e7b3741e453ff00dbd756f58250a856 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Mon, 4 Aug 2025 09:05:10 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/enums/InstructType6170.java | 50 ++++ .../mqtt/DeviceReceiverMessageHandler.java | 264 ++++++++++++++++++ .../equipment/domain/bo/DeviceLogBo.java | 9 +- .../service/impl/DeviceLogServiceImpl.java | 38 ++- .../utils/c/DotMatrixDisplaySimulator.java | 204 ++++++++++++++ .../equipment/utils/c/TextToDotMatrix.java | 185 ++++++++++++ 6 files changed, 741 insertions(+), 9 deletions(-) create mode 100644 fys-admin/src/main/java/com/fuyuanshen/web/enums/InstructType6170.java create mode 100644 fys-admin/src/main/java/com/fuyuanshen/web/handler/mqtt/DeviceReceiverMessageHandler.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/DotMatrixDisplaySimulator.java create mode 100644 fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/TextToDotMatrix.java diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/enums/InstructType6170.java b/fys-admin/src/main/java/com/fuyuanshen/web/enums/InstructType6170.java new file mode 100644 index 00000000..9f5f0d90 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/enums/InstructType6170.java @@ -0,0 +1,50 @@ +package com.fuyuanshen.web.enums; + +/** + * @author: 默苍璃 + * @date: 2025-08-0114:14 + */ +public enum InstructType6170 { + + EQUIPMENT_REPORTING(0, "设备启动"), + LIGHT_MODE(1, "灯光模式"), + /** + * 设备信息 + * 单位/姓名/职位 + */ + UNIT_INFO(2, "设备信息"), + BOOT_IMAGE(3, "开机图片"), + LASER_LIGHT(4, "激光灯"), + BRIGHTNESS(5, "亮度调节"), + LOCATION_DATA(11, "定位数据"), + + + UNKNOWN(-1, "未知操作"); + + private final int code; + private final String description; + + InstructType6170(int code, String description) { + this.code = code; + this.description = description; + } + + public int getCode() { + return code; + } + + public String getDescription() { + return description; + } + + public static InstructType6170 fromCode(int code) { + for (InstructType6170 type : values()) { + if (type.getCode() == code) { + return type; + } + } + // throw new IllegalArgumentException("未知的指令类型代码: " + code); + return UNKNOWN; + } + +} 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 new file mode 100644 index 00000000..2f31fc37 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/handler/mqtt/DeviceReceiverMessageHandler.java @@ -0,0 +1,264 @@ +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.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.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 payload = message.getPayload().toString(); + + if (receivedTopicName != null) { + // 1. 提取设备ID (从主题中获取) + String deviceImei = extractDeviceId(receivedTopicName); + Device device = deviceMapper.selectOne(new QueryWrapper().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("客户端操作"); + } + } + deviceLogMapper.insert(record); + } + + if (root.has("imei")) { + // 设备行为 + record.setDeviceAction(InstructType6170.fromCode(0).getDescription()); + record.setDataSource("设备上报"); + record.setContent("设备启动"); + 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 StateRecord parseState(Device device, JsonNode array) { + // StateRecord record = new StateRecord(); + // record.setDevice(device); + // record.setStateType(array.get(0).asInt()); + // + // switch (record.getStateType()) { + // case 1: // 灯光状态 + // record.setLightMode(array.get(1).asInt()); + // record.setBrightness(array.get(2).asInt()); + // break; + // + // case 2: // 设置结果 + // record.setSetResult(array.get(1).asInt() == 1); + // break; + // + // case 3: // 图片更新状态 + // record.setImagePage(array.get(1).asInt()); + // break; + // + // case 4: // 激光灯状态 + // record.setLaserStatus(array.get(1).asInt() == 1); + // break; + // + // case 5: // 亮度状态 + // record.setBrightness(array.get(1).asInt()); + // break; + // + // case 11: // 定位上报 + // record.setLatitude(array.get(1).asDouble()); + // record.setLongitude(array.get(2).asDouble()); + // break; + // + // case 12: // 设备状态 + // record.setMainLightGear(array.get(1).asInt()); + // record.setLaserLightGear(array.get(2).asInt()); + // record.setBattery(array.get(3).asInt()); + // record.setChargeStatus(array.get(4).asInt()); + // record.setDuration(array.get(5).asInt()); + // break; + // } + // return record; + // } + + +} diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceLogBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceLogBo.java index 71900d58..2ac1f662 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceLogBo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceLogBo.java @@ -8,6 +8,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import jakarta.validation.constraints.*; +import java.util.List; + /** * 设备日志业务对象 device_log * @@ -22,9 +24,14 @@ public class DeviceLogBo extends BaseEntity { /** * ID */ - @NotNull(message = "ID不能为空", groups = { EditGroup.class }) + @NotNull(message = "ID不能为空", groups = {EditGroup.class}) private Long id; + /** + * 设备编号 + */ + private List deviceIds; + /** * 设备行为 */ diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceLogServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceLogServiceImpl.java index 60d46df5..16ca6d3d 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceLogServiceImpl.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceLogServiceImpl.java @@ -1,11 +1,16 @@ package com.fuyuanshen.equipment.service.impl; +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 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 com.fuyuanshen.common.satoken.utils.LoginHelper; +import com.fuyuanshen.equipment.domain.DeviceAssignments; +import com.fuyuanshen.equipment.mapper.DeviceAssignmentsMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -19,6 +24,7 @@ import com.fuyuanshen.equipment.service.IDeviceLogService; import java.util.List; import java.util.Map; import java.util.Collection; +import java.util.stream.Collectors; /** * 设备日志Service业务层处理 @@ -33,6 +39,9 @@ public class DeviceLogServiceImpl implements IDeviceLogService { private final DeviceLogMapper baseMapper; + private final DeviceAssignmentsMapper deviceAssignmentsMapper; + + /** * 查询设备日志 * @@ -40,7 +49,7 @@ public class DeviceLogServiceImpl implements IDeviceLogService { * @return 设备日志 */ @Override - public DeviceLogVo queryById(Long id){ + public DeviceLogVo queryById(Long id) { return baseMapper.selectVoById(id); } @@ -53,6 +62,8 @@ public class DeviceLogServiceImpl implements IDeviceLogService { */ @Override public TableDataInfo queryPageList(DeviceLogBo bo, PageQuery pageQuery) { + + LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); return TableDataInfo.build(result); @@ -71,16 +82,27 @@ public class DeviceLogServiceImpl implements IDeviceLogService { } private LambdaQueryWrapper buildQueryWrapper(DeviceLogBo bo) { + + Long userId = LoginHelper.getUserId(); + List assignments = deviceAssignmentsMapper.selectList(new QueryWrapper().eq("assignee_id", userId)); + List deviceIds = assignments.stream().map(DeviceAssignments::getDeviceId).collect(Collectors.toList()); + if (deviceIds.isEmpty()) { + deviceIds.add(-1L); + } + bo.setDeviceIds(deviceIds); + Map params = bo.getParams(); LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.orderByAsc(DeviceLog::getId); - lqw.eq(StringUtils.isNotBlank(bo.getDeviceAction()), DeviceLog::getDeviceAction, bo.getDeviceAction()); + lqw.orderByDesc(DeviceLog::getCreateTime); + lqw.like(StringUtils.isNotBlank(bo.getDeviceAction()), DeviceLog::getDeviceAction, bo.getDeviceAction()); lqw.like(StringUtils.isNotBlank(bo.getDeviceName()), DeviceLog::getDeviceName, bo.getDeviceName()); lqw.eq(StringUtils.isNotBlank(bo.getDataSource()), DeviceLog::getDataSource, bo.getDataSource()); - lqw.eq(StringUtils.isNotBlank(bo.getContent()), DeviceLog::getContent, bo.getContent()); + lqw.like(StringUtils.isNotBlank(bo.getContent()), DeviceLog::getContent, bo.getContent()); + lqw.in(CollectionUtil.isNotEmpty(bo.getDeviceIds()), DeviceLog::getDeviceId, bo.getDeviceIds()); return lqw; } + /** * 新增设备日志 * @@ -114,8 +136,8 @@ public class DeviceLogServiceImpl implements IDeviceLogService { /** * 保存前的数据校验 */ - private void validEntityBeforeSave(DeviceLog entity){ - //TODO 做一些数据校验,如唯一约束 + private void validEntityBeforeSave(DeviceLog entity) { + // TODO 做一些数据校验,如唯一约束 } /** @@ -127,8 +149,8 @@ public class DeviceLogServiceImpl implements IDeviceLogService { */ @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { - if(isValid){ - //TODO 做一些业务上的校验,判断是否需要校验 + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 } return baseMapper.deleteByIds(ids) > 0; } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/DotMatrixDisplaySimulator.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/DotMatrixDisplaySimulator.java new file mode 100644 index 00000000..3d022fea --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/DotMatrixDisplaySimulator.java @@ -0,0 +1,204 @@ +package com.fuyuanshen.equipment.utils.c; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.util.Arrays; + +public class DotMatrixDisplaySimulator extends JFrame { + + private static final int WIDTH = 160; + private static final int HEIGHT = 80; + private static final int SCALE = 4; // 显示缩放比例 + + private JComboBox fontSizeCombo; + private JComboBox exampleCombo; + private JTextArea textInput; + private DotMatrixPanel displayPanel; + + private final String[] examples = { + "紧急通知:现场危险,请立即撤离!", + "警告:高温区域,禁止入内!", + "系统故障:请立即联系技术人员处理", + "安全提示:请佩戴防护装备进入作业区", + "欢迎使用点阵显示屏模拟系统", + "现场危险,停止救援,紧急撤离至安全区域!" + }; + + public DotMatrixDisplaySimulator() { + super("160x80点阵显示屏模拟器"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(800, 600); + setLayout(new BorderLayout()); + + // 创建控制面板 + JPanel controlPanel = new JPanel(new GridLayout(1, 4, 10, 10)); + controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + // 字体大小选择 + controlPanel.add(new JLabel("字体大小:")); + fontSizeCombo = new JComboBox<>(new Integer[]{8, 10, 12, 14, 16, 18, 20, 24}); + fontSizeCombo.setSelectedItem(14); + controlPanel.add(fontSizeCombo); + + // 示例选择 + controlPanel.add(new JLabel("示例文本:")); + exampleCombo = new JComboBox<>(examples); + exampleCombo.addActionListener(e -> textInput.setText(examples[exampleCombo.getSelectedIndex()])); + controlPanel.add(exampleCombo); + + // 文本输入 + textInput = new JTextArea(examples[0]); + textInput.setLineWrap(true); + textInput.setWrapStyleWord(true); + JScrollPane textScroll = new JScrollPane(textInput); + textScroll.setBorder(BorderFactory.createTitledBorder("输入文本")); + + // 点阵显示面板 + displayPanel = new DotMatrixPanel(); + + // 添加组件 + add(controlPanel, BorderLayout.NORTH); + add(textScroll, BorderLayout.CENTER); + add(displayPanel, BorderLayout.SOUTH); + + // 添加事件监听器 + fontSizeCombo.addActionListener(e -> displayPanel.repaint()); + textInput.getDocument().addDocumentListener(new javax.swing.event.DocumentListener() { + public void changedUpdate(javax.swing.event.DocumentEvent e) { update(); } + public void removeUpdate(javax.swing.event.DocumentEvent e) { update(); } + public void insertUpdate(javax.swing.event.DocumentEvent e) { update(); } + private void update() { + displayPanel.repaint(); + } + }); + + setLocationRelativeTo(null); + } + + class DotMatrixPanel extends JPanel { + private final int panelWidth = WIDTH * SCALE; + private final int panelHeight = HEIGHT * SCALE; + + public DotMatrixPanel() { + setPreferredSize(new Dimension(panelWidth, panelHeight + 50)); + setBorder(BorderFactory.createTitledBorder("点阵预览 (160x80)")); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + // 绘制点阵背景 + g.setColor(Color.WHITE); + g.fillRect(0, 0, panelWidth, panelHeight); + + // 绘制网格 + g.setColor(new Color(240, 240, 240)); + for (int x = 0; x <= WIDTH; x++) { + int xPos = x * SCALE; + g.drawLine(xPos, 0, xPos, panelHeight); + } + for (int y = 0; y <= HEIGHT; y++) { + int yPos = y * SCALE; + g.drawLine(0, yPos, panelWidth, yPos); + } + + // 绘制文本 + String text = textInput.getText(); + int fontSize = (Integer) fontSizeCombo.getSelectedItem(); + Font font = new Font("黑体", Font.PLAIN, fontSize); + + // 创建虚拟点阵图像 + BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_BYTE_BINARY); + Graphics2D imgG = img.createGraphics(); + imgG.setColor(Color.WHITE); + imgG.fillRect(0, 0, WIDTH, HEIGHT); + imgG.setColor(Color.BLACK); + imgG.setFont(font); + imgG.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // 绘制文本到虚拟点阵 + FontMetrics metrics = imgG.getFontMetrics(); + int lineHeight = metrics.getHeight(); + int yPos = metrics.getAscent(); + String[] lines = text.split("\n"); + + int maxLines = HEIGHT / lineHeight; + int actualLines = Math.min(lines.length, maxLines); + int totalChars = 0; + + for (int i = 0; i < actualLines; i++) { + String line = lines[i]; + int lineWidth = metrics.stringWidth(line); + int maxChars = WIDTH / metrics.stringWidth("字"); // 估算每行字数 + + // 截断超过宽度的文本 + if (lineWidth > WIDTH) { + while (metrics.stringWidth(line) > WIDTH) { + line = line.substring(0, line.length() - 1); + } + line += "..."; + } + + // 居中显示文本 + int xPos = (WIDTH - metrics.stringWidth(line)) / 2; + imgG.drawString(line, xPos, yPos); + + totalChars += line.length(); + yPos += lineHeight; + + if (yPos + lineHeight > HEIGHT) break; + } + imgG.dispose(); + + // 绘制到预览面板 + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + int rgb = img.getRGB(x, y) & 0xFFFFFF; + if (rgb != 0xFFFFFF) { // 黑色像素 + g.setColor(Color.BLACK); + g.fillRect(x * SCALE, y * SCALE, SCALE, SCALE); + } + } + } + + // 显示统计信息 + g.setColor(Color.BLACK); + g.setFont(new Font("宋体", Font.PLAIN, 12)); + String info = String.format("字体大小: %dpt | 显示行数: %d/%d | 显示字数: %d", + fontSize, actualLines, maxLines, totalChars); + g.drawString(info, 10, panelHeight + 20); + + String capacity = String.format("容量分析: %d×80点阵可显示%d-%d个汉字(%dpt字体)", + WIDTH, + (int)(WIDTH*HEIGHT/(fontSize*fontSize*1.2)), + (int)(WIDTH*HEIGHT/(fontSize*fontSize*0.8)), + fontSize); + g.drawString(capacity, 10, panelHeight + 35); + } + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + DotMatrixDisplaySimulator frame = new DotMatrixDisplaySimulator(); + frame.setVisible(true); + + // 显示使用提示 + String message = "
160×80点阵显示屏文字容量分析

" + + "• 使用上方下拉菜单选择字体大小和示例文本
" + + "• 在文本区域输入自定义内容
" + + "• 点阵预览区域实时显示效果

" + + "容量参考:
" + + "8-9pt:约20字/行 × 10行 = 200字
" + + "10-11pt:约16字/行 × 8行 = 128字
" + + "12-13pt:约13字/行 × 6行 = 78字
" + + "14-15pt:约11字/行 × 5行 = 55字
" + + "16-18pt:约9字/行 × 4行 = 36字
" + + "20-24pt:约7字/行 × 3行 = 21字
"; + + JOptionPane.showMessageDialog(frame, message, "使用说明", JOptionPane.INFORMATION_MESSAGE); + }); + } +} \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/TextToDotMatrix.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/TextToDotMatrix.java new file mode 100644 index 00000000..d594deb8 --- /dev/null +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/c/TextToDotMatrix.java @@ -0,0 +1,185 @@ +package com.fuyuanshen.equipment.utils.c; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class TextToDotMatrix { + + public static void main(String[] args) { + String text = "现场危险,停止救援,\n紧急撤离至安全区域!"; + int width = 160; // 点阵宽度 + int height = 80; // 点阵高度 + + try { + // 1. 创建点阵图片 + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); + Graphics2D g = image.createGraphics(); + + // 设置背景为白色 + g.setColor(Color.WHITE); + g.fillRect(0, 0, width, height); + + // 设置字体并居中显示文本 + g.setColor(Color.BLACK); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // 自动调整字体大小以适应区域 + Font font = findBestFitFont(text, width, height, g); + g.setFont(font); + + // 计算文本位置并绘制 + drawCenteredText(g, text, width, height); + g.dispose(); + + // 2. 生成二进制数组 + List byteList = new ArrayList<>(); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x += 8) { + byte b = 0; + for (int bit = 0; bit < 8; bit++) { + int xPos = x + bit; + if (xPos < width) { + int rgb = image.getRGB(xPos, y) & 0xFFFFFF; + if (rgb != 0xFFFFFF) { // 黑色像素 + b |= (1 << (7 - bit)); + } + } + } + byteList.add(b); + } + } + + // 转换为字节数组 + byte[] dotMatrixData = new byte[byteList.size()]; + for (int i = 0; i < byteList.size(); i++) { + dotMatrixData[i] = byteList.get(i); + } + + // 3. 保存预览图片 + ImageIO.write(image, "png", new File("warning_display.png")); + System.out.println("预览图片已生成: warning_display.png"); + + // 4. 打印点阵数据信息 + System.out.println("\n点阵数据信息:"); + System.out.println("尺寸: " + width + "x" + height + " 像素"); + System.out.println("数据大小: " + dotMatrixData.length + " 字节"); + System.out.println("每行字节数: " + (width / 8)); + System.out.println("总行数: " + height); + + // 5. 打印二进制数组(十六进制格式) + System.out.println("\n点阵数据字节数组 (HEX):"); + System.out.print("byte[] dotMatrixData = {"); + for (int i = 0; i < dotMatrixData.length; i++) { + System.out.printf("0x%02X", dotMatrixData[i] & 0xFF); + if (i < dotMatrixData.length - 1) System.out.print(", "); + if (i % 16 == 15) System.out.println(); + } + System.out.println("};\n"); + + // 6. 打印点阵图预览 + System.out.println("点阵图预览 (缩小版):"); + printTextPreview(image); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + // 自动寻找最佳字体大小 + private static Font findBestFitFont(String text, int width, int height, Graphics2D g) { + int fontSize = 20; // 初始字体大小 + Font bestFont = null; + int bestHeight = 0; + + while (fontSize > 8) { + Font font = new Font("黑体", Font.BOLD, fontSize); + g.setFont(font); + FontMetrics metrics = g.getFontMetrics(); + + // 计算文本所需高度 + String[] lines = text.split("\n"); + int textHeight = metrics.getHeight() * lines.length; + + // 检查是否超出高度 + if (textHeight < height * 0.8) { + bestFont = font; + bestHeight = textHeight; + break; + } + fontSize--; + } + + // 如果没有找到合适字体,使用最小字体 + if (bestFont == null) { + bestFont = new Font("黑体", Font.BOLD, 8); + } + + System.out.println("使用字体: " + bestFont.getSize() + "pt"); + return bestFont; + } + + // 居中绘制文本 + private static void drawCenteredText(Graphics g, String text, int width, int height) { + FontMetrics metrics = g.getFontMetrics(); + String[] lines = text.split("\n"); + + // 计算总文本高度 + int totalHeight = metrics.getHeight() * lines.length; + + // 计算起始Y位置 + int y = (height - totalHeight) / 2 + metrics.getAscent(); + + for (String line : lines) { + // 计算X位置使文本居中 + int x = (width - metrics.stringWidth(line)) / 2; + g.drawString(line, x, y); + y += metrics.getHeight(); + } + } + + // 打印文本预览 + private static void printTextPreview(BufferedImage image) { + int width = image.getWidth(); + int height = image.getHeight(); + + // 缩小预览比例 + int scale = 4; + int previewWidth = width / scale; + int previewHeight = height / scale; + + for (int y = 0; y < previewHeight; y++) { + for (int x = 0; x < previewWidth; x++) { + int pixelCount = 0; + for (int dy = 0; dy < scale; dy++) { + for (int dx = 0; dx < scale; dx++) { + int origX = x * scale + dx; + int origY = y * scale + dy; + if (origX < width && origY < height) { + int rgb = image.getRGB(origX, origY) & 0xFFFFFF; + if (rgb != 0xFFFFFF) { // 黑色像素 + pixelCount++; + } + } + } + } + + // 根据黑色像素密度选择字符 + if (pixelCount > scale * scale * 0.7) { + System.out.print("██"); + } else if (pixelCount > scale * scale * 0.4) { + System.out.print("▓▓"); + } else if (pixelCount > scale * scale * 0.1) { + System.out.print("░░"); + } else { + System.out.print(" "); + } + } + System.out.println(); + } + } +} \ No newline at end of file From 38caba1fad5aef660b27b6579fba326e4ca8aa89 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Sat, 2 Aug 2025 09:18:31 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=8A=B6=E6=80=81-=E5=BC=BA=E5=88=B6=E4=B8=8B=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CustomMqttInboundConfiguration.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 fys-admin/src/main/java/com/fuyuanshen/web/config/CustomMqttInboundConfiguration.java 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 new file mode 100644 index 00000000..faa8cb59 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/config/CustomMqttInboundConfiguration.java @@ -0,0 +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; + } + +} From ae393e8155463e867ee98d5e83020feed6ea1531 Mon Sep 17 00:00:00 2001 From: daiyongfei <974332738@qq.com> Date: Thu, 31 Jul 2025 10:27:02 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/DeviceTypeServiceImpl.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceTypeServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceTypeServiceImpl.java index fcc373e9..6d06c198 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceTypeServiceImpl.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceTypeServiceImpl.java @@ -107,6 +107,13 @@ public class DeviceTypeServiceImpl extends ServiceImpl typeName = deviceTypeMapper.selectList(new QueryWrapper().eq("type_name", resources.getTypeName())); + if (CollectionUtil.isNotEmpty(typeName)) { + throw new RuntimeException("设备类型名称已存在,无法新增!!!"); + } + LoginUser loginUser = LoginHelper.getLoginUser(); resources.setCustomerId(loginUser.getUserId()); resources.setOwnerCustomerId(loginUser.getUserId()); @@ -141,11 +148,23 @@ public class DeviceTypeServiceImpl extends ServiceImpl devices = deviceMapper.selectList(new QueryWrapper() + .eq("device_type", deviceTypeGrants.getDeviceTypeId())); + if (CollectionUtil.isNotEmpty(devices)) { + throw new RuntimeException("该设备类型已绑定设备,无法修改!!!"); + } + + // 校验设备类型名称 + DeviceType dt = deviceTypeMapper.selectOne(new QueryWrapper().eq("type_name", resources.getTypeName())); + if (dt != null && !dt.getId().equals(deviceType.getId())) { + throw new RuntimeException("设备类型名称已存在,无法修改!!!"); + } + if (!Objects.equals(deviceType.getCustomerId(), LoginHelper.getUserId())) { throw new RuntimeException("无权修改该设备类型"); } - // if (deviceMapper.countByTypeId(resources.getId()) > 0) - // throw new RuntimeException("该设备类型已被使用,无法删除"); + BeanUtil.copyProperties(resources, deviceType); deviceTypeMapper.updateById(deviceType); }