异常上报、SN绑定、设备推送

This commit is contained in:
墨大叔 2024-05-06 18:06:58 +08:00
parent 1b342869d3
commit 5ee530e494
49 changed files with 546 additions and 180 deletions

View File

@ -16,7 +16,7 @@ import java.util.Objects;
public enum UserType {
TENANT("00", "租户"),
LANDLORD("01", "房东");
LANDLORD("01", "商户");
private final String type;
private final String name;

View File

@ -0,0 +1,15 @@
package com.ruoyi.iot.constants;
/**
* @author wjh
* 2024/5/6
*/
public class ReceiveConstants {
// 数据点IDSSID
public static final String DS_SSID = "ssid";
// 数据点IDSSID的值创特
public static final String DSV_SSID_CT = "ChangteA";
}

View File

@ -29,10 +29,10 @@ public class CurrentDeviceData {
device.setAt(new Date());
device.setMac(title);
device.setId(id);
if (CollectionUtils.isEmpty(datastreams)) {
return device;
}
for (CurrentDatastream stream : datastreams) {
String value = stream.getValue().toString();
switch (stream.getId()) {
@ -46,13 +46,13 @@ public class CurrentDeviceData {
device.setA(NumberUtils.nonNullDecimal(value));
break;
case "W":
device.setW(NumberUtils.nonNullDecimal(value).divide(new BigDecimal(1000), RoundingMode.HALF_UP));
device.setW(NumberUtils.nonNullDecimal(value).divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP));
break;
case "S":
device.setS(value);
break;
case "M":
device.setM(NumberUtils.nonNullDecimal(value).divide(new BigDecimal(1000), RoundingMode.HALF_UP));
device.setM(NumberUtils.nonNullDecimal(value).divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP));
break;
case "SET":
DeviceOutageWay deviceOutageWay = DeviceOutageWay.parse(value);

View File

@ -1,9 +1,7 @@
package com.ruoyi.iot.domain;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;

View File

@ -9,7 +9,7 @@ import lombok.Data;
*/
@Data
public class BodyObj {
public class ReceiveBody {
/** 设备推送数据,包括设备的生命周期,数据点,物模型属性、事件、服务等 */
private Object msg;

View File

@ -0,0 +1,40 @@
package com.ruoyi.iot.domain;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
/**
* @author wjh
* 2024/5/6
*/
@Data
public class ReceiveMsg {
// 类型 1数据点 2生命周期
private Integer type;
// 设备名称:mac
@JSONField(name = "dev_name")
private String devName;
// 设备上报的时间戳
private Long at;
// 产品id
@JSONField(name ="pid")
private String pid;
// 生命周期状态0离线1在线
private Integer status;
// 数据点id
@JSONField(name = "ds_id")
private String dsId;
// 具体数据部分为设备上传至平台或触发的相关数据
private Object value;
// LwM2M协议设备的IMEI号
private String imei;
}

View File

@ -0,0 +1,19 @@
package com.ruoyi.iot.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author wjh
* 2024/5/6
*/
@Getter
@AllArgsConstructor
public enum ReceiveType {
DATA_POINT(1), // 数据点
DEVICE_STATUS(2); // 生命周期
private final Integer type;
}

View File

@ -2,9 +2,11 @@ package com.ruoyi.iot.receive;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.iot.util.Util;
import com.ruoyi.iot.domain.BodyObj;
import com.ruoyi.iot.domain.ReceiveBody;
import com.ruoyi.iot.domain.ReceiveMsg;
import com.ruoyi.iot.service.IotReceiveService;
import com.ruoyi.iot.service.IotService;
import com.ruoyi.iot.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -32,6 +34,9 @@ public class ReceiveController {
@Autowired
private IotService iotService;
@Autowired
private IotReceiveService iotReceiveService;
/**
* 功能描述第三方平台数据接收<p>
* <ul>:
@ -45,25 +50,25 @@ public class ReceiveController {
@PostMapping(value = "/receive")
@Anonymous
public ResponseEntity<String> receive(@RequestBody String body){
log.info("receive方法接收到参数: body String --- " +body);
BodyObj obj = Util.resolveBody(body, false);
log.info("receive方法解析对象: body Object --- " + JSON.toJSONString(obj));
log.info("receive方法接收到参数: body String --- {}", body);
ReceiveBody obj = Util.resolveBody(body, false);
log.info("receive方法解析对象: body Object --- {}", JSON.toJSONString(obj));
if (obj != null){
boolean dataRight = Util.checkSignature(obj, token);
if (dataRight){
log.info("receive方法验证签名正确: content" + JSON.toJSONString(obj));
if (Util.checkSignature(obj, token)){
log.info("receive方法验证签名正确: content {}", JSON.toJSONString(obj));
Object msg = obj.getMsg();
// TODO 接收到msg 更新设备参数
log.info("receive方法-获取到消息体: msg---" + JSON.toJSONString(msg));
log.info("receive方法-获取到消息体: msg--- {}", JSON.toJSONString(msg));
// 接收到msg
if (msg instanceof String) {
iotReceiveService.handleReceive(JSON.parseObject((String) msg, ReceiveMsg.class));
} else {
iotReceiveService.handleReceive(JSON.parseObject(JSON.toJSONString(msg), ReceiveMsg.class));
}
}else {
log.info("receive方法验证签名错误: signature error");
log.error("receive方法验证签名错误: signature error");
}
}else {
log.info("receive方法参数为空: body empty error");
log.error("receive方法参数为空: body empty error");
}
return new ResponseEntity<>(HttpStatus.OK);
}

View File

@ -0,0 +1,13 @@
package com.ruoyi.iot.service;
import com.ruoyi.iot.domain.ReceiveMsg;
/**
* @author wjh
* 2024/5/6
*/
public interface IotReceiveService {
void handleReceive(ReceiveMsg msg);
}

View File

@ -0,0 +1,41 @@
package com.ruoyi.iot.service;
import com.ruoyi.iot.constants.ReceiveConstants;
import com.ruoyi.iot.domain.ReceiveMsg;
import com.ruoyi.iot.enums.ReceiveType;
import com.ruoyi.ss.device.domain.SmDevice;
import com.ruoyi.ss.device.service.ISmDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author wjh
* 2024/5/6
*/
@Service
@Slf4j
public class IotReceiveServiceImpl implements IotReceiveService{
@Autowired
private ISmDeviceService deviceService;
@Override
public void handleReceive(ReceiveMsg msg) {
log.info("handleReceive {}", msg.toString());
if (ReceiveType.DATA_POINT.getType().equals(msg.getType())
&& ReceiveConstants.DS_SSID.equals(msg.getDsId())
&& ReceiveConstants.DSV_SSID_CT.equals((String) msg.getValue())
) {
// 当数据点推送ssid的值为ChangteA时录入设备
deviceService.addInitDevice(this.parseToDevice(msg));
}
}
private SmDevice parseToDevice(ReceiveMsg msg) {
SmDevice device = new SmDevice();
device.setMac(msg.getDevName());
return device;
}
}

View File

@ -1,5 +1,6 @@
package com.ruoyi.iot.service;
import com.ruoyi.iot.domain.CurrentDeviceData;
import com.ruoyi.iot.domain.HistoryDeviceData;
import com.ruoyi.iot.domain.IotDeviceDetail;

View File

@ -1,6 +1,6 @@
package com.ruoyi.iot.util;
import com.ruoyi.iot.domain.BodyObj;
import com.ruoyi.iot.domain.ReceiveBody;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONObject;
@ -63,7 +63,7 @@ public class Util {
* @param token OneNet平台配置页面token的值
* @return
*/
public static boolean checkSignature(BodyObj obj, String token) {
public static boolean checkSignature(ReceiveBody obj, String token) {
//计算接受到的消息的摘要
//token长度 + 8B随机字符串长度 + 消息长度
byte[] signature = new byte[token.length() + 8 + obj.getMsg().toString().length()];
@ -87,7 +87,7 @@ public class Util {
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static String decryptMsg(BodyObj obj, String encodeKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
public static String decryptMsg(ReceiveBody obj, String encodeKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
byte[] encMsg = Base64.decodeBase64(obj.getMsg().toString());
byte[] aeskey = Base64.decodeBase64(encodeKey + "=");
SecretKey secretKey = new SecretKeySpec(aeskey, 0, 32, "AES");
@ -104,14 +104,14 @@ public class Util {
}
/**
* 功能描述 解析数据推送请求生成code>BodyObj</code>消息对象
* 功能描述 解析数据推送请求生成code>ReceiveBody</code>消息对象
* @param body 数据推送请求body部分
* @param encrypted 表征是否为加密消息
* @return 生成的<code>BodyObj</code>消息对象
* @return 生成的<code>ReceiveBody</code>消息对象
*/
public static BodyObj resolveBody(String body, boolean encrypted) {
public static ReceiveBody resolveBody(String body, boolean encrypted) {
JSONObject jsonMsg = new JSONObject(body);
BodyObj obj = new BodyObj();
ReceiveBody obj = new ReceiveBody();
obj.setNonce(jsonMsg.getString("nonce"));
obj.setSignature(jsonMsg.getString("signature"));
if (encrypted) {

View File

@ -1,5 +1,6 @@
package com.ruoyi.ss.abnormal.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
@ -8,4 +9,8 @@ import lombok.Data;
*/
@Data
public class AbnormalQuery extends Abnormal {
@ApiModelProperty("关键词,可以是故障描述、故障编号")
private String keyword;
}

View File

@ -40,6 +40,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null"> and sa.`user_id` = #{userId}</if>
<if test="deleted != null"> and sa.`deleted` = #{deleted}</if>
<if test="deleted == null"> and sa.deleted = false</if>
<if test="keyword != null">
and (
sa.content like concat('%', #{keyword}, '%') or
sa.name like concat('%', #{keyword}, '%') or
sa.mobile like concat('%', #{keyword}, '%') or
sa.address like concat('%', #{keyword}, '%') or
sa.device_no like concat('%', #{keyword}, '%')
)
</if>
</where>
</select>

View File

@ -162,7 +162,7 @@ public class SmBusinessRecordServiceImpl implements ISmBusinessRecordService
modelDto.setDeleted(false);
brief.setModelCount(modelService.selectCount(modelDto));
// 房东总数
// 商户总数
SmUserQuery userDto = new SmUserQuery();
userDto.setDelFlag(UserStatus.OK.getCode());
brief.setUserCount(userService.selectCount(userDto));

View File

@ -16,7 +16,7 @@ public class BriefVo {
private Integer deviceCount; // 设备数量
private Integer modelCount; // 型号数量
private Integer onlineCount; // 在线数量
private Integer userCount; // 房东用户数量
private Integer userCount; // 商户用户数量
private Integer tenantCount; // 租户用户数量
private BigDecimal rechargeAmount; // 充值金额

View File

@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.common.core.domain.ValidGroup;
import com.ruoyi.common.valid.EnumValid;
import com.ruoyi.ss.device.domain.enums.DeviceOutageWay;
@ -33,22 +34,23 @@ public class SmDevice extends BaseEntity
/** 设备id */
@ApiModelProperty("设备ID")
@NotNull(message = "设备id不允许为空", groups = {ValidGroup.Update.class})
@JsonView(DeviceView.SuitList.class)
@JsonView({DeviceView.SuitList.class, JsonViewProfile.App.class})
private Long deviceId;
@ApiModelProperty("设备编号SN")
@JsonView(DeviceView.SuitList.class)
@JsonView({DeviceView.SuitList.class, JsonViewProfile.App.class})
private String deviceNo;
/** 店铺id */
@Excel(name = "店铺id")
@ApiModelProperty("店铺id")
@JsonView(JsonViewProfile.App.class)
private Long storeId;
/** 设备名称 */
@Excel(name = "设备名称")
@ApiModelProperty("设备名称")
@JsonView(DeviceView.SuitList.class)
@JsonView({DeviceView.SuitList.class, JsonViewProfile.App.class})
@NotNull(message = "设备名称不允许为空", groups = {ValidGroup.Create.class, ValidGroup.Update.class})
private String deviceName;
@ -83,11 +85,13 @@ public class SmDevice extends BaseEntity
/** 在线状态 */
@Excel(name = "在线状态")
@ApiModelProperty("在线状态")
@JsonView(JsonViewProfile.App.class)
private String onlineStatus;
/** 状态 */
@Excel(name = "状态")
@ApiModelProperty("状态")
@JsonView(JsonViewProfile.App.class)
private String status;
/** 实时功率(千瓦) */
@ -107,10 +111,10 @@ public class SmDevice extends BaseEntity
@Min(value = 0, message = "电压不允许小于0", groups = {ValidGroup.Create.class, ValidGroup.Update.class, ValidGroup.FrontUpdate.class})
private BigDecimal voltage;
/** 所属房东ID */
@Excel(name = "所属房东ID")
@ApiModelProperty("所属房东ID")
@NotNull(message = "房东不允许为空", groups = {ValidGroup.Create.class, ValidGroup.Update.class})
/** 所属商户ID */
@Excel(name = "所属商户ID")
@ApiModelProperty("所属商户ID")
@NotNull(message = "商户不允许为空", groups = {ValidGroup.Create.class, ValidGroup.Update.class})
private Long userId;
/** 用户昵称 */

View File

@ -34,7 +34,7 @@ public class SmDeviceQuery extends SmDevice {
@ApiModelProperty("型号")
private String model;
@ApiModelProperty("所属房东名称")
@ApiModelProperty("所属商户名称")
private String userName;
@ApiModelProperty("是否已绑定用户")

View File

@ -14,9 +14,9 @@ import java.util.Objects;
@Getter
public enum DeviceStatus {
ARREARS_OFF("1", "欠费断电"),
ARREARS("2", "欠费"),
NORMAL("3", "正常");
NORMAL("1", "正常"),
USING("2", "使用中"),
FIXING("3", "维修中");
private final String status;
private final String msg;

View File

@ -1,12 +1,16 @@
package com.ruoyi.ss.device.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.ss.device.domain.DeviceView;
import com.ruoyi.ss.device.domain.SmDevice;
import com.ruoyi.ss.suit.domain.SuitVo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalTime;
import java.util.List;
/**
@ -27,7 +31,7 @@ public class SmDeviceVo extends SmDevice {
@ApiModelProperty("型号")
private String model;
@ApiModelProperty("房东名称")
@ApiModelProperty("商户名称")
private String userName;
@ApiModelProperty("图片")
@ -39,4 +43,14 @@ public class SmDeviceVo extends SmDevice {
@ApiModelProperty("套餐列表")
@JsonView(DeviceView.SuitList.class)
private List<SuitVo> suitList;
@ApiModelProperty("店铺营业时间(起始)")
@JsonView(JsonViewProfile.App.class)
@JsonFormat(pattern = "HH:mm", timezone = "GMT+8")
private LocalTime storeBusinessTimeStart;
@ApiModelProperty("店铺营业时间(结束)")
@JsonView(JsonViewProfile.App.class)
@JsonFormat(pattern = "HH:mm", timezone = "GMT+8")
private LocalTime storeBusinessTimeEnd;
}

View File

@ -70,11 +70,11 @@ public interface SmDeviceMapper
int selectCount(SmDeviceQuery dto);
/**
* 增加设备电量
* 增加设备时长
* @param deviceId 设备
* @param num 增加的量
*/
int addElectricity(@Param("deviceId") Long deviceId, @Param("num") BigDecimal num);
int addTime(@Param("deviceId") Long deviceId, @Param("num") BigDecimal num);
/**
* 逻辑删除
@ -89,16 +89,16 @@ public interface SmDeviceMapper
List<SmDeviceVo> selectSimpleList(SmDeviceQuery dto);
/**
* 设备绑定房东
* 设备绑定商户
* @param deviceId 设备id
* @param userId 房东id
* @param userId 商户id
*/
int bindLandlord(@Param("deviceId") Long deviceId, @Param("userId") Long userId);
/**
* 解绑房东
* 解绑商户
* @param deviceId 设备id
* @param userId 房东id
* @param userId 商户id
*/
int unbindLandlord(@Param("deviceId") Long deviceId, @Param("userId") Long userId);
@ -127,4 +127,10 @@ public interface SmDeviceMapper
* @return
*/
SmDeviceVo selectByDeviceNo(String deviceNo);
/**
* 设备绑定SN
*/
int bindSn(@Param("deviceId") Long deviceId, @Param("sn") String sn);
}

View File

@ -251,12 +251,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</trim>
</insert>
<update id="addElectricity">
<update id="addTime">
update sm_device
set surplus_electri_quantity = surplus_electri_quantity + #{num}
set expire_time = IF (
expire_time is null or now() > expire_time,
DATE_ADD(now(),INTERVAL #{num} MINUTE),
DATE_ADD(expire_time,INTERVAL #{num} MINUTE)
)
where device_id = #{deviceId} and deleted = false
</update>
<update id="bindSn">
update sm_device
set device_no = #{sn}
where device_id = #{deviceId} and deleted = false and device_no is null
</update>
<update id="updateSmDevice" parameterType="SmDevice">
update sm_device
<trim prefix="SET" suffixOverrides=",">
@ -326,4 +336,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{deviceId}
</foreach>
</delete>
</mapper>

View File

@ -23,11 +23,17 @@ public interface DeviceAssembler {
* 设置设备分组
* @param device
*/
void setGroup(SmDevice device);
void setStore(SmDevice device);
/**
* 拼接套餐列表
* @param list
*/
void assembleSuitList(List<SmDeviceVo> list);
/**
* 拼接店铺营业时间
* @param list
*/
void assembleBusinessTime(List<SmDeviceVo> list);
}

View File

@ -4,6 +4,7 @@ import com.ruoyi.common.utils.CollectionUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.ss.device.domain.SmDevice;
import com.ruoyi.ss.device.domain.vo.SmDeviceVo;
import com.ruoyi.ss.store.domain.StoreQuery;
import com.ruoyi.ss.store.domain.StoreVo;
import com.ruoyi.ss.store.service.IStoreService;
import com.ruoyi.ss.deviceTenant.domain.SmDeviceTenant;
@ -11,12 +12,12 @@ import com.ruoyi.ss.deviceTenant.service.ISmDeviceTenantService;
import com.ruoyi.ss.suit.domain.SuitQuery;
import com.ruoyi.ss.suit.domain.SuitVo;
import com.ruoyi.ss.suit.service.ISuitService;
import com.ruoyi.ss.user.service.ISmUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -35,6 +36,9 @@ public class DeviceAssemblerImpl implements DeviceAssembler {
@Autowired
private ISuitService suitService;
@Autowired
private IStoreService storeService;
@Override
public void assembleTenant(List<SmDeviceVo> list) {
if (CollectionUtils.isEmpty(list)) {
@ -53,8 +57,8 @@ public class DeviceAssemblerImpl implements DeviceAssembler {
}
@Override
public void setGroup(SmDevice device) {
// 房东的默认店铺
public void setStore(SmDevice device) {
// 商户的默认店铺
if (device.getUserId() != null && device.getStoreId() == null) {
StoreVo defaultStore = smDeviceGroupService.selectDefaultStore(device.getUserId());
if (defaultStore == null) {
@ -83,4 +87,28 @@ public class DeviceAssemblerImpl implements DeviceAssembler {
device.setSuitList(groups.get(device.getDeviceId()));
}
}
/**
* 拼接店铺营业时间
*
* @param list
*/
@Override
public void assembleBusinessTime(List<SmDeviceVo> list) {
if (CollectionUtils.isEmptyElement(list)) {
return;
}
StoreQuery query = new StoreQuery();
query.setStoreIds(list.stream().map(SmDeviceVo::getStoreId).filter(Objects::nonNull).distinct().collect(Collectors.toList()));
Map<Long, StoreVo> map = storeService.selectMap(query, StoreVo::getStoreId);
for (SmDeviceVo device : list) {
StoreVo store = device.getStoreId() == null ? null : map.get(device.getStoreId());
if (store != null) {
device.setStoreBusinessTimeStart(store.getBusinessTimeStart());
device.setStoreBusinessTimeEnd(store.getBusinessTimeEnd());
}
}
}
}

View File

@ -1,5 +1,7 @@
package com.ruoyi.ss.device.service;
import com.ruoyi.common.core.domain.ValidateResult;
import java.util.List;
/**
@ -12,4 +14,5 @@ public interface DeviceValidator {
* 设备编号是否存在
*/
boolean isExistNo(List<String> deviceNos);
}

View File

@ -73,11 +73,11 @@ public interface ISmDeviceService
List<SmDeviceVo> selectSmDeviceByStoreId(Long storeId);
/**
* 增加电量
* 增加时间
* @param deviceId 设备id
* @param num 电量
*/
boolean addElectricity(Long deviceId, BigDecimal num);
boolean addTime(Long deviceId, BigDecimal num);
/**
* 租户绑定设备
@ -131,7 +131,7 @@ public interface ISmDeviceService
/**
* 通过设备id绑定设备
* 设备第一次绑定为房东
* 设备第一次绑定为商户
* 其他时候绑定为租户
* @param userId 用户id
* @param deviceId 设备id
@ -140,7 +140,7 @@ public interface ISmDeviceService
/**
* 通过mac绑定设备
* 设备第一次绑定为房东
* 设备第一次绑定为商户
* 其他时候绑定为租户
* @param userId 用户id
* @param mac 设备mac
@ -148,7 +148,7 @@ public interface ISmDeviceService
boolean bind(Long userId, String mac);
/**
* 房东解绑设备
* 商户解绑设备
* @param userId 用户id
* @param deviceId 设备id
*/
@ -203,4 +203,17 @@ public interface ISmDeviceService
* 根据设备编号查询
*/
SmDeviceVo selectByDeviceNo(String deviceNo);
/**
* 初始设备录入
* @param smDevice
*/
int addInitDevice(SmDevice smDevice);
/**
* 设备绑定SN码
* @param deviceId 设备ID
* @param sn SN
*/
int bindSn(Long deviceId, String sn);
}

View File

@ -9,17 +9,13 @@ import com.ruoyi.ss.device.domain.SmDeviceCountVO;
import com.ruoyi.ss.device.domain.SmDeviceQuery;
import com.ruoyi.ss.device.domain.vo.SmDeviceVo;
import com.ruoyi.ss.device.domain.enums.DeviceOnlineStatus;
import com.ruoyi.ss.device.domain.enums.DeviceOutageWay;
import com.ruoyi.ss.device.domain.enums.DevicePowerStatus;
import com.ruoyi.ss.device.domain.enums.DeviceStatus;
import com.ruoyi.ss.device.mapper.SmDeviceMapper;
import com.ruoyi.ss.deviceBindRecord.service.ISmDeviceBindRecordService;
import com.ruoyi.ss.store.mapper.StoreMapper;
import com.ruoyi.ss.store.service.IStoreService;
import com.ruoyi.ss.deviceTenant.domain.SmDeviceTenant;
import com.ruoyi.ss.deviceTenant.mapper.SmDeviceTenantMapper;
import com.ruoyi.ss.deviceTenant.service.ISmDeviceTenantService;
import com.ruoyi.ss.model.mapper.SmModelMapper;
import com.ruoyi.ss.resetRecord.domain.SmResetRecord;
import com.ruoyi.ss.resetRecord.service.ISmResetRecordService;
import com.ruoyi.ss.user.domain.SmUserVo;
@ -32,8 +28,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@ -77,6 +76,9 @@ public class SmDeviceServiceImpl implements ISmDeviceService
@Autowired
private DeviceAssembler deviceAssembler;
@Autowired
private TransactionTemplate transactionTemplate;
@Value("${debug}")
private Boolean debug;
@ -161,11 +163,10 @@ public class SmDeviceServiceImpl implements ISmDeviceService
{
this.validate(data, false);
deviceAssembler.setGroup(data); // 房东分组
deviceAssembler.setStore(data); // 商户分组
data.setCreateTime(DateUtils.getNowDate());
data.setStatus(DeviceStatus.NORMAL.getStatus());
data.setDeviceNo("DS-" + SnowFlakeUtil.newId());
return smDeviceMapper.insertSmDevice(data);
}
@ -288,19 +289,19 @@ public class SmDeviceServiceImpl implements ISmDeviceService
@Override
@Transactional
public boolean addElectricity(Long deviceId, BigDecimal num) {
public boolean addTime(Long deviceId, BigDecimal num) {
ServiceUtil.assertion(num.compareTo(BigDecimal.ZERO) < 0, "增加的电量不允许小于0");
ServiceUtil.assertion(num.compareTo(BigDecimal.ZERO) < 0, "增加的时长不允许小于0");
SmDeviceVo device = smDeviceMapper.selectSmDeviceByDeviceId(deviceId);
ServiceUtil.assertion(device == null, "设备不存在");
ServiceUtil.assertion(!StringUtils.hasText(device.getMac()), "设备MAC号为空");
// 更新数据库电量
int updateCount = smDeviceMapper.addElectricity(deviceId, num);
ServiceUtil.assertion(updateCount != 1, "增加电量失败,请刷新后重试");
// 更新数据库时长
int updateCount = smDeviceMapper.addTime(deviceId, num);
ServiceUtil.assertion(updateCount != 1, "增加时长失败,请刷新后重试");
// 物联网设备增加电量
// 物联网设备增加时长
boolean rechargeResult = iotService.recharge(device.getMac(), num);
ServiceUtil.assertion(!rechargeResult, "设备充值失败");
@ -319,7 +320,7 @@ public class SmDeviceServiceImpl implements ISmDeviceService
SmDeviceVo device = smDeviceMapper.selectSmDeviceByDeviceId(deviceId);
ServiceUtil.assertion(device == null || device.getDeleted(), "待绑定的设备不存在");
ServiceUtil.assertion(device.getUserId() == null, "该设备还未绑定房东,请先绑定房东");
ServiceUtil.assertion(device.getUserId() == null, "该设备还未绑定商户,请先绑定商户");
SmUserVo user = smUserMapper.selectSmUserByUserId(tenantId);
ServiceUtil.assertion(user == null, "用户不存在");
@ -446,7 +447,7 @@ public class SmDeviceServiceImpl implements ISmDeviceService
deviceAssembler.assembleTenant(Collections.singletonList(device));
ServiceUtil.assertion(!UserUtil.hasFrontUser(device.getTenantIds())
&& !UserUtil.hasFrontUser(device.getUserId()), "您不是该设备的租户或房东,无法进行该操作" );
&& !UserUtil.hasFrontUser(device.getUserId()), "您不是该设备的租户或商户,无法进行该操作" );
if (DevicePowerStatus.ON.equals(status)) {
// 通电检查电量余额是否足够
@ -500,19 +501,6 @@ public class SmDeviceServiceImpl implements ISmDeviceService
data.setLastPullTime(deviceInfo.getAt());
data.setTotalElectriQuantity(deviceInfo.getW());
data.setPowerStatus(deviceInfo.getS());
// 更新电表状态
if (BigDecimal.ZERO.compareTo(deviceInfo.getM()) >= 0) {
if (DeviceOutageWay.IMMEDIATE.getValue().equals(device.getOutageWay())) {
// 欠费断电
data.setStatus(DeviceStatus.ARREARS_OFF.getStatus());
} else {
// 欠费
data.setStatus(DeviceStatus.ARREARS.getStatus());
}
} else {
// 正常
data.setStatus(DeviceStatus.NORMAL.getStatus());
}
}
// 是否在线
@ -548,7 +536,7 @@ public class SmDeviceServiceImpl implements ISmDeviceService
ServiceUtil.assertion(device == null || device.getDeleted(), "设备不存在");
if (device.getUserId() == null) {
// 房东为空绑定房东
// 商户为空绑定商户
this.bindLandlord(userId, deviceId);
} else {
// 绑定租户
@ -599,24 +587,27 @@ public class SmDeviceServiceImpl implements ISmDeviceService
public boolean reset(Long deviceId) {
ServiceUtil.assertion(deviceId == null, "设备id不能为空");
LocalDateTime now = LocalDateTime.now();
SmDeviceVo device = smDeviceMapper.selectSmDeviceByDeviceId(deviceId);
ServiceUtil.assertion(device == null || device.getDeleted(), "设备不存在");
ServiceUtil.assertion(!UserUtil.hasFrontUser(device.getUserId()), "您不是该设备的房东,无法进行该操作");
ServiceUtil.assertion(hasTenant(deviceId), "该设备还有租户,不允许归零");
ServiceUtil.assertion(!UserUtil.hasFrontUser(device.getUserId()), "您不是该设备的商户,无法进行该操作");
ServiceUtil.assertion(device.getExpireTime() == null || device.getExpireTime().isBefore(now), "设备剩余时间不足,无需归零");
// 电量归零设置初始读数
// 归零时间将过期时间设置为现在
SmDevice form = new SmDevice();
form.setDeviceId(deviceId);
form.setInitReading(device.getTotalElectriQuantity());
form.setExpireTime(now);
smDeviceMapper.updateSmDevice(form);
// TODO 物联网设备归零
// 归零记录
scheduledExecutorService.schedule(() -> {
SmResetRecord reset = new SmResetRecord();
reset.setDeviceId(deviceId);
reset.setLandlordId(device.getUserId());
reset.setSurplusElectriQuantity(device.getSurplusElectriQuantity());
reset.setTotalElectriQuantity(device.getTotalElectriQuantity());
reset.setMchId(device.getUserId());
Duration duration = Duration.between(now, device.getExpireTime());
reset.setSurplusTime(new BigDecimal(duration.toMinutes()));
smResetRecordService.insertSmResetRecord(reset);
}, 0, TimeUnit.SECONDS);
@ -729,12 +720,31 @@ public class SmDeviceServiceImpl implements ISmDeviceService
return smDeviceMapper.selectByDeviceNo(deviceNo);
}
/**
* 初始设备录入
*
* @param smDevice 设备信息
*/
@Override
public int addInitDevice(SmDevice smDevice) {
if (smDevice == null) {
return 0;
}
try {
smDevice.setCreateTime(DateUtils.getNowDate());
return smDeviceMapper.insertSmDevice(smDevice);
} catch (Exception e) {
log.error("add init device error: {}", e.getMessage());
return 0;
}
}
@Override
@Transactional
public boolean landlordUnbind(Long userId, Long deviceId) {
SmDeviceVo device = smDeviceMapper.selectSmDeviceByDeviceId(deviceId);
ServiceUtil.assertion(device == null || device.getDeleted(), "设备不存在");
ServiceUtil.assertion(!Objects.equals(device.getUserId(), userId), "您不是该设备的房东");
ServiceUtil.assertion(!Objects.equals(device.getUserId(), userId), "您不是该设备的商户");
deviceAssembler.assembleTenant(Collections.singletonList(device));
ServiceUtil.assertion(!CollectionUtils.isEmpty(device.getTenantIds()), "该设备还有租户绑定,无法解除绑定");
@ -744,10 +754,10 @@ public class SmDeviceServiceImpl implements ISmDeviceService
return true;
}
// 绑定房东
// 绑定商户
@Transactional
public void bindLandlord(Long userId, Long deviceId) {
ServiceUtil.assertion(userId == null || deviceId == null, "房东绑定设备参数错误");
ServiceUtil.assertion(userId == null || deviceId == null, "商户绑定设备参数错误");
SmUserVo user = smUserMapper.selectSmUserByUserId(userId);
@ -758,7 +768,7 @@ public class SmDeviceServiceImpl implements ISmDeviceService
SmDevice device = new SmDevice();
device.setDeviceId(deviceId);
device.setUserId(userId);
deviceAssembler.setGroup(device);
deviceAssembler.setStore(device);
smDeviceMapper.updateSmDevice(device);
// 记录设备绑定
@ -766,4 +776,20 @@ public class SmDeviceServiceImpl implements ISmDeviceService
smDeviceBindRecordService.record(userId, deviceId);
},0, TimeUnit.SECONDS);
}
/**
* 设备绑定SN码
*
* @param deviceId 设备ID
* @param sn SN
*/
@Override
public int bindSn(Long deviceId, String sn) {
Integer result = transactionTemplate.execute(status -> {
int i = smDeviceMapper.bindSn(deviceId, sn);
ServiceUtil.assertion(i != 1, "设备SN已发生变化请刷新后重试");
return i;
});
return result == null ? 0 : result;
}
}

View File

@ -1,8 +1,12 @@
package com.ruoyi.ss.device.service.impl;
import com.ruoyi.common.core.domain.BaseValidator;
import com.ruoyi.common.core.domain.ValidateResult;
import com.ruoyi.common.utils.CollectionUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.UserUtil;
import com.ruoyi.ss.device.domain.SmDeviceQuery;
import com.ruoyi.ss.device.domain.vo.SmDeviceVo;
import com.ruoyi.ss.device.service.DeviceValidator;
import com.ruoyi.ss.device.service.ISmDeviceService;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -28,16 +28,12 @@ public class SmResetRecord extends BaseEntity
private Long deviceId;
/** 归零时剩余电量 */
@Excel(name = "归零时剩余电量")
@ApiModelProperty("归零时剩余电量")
private BigDecimal surplusElectriQuantity;
@Excel(name = "归零时剩余时长(分钟)")
@ApiModelProperty("归零时剩余时长(分钟)")
private BigDecimal surplusTime;
/** 房东id */
@Excel(name = "房东id")
@ApiModelProperty("房东id")
private Long landlordId;
@Excel(name = "归零时总用电量")
@ApiModelProperty("归零时总用电量")
private BigDecimal totalElectriQuantity;
/** 商户id */
@Excel(name = "商户id")
@ApiModelProperty("商户id")
private Long mchId;
}

View File

@ -13,6 +13,6 @@ public class SmResetRecordVo extends SmResetRecord {
@ApiModelProperty("设备名称")
private String deviceName;
@ApiModelProperty("房东名称")
private String landlordName;
@ApiModelProperty("商户名称")
private String mchName;
}

View File

@ -7,35 +7,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<resultMap type="SmResetRecordVo" id="SmResetRecordResult">
<result property="id" column="id" />
<result property="deviceId" column="device_id" />
<result property="surplusElectriQuantity" column="surplus_electri_quantity" />
<result property="surplusTime" column="surplus_time" />
<result property="createTime" column="create_time" />
<result property="landlordId" column="landlord_id" />
<result property="totalElectriQuantity" column="total_electri_quantity" />
<result property="mchId" column="mch_id" />
<result property="deviceName" column="device_name" />
<result property="landlordName" column="landlord_name" />
<result property="mchName" column="mch_name" />
</resultMap>
<sql id="selectSmResetRecordVo">
select
srr.id,
srr.device_id,
srr.surplus_electri_quantity,
srr.surplus_time,
srr.create_time,
srr.landlord_id,
srr.total_electri_quantity,
srr.mch_id,
sd.device_name device_name,
su.user_name landlord_name
su.user_name mch_name
from sm_reset_record srr
left join sm_device sd on sd.device_id = srr.device_id
left join sm_user su on su.user_id = srr.landlord_id
left join sm_user su on su.user_id = srr.mch_id
</sql>
<select id="selectSmResetRecordList" parameterType="SmResetRecordQuery" resultMap="SmResetRecordResult">
<include refid="selectSmResetRecordVo"/>
<where>
<if test="deviceId != null "> and srr.device_id = #{deviceId}</if>
<if test="surplusElectriQuantity != null "> and srr.surplus_electri_quantity = #{surplusElectriQuantity}</if>
<if test="landlordId != null "> and srr.landlord_id = #{landlordId}</if>
<if test="surplusTime != null "> and srr.surplus_time = #{surplusTime}</if>
<if test="mchId != null "> and srr.mch_id = #{mchId}</if>
</where>
order by srr.create_time desc
</select>
@ -50,18 +48,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="deviceId != null">device_id,</if>
<if test="surplusElectriQuantity != null">surplus_electri_quantity,</if>
<if test="surplusTime != null">surplus_time,</if>
<if test="createTime != null">create_time,</if>
<if test="landlordId != null">landlord_id,</if>
<if test="totalElectriQuantity != null">total_electri_quantity,</if>
<if test="mchId != null">mch_id,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="deviceId != null">#{deviceId},</if>
<if test="surplusElectriQuantity != null">#{surplusElectriQuantity},</if>
<if test="surplusTime != null">#{surplusTime},</if>
<if test="createTime != null">#{createTime},</if>
<if test="landlordId != null">#{landlordId},</if>
<if test="totalElectriQuantity != null">#{totalElectriQuantity},</if>
<if test="mchId != null">#{mchId},</if>
</trim>
</insert>
@ -69,10 +65,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
update sm_reset_record
<trim prefix="SET" suffixOverrides=",">
<if test="deviceId != null">device_id = #{deviceId},</if>
<if test="surplusElectriQuantity != null">surplus_electri_quantity = #{surplusElectriQuantity},</if>
<if test="surplusTime != null">surplus_time = #{surplusTime},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="landlordId != null">landlord_id = #{landlordId},</if>
<if test="totalElectriQuantity != null">total_electri_quantity = #{totalElectriQuantity},</if>
<if test="mchId != null">mch_id = #{mchId},</if>
</trim>
where id = #{id}
</update>

View File

@ -38,4 +38,8 @@ public class StoreVo extends Store {
@ApiModelProperty("离线设备数量")
private Integer offlineCount;
@ApiModelProperty("可共享的设备数量")
@JsonView(JsonViewProfile.App.class)
private Integer availableDeviceCount;
}

View File

@ -4,6 +4,7 @@ import com.ruoyi.ss.store.domain.Store;
import com.ruoyi.ss.store.domain.StoreCountVO;
import com.ruoyi.ss.store.domain.StoreQuery;
import com.ruoyi.ss.store.domain.StoreVo;
import org.checkerframework.checker.units.qual.K;
import java.util.List;
import java.util.Map;
@ -101,4 +102,16 @@ public interface IStoreService
*/
Map<Long, Integer> selectCountMapByUserIds(List<Long> userIds);
/**
* 设为默认店铺
* @param userId
* @param storeId
* @return
*/
boolean setDefault(Long userId, Long storeId);
/**
* 查询店铺映射表
*/
<K> Map<K, StoreVo> selectMap(StoreQuery query, Function<? super StoreVo, ? extends K> keyMapper);
}

View File

@ -50,4 +50,10 @@ public interface StoreAssembler {
* @param list
*/
void assembleOfflineCount(List<StoreVo> list);
/**
* 拼接可共享设备数量
* @param list
*/
void assembleAvailableDeviceCount(List<StoreVo> list);
}

View File

@ -71,4 +71,9 @@ public interface StoreValidator {
* @param storeIds
*/
boolean isExist(List<Long> storeIds);
/**
* 设置默认店铺前校验
*/
ValidateResult preSetDefaultByApp(Long userId, Long storeId);
}

View File

@ -5,6 +5,7 @@ import com.ruoyi.ss.device.domain.SmDeviceCountVO;
import com.ruoyi.ss.device.domain.SmDeviceQuery;
import com.ruoyi.ss.device.domain.enums.DeviceGroupBy;
import com.ruoyi.ss.device.domain.enums.DeviceOnlineStatus;
import com.ruoyi.ss.device.domain.enums.DeviceStatus;
import com.ruoyi.ss.device.service.ISmDeviceService;
import com.ruoyi.ss.store.domain.StoreVo;
import com.ruoyi.ss.store.service.StoreAssembler;
@ -154,4 +155,27 @@ public class StoreAssemblerImpl implements StoreAssembler {
store.setOfflineCount(count == null ? 0 :count);
}
}
/**
* 拼接可共享设备数量
*
* @param list
*/
@Override
public void assembleAvailableDeviceCount(List<StoreVo> list) {
if (CollectionUtils.isEmptyElement(list)) {
return;
}
SmDeviceQuery query = new SmDeviceQuery();
query.setStoreIds(list.stream().map(StoreVo::getStoreId).collect(Collectors.toList()));
query.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus());
query.setStatus(DeviceStatus.NORMAL.getStatus());
query.setGroupBy(DeviceGroupBy.store_id.name());
Map<Long, Integer> countMap = deviceService.selectCommonCountMap(query, SmDeviceCountVO::getStoreId);
for (StoreVo store : list) {
Integer count = countMap.get(store.getStoreId());
store.setAvailableDeviceCount(count == null ? 0 :count);
}
}
}

View File

@ -89,7 +89,7 @@ public class StoreServiceImpl implements IStoreService
// 如果没有默认店铺则将其设为默认店铺
if (this.selectDefaultStore(store.getUserId()) == null) {
storeMapper.setDefault(store.getUserId(), store.getStoreId());
this.setDefault(store.getUserId(), store.getStoreId());
}
return Boolean.TRUE;
@ -189,7 +189,7 @@ public class StoreServiceImpl implements IStoreService
StoreVo other = storeMapper.selectOne(query);
if (other != null) {
// 其他店铺不为空则设置为第一个店铺
storeMapper.setDefault(other.getUserId(), other.getStoreId());
this.setDefault(other.getUserId(), other.getStoreId());
}
}
@ -254,6 +254,34 @@ public class StoreServiceImpl implements IStoreService
return this.selectCountMap(query, StoreCountVO::getUserId);
}
/**
* 设为默认店铺
*
* @param userId
* @param storeId
* @return
*/
@Override
public boolean setDefault(Long userId, Long storeId) {
storeMapper.setDefault(userId, storeId);
return true;
}
/**
* 查询店铺映射表
*
* @param query
* @param keyMapper
*/
@Override
public <K> Map<K, StoreVo> selectMap(StoreQuery query, Function<? super StoreVo, ? extends K> keyMapper) {
List<StoreVo> list = this.selectSmStoreList(query);
if (CollectionUtils.isEmptyElement(list)) {
return Collections.emptyMap();
}
return list.stream().collect(Collectors.toMap(keyMapper, item -> item));
}
/**
* 通用查询数量
*

View File

@ -231,6 +231,24 @@ public class StoreValidatorImpl extends BaseValidator implements StoreValidator
return count == new HashSet<Long>(storeIds).size();
}
/**
* 设置默认店铺前校验
*
* @param userId
* @param storeId
*/
@Override
public ValidateResult preSetDefaultByApp(Long userId, Long storeId) {
if (userId == null || storeId == null) {
return error("参数错误userId 与 storeId 不允许为空");
}
if (!this.isStoreBelongUser(Collections.singletonList(storeId), userId)) {
return error("当前店铺不属于当前用户");
}
return success();
}
/**
* 校验时间是符合规则

View File

@ -39,7 +39,7 @@ public class Suit extends BaseEntity
/** 通电时间(分) */
@Excel(name = "通电时间(分钟)")
@JsonView(DeviceView.SuitList.class)
private Integer value;
private BigDecimal value;
/** 价格(元) */
@Excel(name = "价格(元)")

View File

@ -121,7 +121,7 @@ public class TransactionBill extends BaseEntity
@ApiModelProperty("套餐时长(分钟)")
@NotNull(message = "套餐时长不允许为空", groups = {ValidGroup.Recharge.class})
@JsonView(JsonViewProfile.App.class)
private Integer suitTime;
private BigDecimal suitTime;
@ApiModelProperty("套餐开始使用时间")
private Integer suitStartTime;

View File

@ -30,7 +30,7 @@ public class TransactionBillQuery extends TransactionBill {
@ApiModelProperty("用户名称")
private String userName;
@ApiModelProperty("房东名称")
@ApiModelProperty("商户名称")
private String landlordName;
@ApiModelProperty("设备名称")

View File

@ -166,7 +166,7 @@ public interface TransactionBillService
boolean updateWxTransferDetailIds(Long billId, List<String> transferIds);
/**
* 查询房东统计信息
* 查询商户统计信息
* @param dto 查询条件
* @return 统计信息
*/

View File

@ -512,8 +512,8 @@ public class TransactionBillServiceImpl implements TransactionBillService {
ServiceUtil.assertion(TransactionBillDeviceRechargeStatus.SUCCESS.getStatus().equals(bill.getDeviceRechargeStatus()), "设备已充值成功,不允许再次充值");
}
// TODO 开关时间增加,四舍五入,保留1位小数
// deviceService.addElectricity(bill.getDeviceId(), computeElectricity(bill));
// 开关时间增加,四舍五入,保留1位小数
deviceService.addTime(bill.getDeviceId(), bill.getSuitTime());
// 修改设备充值状态成功
transactionBillMapper.updateDeviceRechargeStatus(bill.getBillId(), TransactionBillDeviceRechargeStatus.SUCCESS.getStatus());
@ -574,7 +574,7 @@ public class TransactionBillServiceImpl implements TransactionBillService {
int updateCount = transactionBillMapper.rechargeSuccess(bill.getBillId(), payTime);
ServiceUtil.assertion(updateCount != 1, "修改订单状态失败,请刷新后重试");
// 房东余额增加
// 商户余额增加
userService.addBalance(bill.getMchId(), bill.getArrivalAmount());
// 设备充值

View File

@ -89,7 +89,7 @@ public class TransactionBillValidatorImpl extends BaseValidator implements Trans
if (suit.getValue() == null) {
return error("当前套餐未配置时间,请联系商户处理");
}
if (!suit.getValue().equals(data.getSuitTime())) {
if (suit.getValue().compareTo(data.getSuitTime()) != 0) {
return error("当前套餐时间已发生变化,请重新下单");
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.web.controller.app;
import com.fasterxml.jackson.annotation.JsonView;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.common.core.domain.ValidGroup;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.UserType;
@ -10,11 +11,15 @@ import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.ss.device.domain.DeviceView;
import com.ruoyi.ss.device.domain.SmDevice;
import com.ruoyi.ss.device.domain.SmDeviceQuery;
import com.ruoyi.ss.device.service.DeviceAssembler;
import com.ruoyi.ss.device.service.DeviceValidator;
import com.ruoyi.ss.device.service.impl.DeviceValidatorImpl;
import com.ruoyi.ss.meterReadingRecord.domain.SmMeterReadingRecordQuery;
import com.ruoyi.ss.device.domain.enums.DevicePowerStatus;
import com.ruoyi.ss.device.domain.vo.SmDeviceVo;
import com.ruoyi.ss.device.service.ISmDeviceService;
import com.ruoyi.ss.meterReadingRecord.service.ISmMeterReadingRecordService;
import com.ruoyi.web.core.annotation.MchRequired;
import com.ruoyi.web.core.annotation.UserTypePermission;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -26,6 +31,7 @@ import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
/**
* 设备Controller
@ -43,14 +49,19 @@ public class AppDeviceController extends BaseController {
@Autowired
private ISmMeterReadingRecordService smMeterReadingRecordService;
@Autowired
private DeviceAssembler deviceAssembler;
@Value("${debug}")
private Boolean debug;
@Autowired
private DeviceValidator deviceValidator;
/**
* 修改设备
*/
@UserTypePermission({UserType.LANDLORD})
@ApiOperation("房东修改设备")
@ApiOperation("商户修改设备")
@PutMapping
public AjaxResult edit(@RequestBody @Validated({ValidGroup.FrontUpdate.class}) SmDevice smDevice) {
SmDevice device = new SmDevice();
@ -67,11 +78,8 @@ public class AppDeviceController extends BaseController {
return toAjax(smDeviceService.updateSmDevice(device));
}
/**
* 查询设备列表
*/
@UserTypePermission({UserType.LANDLORD})
@ApiOperation("查询房东设备列表")
@MchRequired
@ApiOperation("查询商户设备列表")
@GetMapping("/list")
public TableDataInfo list(SmDeviceQuery smDevice) {
startPage();
@ -79,6 +87,17 @@ public class AppDeviceController extends BaseController {
return getDataTable(smDeviceService.selectSmDeviceList(smDevice));
}
@ApiOperation("查询店铺设备列表")
@GetMapping("/listByStore/{storeId}")
@JsonView(JsonViewProfile.App.class)
public TableDataInfo listByStore(@PathVariable("storeId") Long storeId, SmDeviceQuery query) {
startPage();
query.setStoreId(storeId);
List<SmDeviceVo> list = smDeviceService.selectSmDeviceList(query);
deviceAssembler.assembleBusinessTime(list); // 店铺营业时间
return getDataTable(list);
}
/**
* 获取设备详细信息
*/
@ -88,21 +107,8 @@ public class AppDeviceController extends BaseController {
return success(smDeviceService.selectSmDeviceByDeviceId(deviceId));
}
/**
* 解除设备绑定删除设备
* @param deviceId 设备id
* @return
*/
@UserTypePermission({UserType.LANDLORD})
@ApiOperation("(弃用)房东解除设备绑定(删除设备)")
@DeleteMapping("/{deviceId}")
public AjaxResult delete(@PathVariable Long deviceId) {
ServiceUtil.assertion(true, "本接口已弃用请使用【DELETE】 /app/device/landlord/unbind/{deviceId}接口");
return success(smDeviceService.logicDel(Collections.singletonList(deviceId)));
}
@UserTypePermission({UserType.LANDLORD})
@ApiOperation("房东新增设备")
@ApiOperation("商户新增设备")
@PostMapping
public AjaxResult add(@RequestBody @Validated({ValidGroup.FrontCreate.class}) SmDevice smDevice) {
SmDevice insertDevice = new SmDevice();
@ -121,14 +127,6 @@ public class AppDeviceController extends BaseController {
return getDataTable(smDeviceService.selectSmDeviceList(dto));
}
@UserTypePermission({UserType.TENANT})
@ApiOperation("租户绑定设备")
@PutMapping("/tenant/bind/{deviceId}")
public AjaxResult tenantBind(@PathVariable @ApiParam("设备id") Long deviceId) {
ServiceUtil.assertion(true, "本接口已弃用请使用【PUT】 /app/device/bind/{deviceId}接口");
return success(smDeviceService.tenantBind(getUserId(), deviceId));
}
@UserTypePermission({UserType.TENANT})
@ApiOperation("租户解绑设备")
@PutMapping("/tenant/unbind/{deviceId}")
@ -157,7 +155,7 @@ public class AppDeviceController extends BaseController {
}
@UserTypePermission({UserType.LANDLORD})
@ApiOperation("房东解除设备绑定")
@ApiOperation("商户解除设备绑定")
@DeleteMapping("/landlord/unbind/{deviceId}")
public AjaxResult landlordUnbind(@PathVariable @ApiParam("设备id") Long deviceId) {
return success(smDeviceService.landlordUnbind(getUserId(), deviceId));
@ -185,7 +183,7 @@ public class AppDeviceController extends BaseController {
SmDeviceVo device = smDeviceService.selectSmDeviceByDeviceId(deviceId);
ServiceUtil.assertion(device == null || !getUserId().equals(device.getUserId()), "设备不存在或您无权充值");
smDeviceService.addElectricity(deviceId, amount);
smDeviceService.addTime(deviceId, amount);
return success(true);
}

View File

@ -29,7 +29,7 @@ public class AppResetRecordController extends BaseController {
@GetMapping("/list")
public TableDataInfo list(SmResetRecordQuery dto) {
startPage();
dto.setLandlordId(getUserId());
dto.setMchId(getUserId());
return getDataTable(smResetRecordService.selectSmResetRecordList(dto));
}

View File

@ -135,6 +135,9 @@ public class AppStoreController extends BaseController {
@Anonymous
public AjaxResult getDetail(@PathVariable @ApiParam("店铺ID") Long storeId) {
StoreVo store = storeService.selectSmStoreById(storeId);
List<StoreVo> list = Collections.singletonList(store);
storeAssembler.assembleDeviceCount(list); // 总设备数量
storeAssembler.assembleAvailableDeviceCount(list); // 可共享设备数量
return success(store);
}
@ -142,13 +145,21 @@ public class AppStoreController extends BaseController {
@ApiOperation("商户获取店铺信息")
@GetMapping("/mch/{storeId}")
public AjaxResult getMchDetail(@PathVariable @ApiParam("店铺ID") Long storeId) {
ServiceUtil.assertion(!storeValidator.isStoreBelongUser(Collections.singletonList(storeId), getUserId()), "该店铺不属于您");
ServiceUtil.assertion(!storeValidator.isStoreBelongUser(Collections.singletonList(storeId), getUserId()), "这不是您的店铺,无法查看");
StoreVo store = storeService.selectSmStoreById(storeId);
// 拼接设备数量
List<StoreVo> storeList = Collections.singletonList(store);
storeAssembler.assembleDeviceCount(storeList);
storeAssembler.assembleRevenue(storeList);
storeAssembler.assembleDeviceCount(storeList); // 总设备数量
storeAssembler.assembleRevenue(storeList); // 经营信息
return success(store);
}
@MchRequired
@ApiOperation("切换默认店铺")
@PutMapping("/{storeId}/setDefault")
public AjaxResult setDefaultStore(@PathVariable Long storeId) {
Long userId = getUserId();
ServiceUtil.assertion(storeValidator.preSetDefaultByApp(userId, storeId));
return success(storeService.setDefault(userId, storeId));
}
}

View File

@ -108,7 +108,7 @@ public class AppTransactionBillController extends BaseController
}
@UserTypePermission({UserType.LANDLORD})
@ApiOperation("获取房东统计信息")
@ApiOperation("获取商户统计信息")
@GetMapping("/landlordCount")
public AjaxResult landlordCount(@Validated({ValidGroup.Query.class}) TransactionBillQuery dto) {
Date now = new Date();

View File

@ -113,7 +113,7 @@ public class SmDeviceController extends BaseController
@PutMapping
public AjaxResult edit(@RequestBody @Validated({ValidGroup.Update.class}) SmDevice smDevice)
{
deviceAssembler.setGroup(smDevice); // 房东分组
deviceAssembler.setStore(smDevice); // 商户分组
return toAjax(smDeviceService.updateSmDevice(smDevice));
}
@ -144,4 +144,10 @@ public class SmDeviceController extends BaseController
return success();
}
@ApiOperation("绑定SN码")
@PutMapping("/{deviceId}/bindSn/{sn}")
public AjaxResult bindSn(@PathVariable @ApiParam("设备ID") Long deviceId, @PathVariable @ApiParam("SN") String sn) {
return success(smDeviceService.bindSn(deviceId, sn));
}
}