forked from dyf/fys-Multi-tenant
Compare commits
6 Commits
4663a5560f
...
a8c9c631ad
Author | SHA1 | Date | |
---|---|---|---|
a8c9c631ad | |||
8a7565459b | |||
0bbac2b497 | |||
364574eeae | |||
f9d9dadf08 | |||
e4df695f5e |
@ -15,8 +15,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import java.time.Duration;
|
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_KEY;
|
||||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
|
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
|
||||||
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 灯光模式订阅设备回传消息
|
* 灯光模式订阅设备回传消息
|
||||||
@ -37,14 +36,10 @@ public class BjqLaserModeSettingsRule implements MqttMessageRule {
|
|||||||
try {
|
try {
|
||||||
Object[] convertArr = context.getConvertArr();
|
Object[] convertArr = context.getConvertArr();
|
||||||
|
|
||||||
String mainLightMode = convertArr[1].toString();
|
String mode = convertArr[1].toString();
|
||||||
if(StringUtils.isNotBlank(mainLightMode)){
|
if(StringUtils.isNotBlank(mode)){
|
||||||
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
|
// 发送设备状态和位置信息到Redis
|
||||||
syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mainLightMode);
|
syncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(30));
|
||||||
@ -65,7 +60,7 @@ public class BjqLaserModeSettingsRule implements MqttMessageRule {
|
|||||||
// });
|
// });
|
||||||
try {
|
try {
|
||||||
// 将设备状态信息存储到Redis中
|
// 将设备状态信息存储到Redis中
|
||||||
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_LIGHT_MODE_KEY_PREFIX;
|
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + deviceImei + DEVICE_LASER_MODE_KEY_PREFIX;
|
||||||
|
|
||||||
// 存储到Redis
|
// 存储到Redis
|
||||||
RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString());
|
RedisUtils.setCacheObject(deviceRedisKey, convertValue.toString());
|
||||||
|
@ -8,19 +8,17 @@ import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
|||||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||||
import com.fuyuanshen.common.web.core.BaseController;
|
import com.fuyuanshen.common.web.core.BaseController;
|
||||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
|
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
|
||||||
|
import com.fuyuanshen.equipment.domain.dto.InstructionRecordDto;
|
||||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
||||||
|
import com.fuyuanshen.equipment.domain.vo.InstructionRecordVo;
|
||||||
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||||
import com.fuyuanshen.web.service.device.DeviceBizService;
|
import com.fuyuanshen.web.service.device.DeviceBizService;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -30,7 +28,7 @@ import java.util.Map;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/api/device/controlCenter")
|
@RequestMapping("/api/device")
|
||||||
public class DeviceControlCenterController extends BaseController {
|
public class DeviceControlCenterController extends BaseController {
|
||||||
|
|
||||||
private final DeviceBizService appDeviceService;
|
private final DeviceBizService appDeviceService;
|
||||||
@ -95,4 +93,12 @@ public class DeviceControlCenterController extends BaseController {
|
|||||||
return R.ok(appDeviceService.getDeviceInfo(deviceMac));
|
return R.ok(appDeviceService.getDeviceInfo(deviceMac));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指令下发记录
|
||||||
|
*/
|
||||||
|
@GetMapping("/instructionRecord")
|
||||||
|
public TableDataInfo<InstructionRecordVo> getInstructionRecord(InstructionRecordDto dto, PageQuery pageQuery) {
|
||||||
|
return appDeviceService.getInstructionRecord(dto,pageQuery);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -114,4 +114,21 @@ public class DeviceGroupController extends BaseController {
|
|||||||
return toAjax(deviceGroupService.deleteWithValidByIds(List.of(ids), true));
|
return toAjax(deviceGroupService.deleteWithValidByIds(List.of(ids), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定设备分组
|
||||||
|
*
|
||||||
|
* @param groupId 分组id
|
||||||
|
* @param deviceId 设备id
|
||||||
|
*/
|
||||||
|
@Operation(summary = "绑定设备分组")
|
||||||
|
// @SaCheckPermission("fys-equipment:group:remove")
|
||||||
|
@Log(title = "绑定设备分组", businessType = BusinessType.DELETE)
|
||||||
|
@GetMapping("/groupId/{deviceId}")
|
||||||
|
public R<Void> bindingDevice(@NotEmpty(message = "分组id 不能为空") @PathVariable Long groupId,
|
||||||
|
@NotEmpty(message = "设备id 不能为空") @PathVariable Long[] deviceId) {
|
||||||
|
return toAjax(deviceGroupService.bindingDevice(groupId, deviceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,18 @@
|
|||||||
package com.fuyuanshen.web.controller.device;
|
package com.fuyuanshen.web.controller.device;
|
||||||
|
|
||||||
|
|
||||||
import com.fuyuanshen.app.domain.dto.APPReNameDTO;
|
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
||||||
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.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.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.equipment.domain.vo.WebDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||||
import com.fuyuanshen.web.service.WEBDeviceService;
|
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.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description:
|
* @Description:
|
||||||
@ -68,6 +57,20 @@ public class WEBDeviceController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备用户详情
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Operation(summary = "设备详情")
|
||||||
|
@GetMapping(value = "/getDeviceUser/{id}")
|
||||||
|
public R<List<AppPersonnelInfoRecords>> getDeviceUser(@PathVariable Long id) {
|
||||||
|
List<AppPersonnelInfoRecords> device = deviceService.getDeviceUser(id);
|
||||||
|
return R.ok(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.fuyuanshen.web.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
||||||
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
import com.fuyuanshen.common.mybatis.core.page.PageQuery;
|
||||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||||
import com.fuyuanshen.equipment.domain.Device;
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
@ -38,4 +39,12 @@ public interface WEBDeviceService extends IService<Device> {
|
|||||||
*/
|
*/
|
||||||
WebDeviceVo getDevice(Long id);
|
WebDeviceVo getDevice(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备用户详情
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<AppPersonnelInfoRecords> getDeviceUser(Long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -190,6 +190,22 @@ public class DeviceBJQBizService {
|
|||||||
vo.setBatteryPercentage("0");
|
vo.setBatteryPercentage("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String lightModeStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX);
|
||||||
|
// 获取电量
|
||||||
|
if(StringUtils.isNotBlank(deviceStatus)){
|
||||||
|
vo.setMainLightMode(lightModeStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
String lightBrightnessStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX);
|
||||||
|
if(StringUtils.isNotBlank(lightBrightnessStatus)){
|
||||||
|
vo.setLightBrightness(lightBrightnessStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
String laserLightMode = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LASER_MODE_KEY_PREFIX);
|
||||||
|
if(StringUtils.isNotBlank(laserLightMode)){
|
||||||
|
vo.setLaserLightMode(laserLightMode);
|
||||||
|
}
|
||||||
|
|
||||||
// 获取经度纬度
|
// 获取经度纬度
|
||||||
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
|
String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX;
|
||||||
String locationInfo = RedisUtils.getCacheObject(locationKey);
|
String locationInfo = RedisUtils.getCacheObject(locationKey);
|
||||||
|
@ -14,7 +14,6 @@ import com.fuyuanshen.app.domain.vo.APPDeviceTypeVo;
|
|||||||
import com.fuyuanshen.app.domain.vo.AppUserVo;
|
import com.fuyuanshen.app.domain.vo.AppUserVo;
|
||||||
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
|
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
|
||||||
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
||||||
import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper;
|
|
||||||
import com.fuyuanshen.app.mapper.AppUserMapper;
|
import com.fuyuanshen.app.mapper.AppUserMapper;
|
||||||
import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper;
|
import com.fuyuanshen.app.mapper.equipment.APPDeviceMapper;
|
||||||
import com.fuyuanshen.common.core.exception.ServiceException;
|
import com.fuyuanshen.common.core.exception.ServiceException;
|
||||||
@ -26,15 +25,15 @@ import com.fuyuanshen.common.redis.utils.RedisUtils;
|
|||||||
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
|
||||||
import com.fuyuanshen.equipment.domain.Device;
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
|
import com.fuyuanshen.equipment.domain.dto.AppDeviceBo;
|
||||||
|
import com.fuyuanshen.equipment.domain.dto.InstructionRecordDto;
|
||||||
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
|
||||||
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.AppDeviceVo;
|
||||||
|
import com.fuyuanshen.equipment.domain.vo.InstructionRecordVo;
|
||||||
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||||
import com.fuyuanshen.equipment.enums.BindingStatusEnum;
|
import com.fuyuanshen.equipment.enums.BindingStatusEnum;
|
||||||
import com.fuyuanshen.equipment.enums.CommunicationModeEnum;
|
import com.fuyuanshen.equipment.enums.CommunicationModeEnum;
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
import com.fuyuanshen.equipment.mapper.DeviceLogMapper;
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||||
import com.fuyuanshen.equipment.mapper.DeviceTypeMapper;
|
|
||||||
import com.fuyuanshen.global.mqtt.config.MqttGateway;
|
|
||||||
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
|
||||||
import com.fuyuanshen.web.service.device.status.base.DeviceStatusRule;
|
import com.fuyuanshen.web.service.device.status.base.DeviceStatusRule;
|
||||||
import com.fuyuanshen.web.service.device.status.base.RealTimeStatusEngine;
|
import com.fuyuanshen.web.service.device.status.base.RealTimeStatusEngine;
|
||||||
@ -332,4 +331,9 @@ public class DeviceBizService {
|
|||||||
// List<Device> devices = deviceMapper.selectList(queryWrapper);
|
// List<Device> devices = deviceMapper.selectList(queryWrapper);
|
||||||
return deviceMapper.getDeviceInfo(deviceMac);
|
return deviceMapper.getDeviceInfo(deviceMac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TableDataInfo<InstructionRecordVo> getInstructionRecord(InstructionRecordDto bo, PageQuery pageQuery) {
|
||||||
|
Page<InstructionRecordVo> result = deviceLogMapper.getInstructionRecord(pageQuery.build(), bo);
|
||||||
|
return TableDataInfo.build(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,11 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.fuyuanshen.app.domain.AppDeviceBindRecord;
|
import com.fuyuanshen.app.domain.AppDeviceBindRecord;
|
||||||
import com.fuyuanshen.app.domain.AppDeviceShare;
|
import com.fuyuanshen.app.domain.AppDeviceShare;
|
||||||
|
import com.fuyuanshen.app.domain.AppPersonnelInfoRecords;
|
||||||
import com.fuyuanshen.app.domain.vo.AppDeviceShareVo;
|
import com.fuyuanshen.app.domain.vo.AppDeviceShareVo;
|
||||||
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
|
import com.fuyuanshen.app.mapper.AppDeviceBindRecordMapper;
|
||||||
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
import com.fuyuanshen.app.mapper.AppDeviceShareMapper;
|
||||||
|
import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper;
|
||||||
import com.fuyuanshen.equipment.domain.Device;
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
import com.fuyuanshen.equipment.domain.DeviceAssignments;
|
import com.fuyuanshen.equipment.domain.DeviceAssignments;
|
||||||
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
import com.fuyuanshen.equipment.domain.vo.WebDeviceVo;
|
||||||
@ -22,6 +24,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Description:
|
* @Description:
|
||||||
* @Author: WY
|
* @Author: WY
|
||||||
@ -35,6 +39,7 @@ public class WEBDeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impl
|
|||||||
private final DeviceAssignmentsMapper deviceAssignmentsMapper;
|
private final DeviceAssignmentsMapper deviceAssignmentsMapper;
|
||||||
|
|
||||||
private final AppDeviceBindRecordMapper appDeviceBindRecordMapper;
|
private final AppDeviceBindRecordMapper appDeviceBindRecordMapper;
|
||||||
|
private final AppPersonnelInfoRecordsMapper infoRecordsMapper;
|
||||||
|
|
||||||
private final DeviceMapper deviceMapper;
|
private final DeviceMapper deviceMapper;
|
||||||
private final AppDeviceShareMapper appDeviceShareMapper;
|
private final AppDeviceShareMapper appDeviceShareMapper;
|
||||||
@ -95,4 +100,19 @@ public class WEBDeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备用户详情
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<AppPersonnelInfoRecords> getDeviceUser(Long id) {
|
||||||
|
List<AppPersonnelInfoRecords> appPersonnelInfoRecords = infoRecordsMapper.selectList(
|
||||||
|
new QueryWrapper<AppPersonnelInfoRecords>().eq("device_id", id)
|
||||||
|
.orderByDesc("create_time"));
|
||||||
|
return appPersonnelInfoRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
d.device_pic,
|
d.device_pic,
|
||||||
dt.type_name,
|
dt.type_name,
|
||||||
dt.communication_mode,
|
dt.communication_mode,
|
||||||
dt.model_dictionary detailPageUrl,
|
dt.app_model_dictionary detailPageUrl,
|
||||||
d.bluetooth_name,
|
d.bluetooth_name,
|
||||||
c.binding_time,
|
c.binding_time,
|
||||||
ad.*,u.user_name otherPhonenumber
|
ad.*,u.user_name otherPhonenumber
|
||||||
@ -33,7 +33,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
dt.type_name,
|
dt.type_name,
|
||||||
dt.communication_mode,
|
dt.communication_mode,
|
||||||
d.bluetooth_name,
|
d.bluetooth_name,
|
||||||
dt.model_dictionary detailPageUrl,
|
dt.app_model_dictionary detailPageUrl,
|
||||||
c.binding_time,
|
c.binding_time,
|
||||||
ad.*,u.user_name otherPhonenumber
|
ad.*,u.user_name otherPhonenumber
|
||||||
from
|
from
|
||||||
|
@ -153,5 +153,8 @@ public class Device extends TenantEntity {
|
|||||||
*/
|
*/
|
||||||
@Schema(title = "出厂日期")
|
@Schema(title = "出厂日期")
|
||||||
private Date productionDate;
|
private Date productionDate;
|
||||||
|
/**
|
||||||
|
* 在线状态(0离线,1在线)
|
||||||
|
*/
|
||||||
|
private Integer onlineStatus;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.fuyuanshen.equipment.domain.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class InstructionRecordDto {
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
|
private String deviceType;
|
||||||
|
/**
|
||||||
|
* 设备名称
|
||||||
|
*/
|
||||||
|
private String deviceName;
|
||||||
|
/**
|
||||||
|
* 设备MAC
|
||||||
|
*/
|
||||||
|
private String deviceMac;
|
||||||
|
/**
|
||||||
|
* 设备IMEI
|
||||||
|
*/
|
||||||
|
private String deviceImei;
|
||||||
|
/**
|
||||||
|
* 操作时间-开始时间
|
||||||
|
*/
|
||||||
|
private String startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作时间-结束时间
|
||||||
|
*/
|
||||||
|
private String endTime;
|
||||||
|
}
|
@ -18,22 +18,34 @@ import java.util.Set;
|
|||||||
@Data
|
@Data
|
||||||
public class DeviceQueryCriteria extends BaseEntity {
|
public class DeviceQueryCriteria extends BaseEntity {
|
||||||
|
|
||||||
@Schema(name = "设备id")
|
/**
|
||||||
|
* 设备id
|
||||||
|
*/
|
||||||
private Long deviceId;
|
private Long deviceId;
|
||||||
|
|
||||||
@Schema(name = "设备名称")
|
/**
|
||||||
|
* 设备名称
|
||||||
|
*/
|
||||||
private String deviceName;
|
private String deviceName;
|
||||||
|
|
||||||
@Schema(name = "设备类型")
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
private Long deviceType;
|
private Long deviceType;
|
||||||
|
|
||||||
@Schema(name = "设备MAC")
|
/**
|
||||||
|
* 设备MAC
|
||||||
|
*/
|
||||||
private String deviceMac;
|
private String deviceMac;
|
||||||
|
|
||||||
@Schema(name = "设备IMEI")
|
/**
|
||||||
|
* 设备IMEI
|
||||||
|
*/
|
||||||
private String deviceImei;
|
private String deviceImei;
|
||||||
|
|
||||||
@Schema(name = "设备SN")
|
/**
|
||||||
|
* 设备SN
|
||||||
|
*/
|
||||||
private String deviceSn;
|
private String deviceSn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,26 +53,37 @@ public class DeviceQueryCriteria extends BaseEntity {
|
|||||||
* 0 失效
|
* 0 失效
|
||||||
* 1 正常
|
* 1 正常
|
||||||
*/
|
*/
|
||||||
@Schema(name = "设备状态 0 失效 1 正常 ")
|
|
||||||
private Integer deviceStatus;
|
private Integer deviceStatus;
|
||||||
|
|
||||||
@Schema(name = "页码", example = "1")
|
/**
|
||||||
|
* 页码
|
||||||
|
*/
|
||||||
private Integer pageNum = 1;
|
private Integer pageNum = 1;
|
||||||
|
|
||||||
@Schema(name = "每页数据量", example = "10")
|
/**
|
||||||
|
* 每页数据量
|
||||||
|
*/
|
||||||
private Integer pageSize = 10;
|
private Integer pageSize = 10;
|
||||||
|
|
||||||
@Schema(name = "客户id")
|
/**
|
||||||
|
* 客户id
|
||||||
|
*/
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
private Set<Long> customerIds;
|
private Set<Long> customerIds;
|
||||||
|
|
||||||
@Schema(name = "当前所有者")
|
/**
|
||||||
|
* 当前所有者
|
||||||
|
*/
|
||||||
private Long currentOwnerId;
|
private Long currentOwnerId;
|
||||||
|
|
||||||
@Schema(name = "租户ID")
|
/**
|
||||||
|
* 租户ID
|
||||||
|
*/
|
||||||
private String tenantId;
|
private String tenantId;
|
||||||
|
|
||||||
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙")
|
/**
|
||||||
|
* 通讯方式 0:4G;1:蓝牙
|
||||||
|
*/
|
||||||
private Integer communicationMode;
|
private Integer communicationMode;
|
||||||
|
|
||||||
/* app绑定用户id */
|
/* app绑定用户id */
|
||||||
@ -72,22 +95,22 @@ public class DeviceQueryCriteria extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String personnelBy;
|
private String personnelBy;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为管理员
|
* 是否为管理员
|
||||||
*/
|
*/
|
||||||
@Schema(name = "是否为管理员")
|
|
||||||
private Boolean isAdmin = false;
|
private Boolean isAdmin = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备所属分组
|
* 设备所属分组
|
||||||
*/
|
*/
|
||||||
@Schema(name = "设备所属分组")
|
|
||||||
private Long groupId;
|
private Long groupId;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备地区
|
* 设备地区
|
||||||
*/
|
*/
|
||||||
@Schema(name = "设备地区")
|
|
||||||
private String area;
|
private String area;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package com.fuyuanshen.equipment.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class InstructionRecordVo {
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 设备名称
|
||||||
|
*/
|
||||||
|
private String deviceName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备类型
|
||||||
|
*/
|
||||||
|
private String deviceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作模块
|
||||||
|
*/
|
||||||
|
private String deviceAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作内容
|
||||||
|
*/
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作时间
|
||||||
|
*/
|
||||||
|
private String createTime;
|
||||||
|
}
|
@ -1,8 +1,12 @@
|
|||||||
package com.fuyuanshen.equipment.mapper;
|
package com.fuyuanshen.equipment.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.fuyuanshen.equipment.domain.DeviceLog;
|
import com.fuyuanshen.equipment.domain.DeviceLog;
|
||||||
|
import com.fuyuanshen.equipment.domain.dto.InstructionRecordDto;
|
||||||
import com.fuyuanshen.equipment.domain.vo.DeviceLogVo;
|
import com.fuyuanshen.equipment.domain.vo.DeviceLogVo;
|
||||||
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
|
import com.fuyuanshen.equipment.domain.vo.InstructionRecordVo;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备日志Mapper接口
|
* 设备日志Mapper接口
|
||||||
@ -12,4 +16,5 @@ import com.fuyuanshen.common.mybatis.core.mapper.BaseMapperPlus;
|
|||||||
*/
|
*/
|
||||||
public interface DeviceLogMapper extends BaseMapperPlus<DeviceLog, DeviceLogVo> {
|
public interface DeviceLogMapper extends BaseMapperPlus<DeviceLog, DeviceLogVo> {
|
||||||
|
|
||||||
|
Page<InstructionRecordVo> getInstructionRecord(Page<InstructionRecordVo> page,@Param("bo") InstructionRecordDto bo);
|
||||||
}
|
}
|
||||||
|
@ -70,5 +70,5 @@ public interface DeviceMapper extends BaseMapper<Device> {
|
|||||||
|
|
||||||
AppDeviceVo getDeviceInfo(@Param("deviceMac") String deviceMac);
|
AppDeviceVo getDeviceInfo(@Param("deviceMac") String deviceMac);
|
||||||
|
|
||||||
Page<WebDeviceVo> queryWebDeviceList(Page<Object> build, DeviceQueryCriteria bo);
|
Page<WebDeviceVo> queryWebDeviceList(Page<Object> build,@Param("criteria") DeviceQueryCriteria criteria);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.fuyuanshen.equipment.service;
|
|||||||
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
||||||
import com.fuyuanshen.equipment.domain.vo.DeviceGroupVo;
|
import com.fuyuanshen.equipment.domain.vo.DeviceGroupVo;
|
||||||
import com.fuyuanshen.equipment.domain.bo.DeviceGroupBo;
|
import com.fuyuanshen.equipment.domain.bo.DeviceGroupBo;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -56,4 +57,14 @@ public interface IDeviceGroupService {
|
|||||||
* @return 是否删除成功
|
* @return 是否删除成功
|
||||||
*/
|
*/
|
||||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定设备分组
|
||||||
|
*
|
||||||
|
* @param groupId 分组id
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return 是否绑定成功
|
||||||
|
*/
|
||||||
|
Boolean bindingDevice(@NotEmpty(message = "分组id 不能为空") Long groupId, @NotEmpty(message = "设备id 不能为空") Long[] deviceId);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.fuyuanshen.equipment.service.impl;
|
package com.fuyuanshen.equipment.service.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.fuyuanshen.common.core.domain.R;
|
import com.fuyuanshen.common.core.domain.R;
|
||||||
@ -11,6 +12,8 @@ import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
|
|||||||
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
import com.fuyuanshen.common.satoken.utils.LoginHelper;
|
||||||
import com.fuyuanshen.equipment.domain.Device;
|
import com.fuyuanshen.equipment.domain.Device;
|
||||||
import com.fuyuanshen.equipment.domain.DeviceTypeGrants;
|
import com.fuyuanshen.equipment.domain.DeviceTypeGrants;
|
||||||
|
import com.fuyuanshen.equipment.mapper.DeviceMapper;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -22,6 +25,7 @@ import com.fuyuanshen.equipment.mapper.DeviceGroupMapper;
|
|||||||
import com.fuyuanshen.equipment.service.IDeviceGroupService;
|
import com.fuyuanshen.equipment.service.IDeviceGroupService;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -39,6 +43,7 @@ import java.util.stream.Collectors;
|
|||||||
public class DeviceGroupServiceImpl implements IDeviceGroupService {
|
public class DeviceGroupServiceImpl implements IDeviceGroupService {
|
||||||
|
|
||||||
private final DeviceGroupMapper baseMapper;
|
private final DeviceGroupMapper baseMapper;
|
||||||
|
private final DeviceMapper deviceMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +68,7 @@ public class DeviceGroupServiceImpl implements IDeviceGroupService {
|
|||||||
public List<DeviceGroupVo> queryList(DeviceGroupBo bo) {
|
public List<DeviceGroupVo> queryList(DeviceGroupBo bo) {
|
||||||
Page<Device> page = new Page<>(bo.getPageNum(), bo.getPageSize());
|
Page<Device> page = new Page<>(bo.getPageNum(), bo.getPageSize());
|
||||||
// 1. 查询顶级分组(parent_id为null)
|
// 1. 查询顶级分组(parent_id为null)
|
||||||
IPage<DeviceGroup> rootGroups = baseMapper.selectRootGroups(bo, page);
|
IPage<DeviceGroup> rootGroups = baseMapper.selectRootGroups(bo, page);
|
||||||
List<DeviceGroup> records = rootGroups.getRecords();
|
List<DeviceGroup> records = rootGroups.getRecords();
|
||||||
|
|
||||||
// 2. 递归构建树形结构
|
// 2. 递归构建树形结构
|
||||||
@ -169,4 +174,29 @@ public class DeviceGroupServiceImpl implements IDeviceGroupService {
|
|||||||
}
|
}
|
||||||
return baseMapper.deleteByIds(ids) > 0;
|
return baseMapper.deleteByIds(ids) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定设备分组
|
||||||
|
*
|
||||||
|
* @param groupId 分组id
|
||||||
|
* @param deviceId 设备id
|
||||||
|
* @return 是否绑定成功
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Boolean bindingDevice(Long groupId, Long[] deviceId) {
|
||||||
|
|
||||||
|
if (deviceId != null && deviceId.length > 0) {
|
||||||
|
// 创建更新条件
|
||||||
|
UpdateWrapper<Device> updateWrapper = new UpdateWrapper<>();
|
||||||
|
updateWrapper.in("id", Arrays.asList(deviceId));
|
||||||
|
updateWrapper.set("group_id", groupId);
|
||||||
|
|
||||||
|
// 执行批量更新
|
||||||
|
deviceMapper.update(updateWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,37 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.fuyuanshen.equipment.mapper.DeviceLogMapper">
|
<mapper namespace="com.fuyuanshen.equipment.mapper.DeviceLogMapper">
|
||||||
|
|
||||||
|
<select id="getInstructionRecord" resultType="com.fuyuanshen.equipment.domain.vo.InstructionRecordVo">
|
||||||
|
SELECT
|
||||||
|
a.id,
|
||||||
|
a.device_name AS deviceName,
|
||||||
|
c.type_name deviceType,
|
||||||
|
a.device_action AS deviceAction,
|
||||||
|
a.content,
|
||||||
|
a.create_time AS createTime
|
||||||
|
FROM
|
||||||
|
device_log a left join device b on a.device_id = b.id
|
||||||
|
left join device_type c on b.device_type = c.id
|
||||||
|
WHERE 1 = 1
|
||||||
|
<if test="bo.deviceType != null">
|
||||||
|
AND c.id = #{bo.deviceType}
|
||||||
|
</if>
|
||||||
|
<if test="bo.deviceName != null and bo.deviceName != ''">
|
||||||
|
AND a.device_name like concat('%',#{bo.deviceName},'%')
|
||||||
|
</if>
|
||||||
|
<if test="bo.deviceMac != null and bo.deviceMac != ''">
|
||||||
|
AND b.device_mac = #{bo.deviceMac}
|
||||||
|
</if>
|
||||||
|
<if test="bo.deviceImei != null and bo.deviceImei != ''">
|
||||||
|
AND b.device_imei = #{bo.deviceImei}
|
||||||
|
</if>
|
||||||
|
<if test="bo.startTime != null and bo.startTime != ''">
|
||||||
|
AND create_time <![CDATA[>=]]> #{bo.startTime}
|
||||||
|
</if>
|
||||||
|
<if test="bo.endTime != null and bo.endTime != ''">
|
||||||
|
AND create_time <![CDATA[<=]]> #{bo.startTime}
|
||||||
|
</if>
|
||||||
|
ORDER BY
|
||||||
|
a.create_time DESC
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
@ -151,7 +151,7 @@
|
|||||||
dt.type_name,
|
dt.type_name,
|
||||||
dt.communication_mode,
|
dt.communication_mode,
|
||||||
d.bluetooth_name,
|
d.bluetooth_name,
|
||||||
dt.model_dictionary detailPageUrl,
|
dt.app_model_dictionary detailPageUrl,
|
||||||
c.binding_time
|
c.binding_time
|
||||||
from device d
|
from device d
|
||||||
inner join device_type dt on d.device_type = dt.id
|
inner join device_type dt on d.device_type = dt.id
|
||||||
@ -181,7 +181,7 @@
|
|||||||
d.device_pic,
|
d.device_pic,
|
||||||
dt.type_name,
|
dt.type_name,
|
||||||
dt.communication_mode,
|
dt.communication_mode,
|
||||||
dt.model_dictionary detailPageUrl,
|
dt.app_model_dictionary detailPageUrl,
|
||||||
d.bluetooth_name
|
d.bluetooth_name
|
||||||
from device d
|
from device d
|
||||||
inner join device_type dt on d.device_type = dt.id
|
inner join device_type dt on d.device_type = dt.id
|
||||||
@ -227,7 +227,7 @@
|
|||||||
dt.type_name,
|
dt.type_name,
|
||||||
dt.communication_mode,
|
dt.communication_mode,
|
||||||
d.bluetooth_name,
|
d.bluetooth_name,
|
||||||
dt.model_dictionary detailPageUrl
|
dt.app_model_dictionary detailPageUrl
|
||||||
from device d
|
from device d
|
||||||
inner join device_type dt on d.device_type = dt.id
|
inner join device_type dt on d.device_type = dt.id
|
||||||
where d.device_mac = #{deviceMac}
|
where d.device_mac = #{deviceMac}
|
||||||
@ -242,7 +242,7 @@
|
|||||||
dt.type_name,
|
dt.type_name,
|
||||||
dt.communication_mode,
|
dt.communication_mode,
|
||||||
d.bluetooth_name,
|
d.bluetooth_name,
|
||||||
dt.model_dictionary detailPageUrl,
|
dt.pc_model_dictionary detailPageUrl,
|
||||||
ap.name personnelBy,
|
ap.name personnelBy,
|
||||||
d.device_status,
|
d.device_status,
|
||||||
c.binding_time
|
c.binding_time
|
||||||
@ -254,7 +254,7 @@
|
|||||||
<if test="criteria.deviceType != null">
|
<if test="criteria.deviceType != null">
|
||||||
and d.device_type = #{criteria.deviceType}
|
and d.device_type = #{criteria.deviceType}
|
||||||
</if>
|
</if>
|
||||||
<if test="criteria.deviceName != null">
|
<if test="criteria.deviceName != null and criteria.deviceName != ''">
|
||||||
and d.device_name like concat('%', #{criteria.deviceName}, '%')
|
and d.device_name like concat('%', #{criteria.deviceName}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="criteria.deviceMac != null">
|
<if test="criteria.deviceMac != null">
|
||||||
@ -270,7 +270,10 @@
|
|||||||
and ap.name like concat('%', #{criteria.personnelBy}, '%')
|
and ap.name like concat('%', #{criteria.personnelBy}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="criteria.communicationMode != null">
|
<if test="criteria.communicationMode != null">
|
||||||
and dt.communication_mode, = #{criteria.communicationMode}
|
and dt.communication_mode = #{criteria.communicationMode}
|
||||||
|
</if>
|
||||||
|
<if test="criteria.groupId != null">
|
||||||
|
and d.group_id = #{criteria.groupId}
|
||||||
</if>
|
</if>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user