Merge branch 'master' of http://47.109.37.87:3000/by2025/SmartParks
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

# Conflicts:
#	pom.xml
#	ruoyi-modules/Property/pom.xml
This commit is contained in:
15683799673
2025-07-21 03:37:26 +08:00
38 changed files with 1021 additions and 92 deletions

10
pom.xml
View File

@@ -73,9 +73,9 @@
<id>local</id>
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active>
<nacos.server>172.18.128.1:8848</nacos.server>
<logstash.address>172.18.128.1:4560</logstash.address>
<profiles.active>dev</profiles.active>
<nacos.server>127.0.0.1:8848</nacos.server>
<logstash.address>127.0.0.1:4560</logstash.address>
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
<nacos.username>nacos</nacos.username>
@@ -91,8 +91,8 @@
<properties>
<!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active>
<nacos.server>192.168.0.108:8848</nacos.server>
<logstash.address>192.168.0.108:4560</logstash.address>
<nacos.server>by.missmoc.top:8848</nacos.server>
<logstash.address>by.missmoc.top:4560</logstash.address>
<nacos.discovery.group>DEFAULT_GROUP</nacos.discovery.group>
<nacos.config.group>DEFAULT_GROUP</nacos.config.group>
<nacos.username>nacos</nacos.username>

View File

@@ -1,10 +1,14 @@
package org.dromara.auth.controller;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import org.springframework.beans.BeanUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jodd.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
@@ -37,12 +41,14 @@ import org.dromara.system.api.RemoteSocialService;
import org.dromara.system.api.RemoteTenantService;
import org.dromara.system.api.domain.vo.RemoteClientVo;
import org.dromara.system.api.domain.vo.RemoteTenantVo;
import org.dromara.system.api.model.LoginUser;
import org.springframework.web.bind.annotation.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -104,9 +110,17 @@ public class TokenController {
scheduledExecutorService.schedule(() -> {
remoteMessageService.publishMessage(List.of(userId), "欢迎登录RuoYi-Cloud-Plus微服务管理系统");
}, 3, TimeUnit.SECONDS);
if (loginBody.getRetUrl()!=null){
return R.f(loginBody.getRetUrl()+"?token="+loginVo.getAccessToken());
}
return R.ok(loginVo);
}
@RequestMapping("/token/check")
public R<LoginUser> checkToken(String token) {
return R.ok(LoginHelper.getLoginUser(token));
}
/**
* 第三方登录请求
*

View File

@@ -1,8 +1,14 @@
package org.dromara.auth.service;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import org.dromara.auth.domain.vo.LoginVo;
import org.dromara.auth.form.PasswordLoginBody;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.api.domain.vo.RemoteClientVo;
/**

View File

@@ -24,6 +24,11 @@ public class R<T> implements Serializable {
*/
public static final int SUCCESS = 200;
/**
* 跳转
*/
public static final int FORBIDDEN = 403;
/**
* 失败
*/
@@ -43,6 +48,9 @@ public class R<T> implements Serializable {
* 数据对象
*/
private T data;
public static <T> R<T> f(String url) {
return restResult(null, FORBIDDEN, url);
}
public static <T> R<T> ok() {
return restResult(null, SUCCESS, "操作成功");

View File

@@ -40,4 +40,9 @@ public class LoginBody {
*/
private String uuid;
/**
* 回调地址
*/
private String retUrl;
}

View File

@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.property.domain.bo.CostChargeReturnFeeBo;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
@@ -80,6 +81,15 @@ public class CostCarChargeController extends BaseController {
return toAjax(costCarChargeService.insertByBo(bo));
}
/**
* 车辆退费接口
* @param bo
* @return
*/
@PostMapping("/returnFee")
public R<Void> returnFree( @RequestBody CostChargeReturnFeeBo bo) {
return toAjax(costCarChargeService.returnFree(bo));
}
/**
* 修改费用-车辆收费
*/

View File

@@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.dromara.property.domain.bo.CostChargeReturnFeeBo;
import org.dromara.property.domain.vo.CostHouseChargeDetailVo;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
@@ -80,6 +81,10 @@ public class CostHouseChargeController extends BaseController {
public R<Void> add(@Validated(AddGroup.class) @RequestBody CostHouseChargeBo bo) {
return toAjax(costHouseChargeService.insertByBo(bo));
}
@PostMapping("/returnFee")
public R<Void> returnFree( @RequestBody CostChargeReturnFeeBo bo) {
return toAjax(costHouseChargeService.returnFree(bo));
}
/**
* 修改房屋收费

View File

@@ -59,7 +59,10 @@ public class CostCarCharge extends TenantEntity {
* 状态
*/
private String state;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 收费项目
*/

View File

@@ -4,6 +4,8 @@ import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -33,12 +35,18 @@ public class CostHouseCharge extends TenantEntity {
* 房屋
*/
private Long roomId;
/**
* 业主
*/
private Long personId;
/**
* 收费项目
*/
private Long costItemsId;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 支付方式
*/
@@ -52,7 +60,7 @@ public class CostHouseCharge extends TenantEntity {
/**
* 应收金额
*/
private Long amountReceivable;
private BigDecimal amountReceivable;
/**
* 计费开始时间

View File

@@ -1,5 +1,6 @@
package org.dromara.property.domain;
import lombok.experimental.Accessors;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
@@ -17,6 +18,7 @@ import java.io.Serial;
* @date 2025-07-17
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@TableName("cost_pay_fee_audit")
public class CostPayFeeAudit extends TenantEntity {
@@ -31,9 +33,13 @@ public class CostPayFeeAudit extends TenantEntity {
private Long id;
/**
* 房屋收费id
* 收费id
*/
private Long houseChargeId;
private Long chargeId;
/**
* 收费类型
*/
private String chargeType;
/**
* 费用项目id
@@ -62,8 +68,6 @@ public class CostPayFeeAudit extends TenantEntity {
/**
* 缴费时间
*/
private Date payTime;

View File

@@ -1,9 +1,12 @@
package org.dromara.property.domain;
import lombok.experimental.Accessors;
import org.dromara.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
@@ -16,6 +19,7 @@ import java.io.Serial;
* @date 2025-07-17
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@TableName("cost_return_pay_fee")
public class CostReturnPayFee extends TenantEntity {
@@ -28,7 +32,14 @@ public class CostReturnPayFee extends TenantEntity {
*/
@TableId(value = "id")
private Long id;
/**
* 收费id
*/
private Long chargeId;
/**
* 收费类型
*/
private String chargeType;
/**
* 退款单号
*/
@@ -57,7 +68,7 @@ public class CostReturnPayFee extends TenantEntity {
/**
* 支付金额
*/
private Long payAcount;
private BigDecimal payAcount;
/**
* 支付时间
@@ -74,10 +85,5 @@ public class CostReturnPayFee extends TenantEntity {
*/
private String remark;
/**
* 搜索值
*/
private String searchValue;
}

View File

@@ -37,6 +37,7 @@ public class CostCarChargeBo extends BaseEntity {
/**
* 业主
*/
@NotNull(message = "业主不能为空", groups = { AddGroup.class, EditGroup.class })
private Long personId;
/**
@@ -49,7 +50,10 @@ public class CostCarChargeBo extends BaseEntity {
* 车位
*/
private String location;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 状态
*/

View File

@@ -0,0 +1,37 @@
package org.dromara.property.domain.bo;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
/**
* @Author:yuyongle
* @Date:2025/7/19 13:50
* @Description:
**/
@Data
public class CostChargeReturnFeeBo {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = { EditGroup.class })
private Long id;
/**
* 业主
*/
@NotNull(message = "业主不能为空", groups = { AddGroup.class, EditGroup.class })
private Long personId;
/**
* 收费项目
*/
@NotNull(message = "收费项目不能为空", groups = { AddGroup.class, EditGroup.class })
private Long costItemsId;
/**
* 退款原因
*/
@NotNull(message = "退款原因不能为空", groups = { AddGroup.class, EditGroup.class })
private String reason;
}

View File

@@ -1,17 +1,16 @@
package org.dromara.property.domain.bo;
import org.dromara.property.domain.CostHouseCharge;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.property.domain.CostHouseCharge;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 房屋收费业务对象 cost_house_charge
@@ -35,13 +34,22 @@ public class CostHouseChargeBo extends BaseEntity {
*/
@NotNull(message = "房屋不能为空", groups = { AddGroup.class, EditGroup.class })
private Long roomId;
/**
* 业主
*/
@NotNull(message = "业主不能为空", groups = { AddGroup.class, EditGroup.class })
private Long personId;
/**
* 收费项目
*/
@NotNull(message = "收费项目不能为空", groups = { AddGroup.class, EditGroup.class })
private Long costItemsId;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 支付方式
*/

View File

@@ -31,10 +31,13 @@ public class CostPayFeeAuditBo extends BaseEntity {
private Long id;
/**
* 房屋收费id
* 收费id
*/
@NotNull(message = "房屋收费id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long houseChargeId;
private Long chargeId;
/**
* 收费类型
*/
private String chargeType;
/**
* 费用项目id
@@ -65,12 +68,7 @@ public class CostPayFeeAuditBo extends BaseEntity {
@NotNull(message = "应收金额不能为空", groups = { AddGroup.class, EditGroup.class })
private BigDecimal receivableAmount;
/**
* 缴费时间
*/
@NotNull(message = "缴费时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date payTime;
/**

View File

@@ -9,6 +9,7 @@ import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import org.dromara.property.domain.CostReturnPayFee;
import java.math.BigDecimal;
import java.util.Date;
/**
@@ -60,12 +61,11 @@ public class CostReturnPayFeeBo extends BaseEntity {
/**
* 支付金额
*/
private Long payAcount;
private BigDecimal payAcount;
/**
* 支付时间
*/
@NotNull(message = "支付时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date payTime;
/**

View File

@@ -0,0 +1,44 @@
package org.dromara.property.domain.enums;
import lombok.Data;
import lombok.Getter;
/**
* @Author:yuyongle
* @Date:2025/7/19 11:33
* @Description:
**/
@Getter
public enum ChargeStatusEnum {
/**
* 缴费待审核
*/
PAYMENT_IS_SUBJECT_TO_REVIEW("缴费待审核", "1"),
/**
* 月/天
*/
THE_PAYMENT_WAS_APPROVED("缴费审核通过", "2"),
THE_PAYMENT_REVIEW_FAILED("缴费审核不通过", "3"),
PAID_FEE("已缴费", "4"),
REFUND_PENDING_REVIEW("退费待审核", "5"),
THE_REFUND_HAS_BEEN_APPROVED("已退费审核通过", "6"),
THE_REFUND_REVIEW_IS_NOT_PASSED("退费审核不通过", "7");
private final String name;
private final String value;
ChargeStatusEnum(String name, String value) {
this.name = name;
this.value = value;
}
public String getName() {
return this.name;
}
public String getValue() {
return this.value;
}
}

View File

@@ -71,6 +71,10 @@ public class CostCarChargeVo implements Serializable {
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "wy_cszt")
private String state;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 收费项目

View File

@@ -9,6 +9,7 @@ import org.dromara.property.domain.CostItems;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
@@ -34,13 +35,24 @@ public class CostHouseChargeDetailVo implements Serializable {
*/
@ExcelProperty(value = "房屋")
private Long roomId;
/**
* 业主
*/
private Long personId;
/**
* 业主姓名
*/
private String personName;
/**
* 收费项目
*/
@ExcelProperty(value = "收费项目")
private Long costItemsId;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 支付方式
*/
@@ -57,7 +69,7 @@ public class CostHouseChargeDetailVo implements Serializable {
* 应收金额
*/
@ExcelProperty(value = "应收金额")
private Long amountReceivable;
private BigDecimal amountReceivable;
/**
* 计费开始时间

View File

@@ -1,5 +1,6 @@
package org.dromara.property.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.property.domain.CostHouseCharge;
@@ -41,7 +42,10 @@ public class CostHouseChargeVo implements Serializable {
*/
@ExcelProperty(value = "房屋")
private Long roomId;
/**
* 业主
*/
private Long personId;
/**
* 收费项目
*/
@@ -59,12 +63,15 @@ public class CostHouseChargeVo implements Serializable {
*/
@ExcelProperty(value = "支付周期")
private String chargeCycle;
/**
* 缴费状态
*/
private String chargeStatus;
/**
* 应收金额
*/
@ExcelProperty(value = "应收金额")
private Long amountReceivable;
private BigDecimal amountReceivable;
/**
* 计费开始时间

View File

@@ -37,10 +37,13 @@ public class CostPayFeeAuditVo implements Serializable {
private Long id;
/**
* 房屋收费id
* 收费id
*/
@ExcelProperty(value = "房屋收费id")
private Long houseChargeId;
private Long chargeId;
/**
* 收费类型
*/
private String chargeType;
/**
* 费用类型
*/

View File

@@ -8,6 +8,7 @@ import org.dromara.property.domain.CostReturnPayFee;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@@ -44,6 +45,7 @@ public class CostReturnPayFeeVo implements Serializable {
@ExcelProperty(value = "支付单号")
private String payNo;
/**
* 退款原因
*/
@@ -66,7 +68,7 @@ public class CostReturnPayFeeVo implements Serializable {
* 支付金额
*/
@ExcelProperty(value = "支付金额")
private Long payAcount;
private BigDecimal payAcount;
/**
* 支付时间

View File

@@ -111,6 +111,16 @@ public class RemoteFloorServiceImpl implements RemoteFloorService {
@Override
public List<RemoteFloorVo> queryByUnitId(Long unitId){
List<TbFloorVo> tbFloorVo = floorService.queryByUnitId(unitId);
return MapstructUtils.convert(tbFloorVo, RemoteFloorVo.class);
List<RemoteFloorVo> remoteFloorVos = new ArrayList<>();
tbFloorVo.forEach(item -> {
RemoteFloorVo remoteFloorVo = new RemoteFloorVo();
remoteFloorVo.setId(item.getId());
remoteFloorVo.setFloorName(item.getFloorName());
remoteFloorVo.setFloorNumber(item.getFloorNumber());
remoteFloorVos.add(remoteFloorVo);
});
return remoteFloorVos;
}
}

View File

@@ -1,6 +1,6 @@
package org.dromara.property.service;
import org.dromara.property.domain.CostCarCharge;
import org.dromara.property.domain.bo.CostChargeReturnFeeBo;
import org.dromara.property.domain.vo.CostCarChargeVo;
import org.dromara.property.domain.bo.CostCarChargeBo;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -50,6 +50,12 @@ public interface ICostCarChargeService {
*/
Boolean insertByBo(CostCarChargeBo bo);
/**
* 车辆退费
* @param bo
* @return
*/
Boolean returnFree(CostChargeReturnFeeBo bo);
/**
* 修改费用-车辆收费
*

View File

@@ -1,6 +1,6 @@
package org.dromara.property.service;
import org.dromara.property.domain.CostHouseCharge;
import org.dromara.property.domain.bo.CostChargeReturnFeeBo;
import org.dromara.property.domain.vo.CostHouseChargeDetailVo;
import org.dromara.property.domain.vo.CostHouseChargeVo;
import org.dromara.property.domain.bo.CostHouseChargeBo;
@@ -51,6 +51,14 @@ public interface ICostHouseChargeService {
*/
Boolean insertByBo(CostHouseChargeBo bo);
/**
* 房屋退费
*
* @param bo 房屋退费
* @return 是否修改成功
*/
Boolean returnFree(CostChargeReturnFeeBo bo);
/**
* 修改房屋收费
*

View File

@@ -1,5 +1,9 @@
package org.dromara.property.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -9,14 +13,23 @@ 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.dromara.property.domain.CostHouseCharge;
import org.dromara.property.domain.CostPayFeeAudit;
import org.dromara.property.domain.CostReturnPayFee;
import org.dromara.property.domain.bo.CostChargeReturnFeeBo;
import org.dromara.property.domain.enums.ChargeStatusEnum;
import org.dromara.property.domain.vo.CostHouseChargeVo;
import org.dromara.property.domain.vo.CostItemsVo;
import org.dromara.property.mapper.CostItemsMapper;
import org.dromara.property.mapper.CostPayFeeAuditMapper;
import org.dromara.property.mapper.CostReturnPayFeeMapper;
import org.springframework.stereotype.Service;
import org.dromara.property.domain.bo.CostCarChargeBo;
import org.dromara.property.domain.vo.CostCarChargeVo;
import org.dromara.property.domain.CostCarCharge;
import org.dromara.property.mapper.CostCarChargeMapper;
import org.dromara.property.service.ICostCarChargeService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
@@ -36,6 +49,8 @@ public class CostCarChargeServiceImpl implements ICostCarChargeService {
private final CostCarChargeMapper baseMapper;
private final CostItemsMapper costItemsMapper;
private final CostPayFeeAuditMapper costPayFeeAuditMapper;
private final CostReturnPayFeeMapper costReturnPayFeeMapper;
/**
@@ -98,6 +113,7 @@ public class CostCarChargeServiceImpl implements ICostCarChargeService {
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(CostCarChargeBo bo) {
CostCarCharge add = MapstructUtils.convert(bo, CostCarCharge.class);
CostItemsVo costItemsVo = costItemsMapper.selectVoById(add.getCostItemsId());
@@ -107,10 +123,46 @@ public class CostCarChargeServiceImpl implements ICostCarChargeService {
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
//新增缴费记录
var CostPayFeeAudit = new CostPayFeeAudit()
.setChargeId(add.getId())
.setChargeType("2")
.setItemId(costItemsVo.getId())
.setStartTime(add.getStarTime())
.setEndTime(add.getEndTime())
.setReceivableAmount(add.getAmountReceivable())
.setState("0");
costPayFeeAuditMapper.insert(CostPayFeeAudit);
}
return flag;
}
/**
* 车辆退费
* @param bo
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean returnFree(CostChargeReturnFeeBo bo) {
CostCarCharge costCarCharge = baseMapper.selectById(bo.getId());
Assert.isTrue(ObjectUtil.isNotEmpty(costCarCharge),"该费用不存在");
var CostReturnPayFee = new CostReturnPayFee()
.setChargeId(costCarCharge.getId())
.setChargeType("2")
.setItemId(costCarCharge.getCostItemsId())
.setReturnNo(RandomUtil.randomNumbers(11))
.setReason(bo.getReason())
.setUserId(costCarCharge.getPersonId())
.setPayNo(costCarCharge.getId().toString())
.setPayAcount(costCarCharge.getAmountReceivable())
.setState("0")
;
costReturnPayFeeMapper.insert(CostReturnPayFee);
costCarCharge.setChargeStatus(ChargeStatusEnum.REFUND_PENDING_REVIEW.getValue());
return baseMapper.updateById(costCarCharge) > 0;
}
/**
* 修改费用-车辆收费
*

View File

@@ -1,6 +1,9 @@
package org.dromara.property.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -10,17 +13,17 @@ 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.dromara.property.domain.vo.CostHouseChargeDetailVo;
import org.dromara.property.domain.vo.CostItemsVo;
import org.dromara.property.domain.vo.TbRoomVo;
import org.dromara.property.mapper.CostItemsMapper;
import org.dromara.property.mapper.TbRoomMapper;
import org.dromara.property.domain.CostPayFeeAudit;
import org.dromara.property.domain.CostReturnPayFee;
import org.dromara.property.domain.bo.CostChargeReturnFeeBo;
import org.dromara.property.domain.enums.ChargeStatusEnum;
import org.dromara.property.domain.vo.*;
import org.dromara.property.mapper.*;
import org.springframework.stereotype.Service;
import org.dromara.property.domain.bo.CostHouseChargeBo;
import org.dromara.property.domain.vo.CostHouseChargeVo;
import org.dromara.property.domain.CostHouseCharge;
import org.dromara.property.mapper.CostHouseChargeMapper;
import org.dromara.property.service.ICostHouseChargeService;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
@@ -42,7 +45,9 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
private final CostHouseChargeMapper baseMapper;
private final CostItemsMapper costItemsMapper;
private final TbRoomMapper tbRoomMapper;
private final CostPayFeeAuditMapper costPayFeeAuditMapper;
private final CostReturnPayFeeMapper costReturnPayFeeMapper;
private final ResidentPersonMapper residentPersonMapper;
/**
* 查询房屋收费
*
@@ -50,13 +55,15 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
* @return 房屋收费
*/
@Override
public CostHouseChargeDetailVo queryById(Long id){
public CostHouseChargeDetailVo queryById(Long id) {
CostHouseChargeVo costHouseChargeVo = baseMapper.selectVoById(id);
CostHouseChargeDetailVo costHouseChargeDetailVo = BeanUtil.copyProperties(costHouseChargeVo, CostHouseChargeDetailVo.class);
CostItemsVo costItemsVo = costItemsMapper.selectVoById(costHouseChargeDetailVo.getCostItemsId());
costHouseChargeDetailVo.setCostItemsVo( costItemsVo );
costHouseChargeDetailVo.setCostItemsVo(costItemsVo);
TbRoomVo tbRoomVo = tbRoomMapper.selectVoById(costHouseChargeDetailVo.getRoomId());
costHouseChargeDetailVo.setRoomVo(tbRoomVo);
ResidentPersonVo residentPersonVo = residentPersonMapper.selectVoById(costHouseChargeVo.getPersonId());
costHouseChargeDetailVo.setPersonName(residentPersonVo.getUserName());
return costHouseChargeDetailVo;
}
@@ -92,7 +99,6 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
lqw.orderByAsc(CostHouseCharge::getId);
lqw.eq(bo.getRoomId() != null, CostHouseCharge::getRoomId, bo.getRoomId());
lqw.eq(bo.getCostItemsId() != null, CostHouseCharge::getCostItemsId, bo.getCostItemsId());
lqw.eq(StringUtils.isNotBlank(bo.getPayType()), CostHouseCharge::getPayType, bo.getPayType());
lqw.eq(StringUtils.isNotBlank(bo.getChargeCycle()), CostHouseCharge::getChargeCycle, bo.getChargeCycle());
lqw.eq(bo.getAmountReceivable() != null, CostHouseCharge::getAmountReceivable, bo.getAmountReceivable());
lqw.eq(bo.getStartTime() != null, CostHouseCharge::getStartTime, bo.getStartTime());
@@ -109,6 +115,7 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByBo(CostHouseChargeBo bo) {
CostHouseCharge add = MapstructUtils.convert(bo, CostHouseCharge.class);
//查询房间面积
@@ -117,26 +124,63 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
CostItemsVo costItemsVo = costItemsMapper.selectVoById(add.getCostItemsId());
BigDecimal unitPrice = costItemsVo.getUnitPrice();
//向上取整
if(costItemsVo.getRoundingMode().equals("1")){
add.setAmountReceivable(area.multiply(unitPrice).add(costItemsVo.getSurcharge()).setScale(Integer.valueOf(costItemsVo.getCurrencyDecimals()), BigDecimal.ROUND_UP).longValue());
if (costItemsVo.getRoundingMode().equals("1")) {
add.setAmountReceivable(area.multiply(unitPrice).add(costItemsVo.getSurcharge()).setScale(Integer.valueOf(costItemsVo.getCurrencyDecimals()), BigDecimal.ROUND_UP));
}
//向下取整
if(costItemsVo.getRoundingMode().equals("2")){
add.setAmountReceivable( area.multiply(unitPrice).add(costItemsVo.getSurcharge()).setScale(Integer.valueOf(costItemsVo.getCurrencyDecimals()), BigDecimal.ROUND_DOWN).longValue());
if (costItemsVo.getRoundingMode().equals("2")) {
add.setAmountReceivable(area.multiply(unitPrice).add(costItemsVo.getSurcharge()).setScale(Integer.valueOf(costItemsVo.getCurrencyDecimals()), BigDecimal.ROUND_DOWN));
}
//四舍五入
if(costItemsVo.getRoundingMode().equals("0")){
add.setAmountReceivable(area.multiply(unitPrice).add(costItemsVo.getSurcharge()).setScale( Integer.valueOf(costItemsVo.getCurrencyDecimals()), RoundingMode.HALF_UP).longValue());
if (costItemsVo.getRoundingMode().equals("0")) {
add.setAmountReceivable(area.multiply(unitPrice).add(costItemsVo.getSurcharge()).setScale(Integer.valueOf(costItemsVo.getCurrencyDecimals()), RoundingMode.HALF_UP));
}
add.setChargeStatus(ChargeStatusEnum.PAYMENT_IS_SUBJECT_TO_REVIEW.getValue());
//area
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
//新增缴费记录
var CostPayFeeAudit = new CostPayFeeAudit()
.setChargeId(add.getId())
.setChargeType("1")
.setItemId(costItemsVo.getId())
.setStartTime(add.getStartTime())
.setEndTime(add.getEndTime())
.setReceivableAmount(add.getAmountReceivable())
.setState("0");
costPayFeeAuditMapper.insert(CostPayFeeAudit);
}
return flag;
}
/**
* 房屋退费
*
* @param bo 房屋退费
* @return 是否退费成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean returnFree(CostChargeReturnFeeBo bo) {
CostHouseChargeVo costHouseChargeVo = baseMapper.selectVoById(bo.getId());
Assert.isTrue(ObjectUtil.isNotEmpty(costHouseChargeVo),"该费用不存在");
var CostReturnPayFee = new CostReturnPayFee().setItemId(costHouseChargeVo.getCostItemsId())
.setReturnNo(RandomUtil.randomNumbers(11))
.setReason(bo.getReason())
.setItemId(costHouseChargeVo.getCostItemsId())
.setUserId(costHouseChargeVo.getPersonId())
.setPayNo(costHouseChargeVo.getId().toString())
.setPayAcount(costHouseChargeVo.getAmountReceivable())
.setState("0")
;
boolean flag = costReturnPayFeeMapper.insert(CostReturnPayFee) > 0;
CostHouseCharge costHouseCharge = BeanUtil.copyProperties(costHouseChargeVo, CostHouseCharge.class);
costHouseCharge.setChargeStatus(ChargeStatusEnum.REFUND_PENDING_REVIEW.getValue());
return baseMapper.updateById(costHouseCharge) > 0;
}
/**
* 修改房屋收费
*
@@ -144,6 +188,7 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
* @return 是否修改成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(CostHouseChargeBo bo) {
CostHouseCharge update = MapstructUtils.convert(bo, CostHouseCharge.class);
validEntityBeforeSave(update);
@@ -153,7 +198,7 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(CostHouseCharge entity){
private void validEntityBeforeSave(CostHouseCharge entity) {
//TODO 做一些数据校验,如唯一约束
}
@@ -165,8 +210,10 @@ public class CostHouseChargeServiceImpl implements ICostHouseChargeService {
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;

View File

@@ -1,5 +1,6 @@
package org.dromara.property.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import org.checkerframework.checker.units.qual.C;
import org.dromara.common.core.utils.MapstructUtils;
@@ -11,12 +12,13 @@ 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.dromara.property.domain.CostCarCharge;
import org.dromara.property.domain.CostHouseCharge;
import org.dromara.property.domain.CostPayFeeAudit;
import org.dromara.property.domain.bo.CostPayFeeAuditBo;
import org.dromara.property.domain.enums.ChargeStatusEnum;
import org.dromara.property.domain.vo.*;
import org.dromara.property.mapper.CostItemsMapper;
import org.dromara.property.mapper.CostPayFeeAuditMapper;
import org.dromara.property.mapper.TbRoomMapper;
import org.dromara.property.mapper.*;
import org.dromara.property.service.ICostPayFeeAuditService;
import org.springframework.stereotype.Service;
@@ -40,6 +42,8 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
private final CostPayFeeAuditMapper baseMapper;
private final CostItemsMapper costItemsMapper;
private final TbRoomMapper roomMapper;
private final CostHouseChargeMapper coinHouseChargeMapper;
private final CostCarChargeMapper costCarChargeMapper;
/**
* 查询费用-缴费审核
@@ -49,7 +53,13 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
*/
@Override
public CostPayFeeAuditVo queryById(Long id){
return baseMapper.selectVoById(id);
CostPayFeeAuditVo costPayFeeAuditVo = baseMapper.selectVoById(id);
CostItemsVo costItemsVo = costItemsMapper.selectVoById(costPayFeeAuditVo.getItemId());
costPayFeeAuditVo.setChargeItem(ObjectUtil.isNotEmpty(costItemsVo)? costItemsVo.getChargeItem() :null );
costPayFeeAuditVo.setChargeCycle(ObjectUtil.isNotEmpty(costItemsVo)? costItemsVo.getChargeCycle() :null );
//TbRoomVo roomVo = roomMapper.selectVoById(costPayFeeAuditVo.getChargeId());
//costPayFeeAuditVo.setRoomNumber(ObjectUtil.isNotEmpty(roomVo)? roomVo.getRoomNumber() :null );
return costPayFeeAuditVo;
}
/**
@@ -63,12 +73,15 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
public TableDataInfo<CostPayFeeAuditVo> queryPageList(CostPayFeeAuditBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<CostPayFeeAudit> lqw = buildQueryWrapper(bo);
Page<CostPayFeeAuditVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
if(CollUtil.isEmpty(result.getRecords())){
return TableDataInfo.build(result);
}
List<Long> itemIdList = result.getRecords().stream()
.map(vo -> vo.getItemId())
.distinct()
.collect(Collectors.toList());
List<Long> roomIdList = result.getRecords().stream()
.map(vo -> vo.getHouseChargeId())
.map(vo -> vo.getChargeId())
.distinct()
.collect(Collectors.toList());
List<CostItemsVo> costItemsVoList = costItemsMapper.selectVoByIds(itemIdList);
@@ -81,7 +94,7 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
s.setCostType(ObjectUtil.isNotEmpty(costItemsVo)?costItemsVo.getCostType():null);
s.setChargeCycle(ObjectUtil.isNotEmpty(costItemsVo)?costItemsVo.getChargeCycle():null);
TbRoomVo tbRoomVo = roomVoList.stream()
.filter(vo -> vo.getId() != null && vo.getId().equals(s.getHouseChargeId())).findFirst().orElse(null);
.filter(vo -> vo.getId() != null && vo.getId().equals(s.getChargeId())).findFirst().orElse(null);
s.setRoomNumber(ObjectUtil.isNotEmpty(tbRoomVo)?tbRoomVo.getRoomNumber():null);
costPayFeeAuditVoList.add(s);
@@ -105,7 +118,7 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<CostPayFeeAudit> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(CostPayFeeAudit::getId);
lqw.eq(bo.getHouseChargeId() != null, CostPayFeeAudit::getHouseChargeId, bo.getHouseChargeId());
lqw.eq(bo.getChargeId() != null, CostPayFeeAudit::getChargeId, bo.getChargeId());
lqw.eq(bo.getItemId() != null, CostPayFeeAudit::getItemId, bo.getItemId());
lqw.eq(bo.getStartTime() != null, CostPayFeeAudit::getStartTime, bo.getStartTime());
lqw.eq(bo.getEndTime() != null, CostPayFeeAudit::getEndTime, bo.getEndTime());
@@ -134,7 +147,7 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
}
/**
* 修改费用-缴费审核
* 修改费用-缴费审核修改状态
*
* @param bo 费用-缴费审核
* @return 是否修改成功
@@ -142,7 +155,7 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
@Override
public Boolean updateByBo(CostPayFeeAuditBo bo) {
CostPayFeeAudit update = MapstructUtils.convert(bo, CostPayFeeAudit.class);
validEntityBeforeSave(update);
validEntityBeforeUpdate(update);
return baseMapper.updateById(update) > 0;
}
@@ -152,6 +165,36 @@ public class CostPayFeeAuditServiceImpl implements ICostPayFeeAuditService {
private void validEntityBeforeSave(CostPayFeeAudit entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 修改前的数据校验
*/
private void validEntityBeforeUpdate(CostPayFeeAudit entity){
//TODO 做一些数据校验,如唯一约束
if(entity.getState().equals("1")){
if(entity.getChargeType().equals("1")){
CostHouseCharge costHouseCharge = coinHouseChargeMapper.selectById(entity.getChargeId());
costHouseCharge.setChargeStatus(ChargeStatusEnum.THE_PAYMENT_WAS_APPROVED.getValue());
coinHouseChargeMapper.updateById(costHouseCharge);
}
if(entity.getChargeType().equals("2")){
CostCarCharge costCarCharge = costCarChargeMapper.selectById(entity.getChargeId());
costCarCharge.setChargeStatus(ChargeStatusEnum.THE_PAYMENT_WAS_APPROVED.getValue());
costCarChargeMapper.updateById(costCarCharge);
}
}
if(entity.getState().equals("2")){
if(entity.getChargeType().equals("1")){
CostHouseCharge costHouseCharge = coinHouseChargeMapper.selectById(entity.getChargeId());
costHouseCharge.setChargeStatus(ChargeStatusEnum.THE_PAYMENT_REVIEW_FAILED.getValue());
coinHouseChargeMapper.updateById(costHouseCharge);
}
if(entity.getChargeType().equals("2")){
CostCarCharge costCarCharge = costCarChargeMapper.selectById(entity.getChargeId());
costCarCharge.setChargeStatus(ChargeStatusEnum.THE_PAYMENT_REVIEW_FAILED.getValue());
costCarChargeMapper.updateById(costCarCharge);
}
}
}
/**
* 校验并批量删除费用-缴费审核信息

View File

@@ -9,9 +9,14 @@ 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.dromara.property.domain.CostCarCharge;
import org.dromara.property.domain.CostHouseCharge;
import org.dromara.property.domain.CostReturnPayFee;
import org.dromara.property.domain.bo.CostReturnPayFeeBo;
import org.dromara.property.domain.enums.ChargeStatusEnum;
import org.dromara.property.domain.vo.CostReturnPayFeeVo;
import org.dromara.property.mapper.CostCarChargeMapper;
import org.dromara.property.mapper.CostHouseChargeMapper;
import org.dromara.property.mapper.CostReturnPayFeeMapper;
import org.dromara.property.service.ICostReturnPayFeeService;
import org.springframework.stereotype.Service;
@@ -32,6 +37,8 @@ import java.util.Collection;
public class CostReturnPayFeeServiceImpl implements ICostReturnPayFeeService {
private final CostReturnPayFeeMapper baseMapper;
private final CostHouseChargeMapper coinHouseChargeMapper;
private final CostCarChargeMapper costCarChargeMapper;
/**
* 查询费用-抄类型
@@ -112,7 +119,7 @@ public class CostReturnPayFeeServiceImpl implements ICostReturnPayFeeService {
@Override
public Boolean updateByBo(CostReturnPayFeeBo bo) {
CostReturnPayFee update = MapstructUtils.convert(bo, CostReturnPayFee.class);
validEntityBeforeSave(update);
validEntityBeforeUpdate(update);
return baseMapper.updateById(update) > 0;
}
@@ -122,6 +129,36 @@ public class CostReturnPayFeeServiceImpl implements ICostReturnPayFeeService {
private void validEntityBeforeSave(CostReturnPayFee entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 修改前的数据校验
*/
private void validEntityBeforeUpdate(CostReturnPayFee entity){
//TODO 做一些数据校验,如唯一约束
if(entity.getState().equals("1")){
if(entity.getChargeType().equals("1")){
CostHouseCharge costHouseCharge = coinHouseChargeMapper.selectById(entity.getChargeId());
costHouseCharge.setChargeStatus(ChargeStatusEnum. THE_REFUND_HAS_BEEN_APPROVED.getValue());
coinHouseChargeMapper.updateById(costHouseCharge);
}
if(entity.getChargeType().equals("2")){
CostCarCharge costCarCharge = costCarChargeMapper.selectById(entity.getChargeId());
costCarCharge.setChargeStatus(ChargeStatusEnum.THE_REFUND_HAS_BEEN_APPROVED.getValue());
costCarChargeMapper.updateById(costCarCharge);
}
}
if(entity.getState().equals("2")){
if(entity.getChargeType().equals("1")){
CostHouseCharge costHouseCharge = coinHouseChargeMapper.selectById(entity.getChargeId());
costHouseCharge.setChargeStatus(ChargeStatusEnum.THE_REFUND_REVIEW_IS_NOT_PASSED.getValue());
coinHouseChargeMapper.updateById(costHouseCharge);
}
if(entity.getChargeType().equals("2")){
CostCarCharge costCarCharge = costCarChargeMapper.selectById(entity.getChargeId());
costCarCharge.setChargeStatus(ChargeStatusEnum.THE_REFUND_REVIEW_IS_NOT_PASSED.getValue());
costCarChargeMapper.updateById(costCarCharge);
}
}
}
/**
* 校验并批量删除费用-抄类型信息

View File

@@ -125,7 +125,6 @@ public class InspectionPlanServiceImpl implements IInspectionPlanService {
lqw.eq(StringUtils.isNotBlank(bo.getSignType()), InspectionPlan::getSignType, bo.getSignType());
lqw.eq(StringUtils.isNotBlank(bo.getCanReexamine()), InspectionPlan::getCanReexamine, bo.getCanReexamine());
lqw.like(StringUtils.isNotBlank(bo.getState()), InspectionPlan::getState, bo.getState());
lqw.eq(StringUtils.isNotBlank(bo.getSearchValue()), InspectionPlan::getSearchValue, bo.getSearchValue());
return lqw;
}
@@ -147,8 +146,9 @@ public class InspectionPlanServiceImpl implements IInspectionPlanService {
if (CollectionUtil.isNotEmpty(inspectionPlanStaffBoList)) {
for (InspectionPlanStaffBo staffBo : inspectionPlanStaffBoList) {
staffBo.setInspectionPlanId(add.getId());
InspectionPlanStaff convert = MapstructUtils.convert(staffBo, InspectionPlanStaff.class);
inspectionPlanStaffMapper.insert(convert);
}
inspectionPlanStaffMapper.insertBatch(BeanUtil.copyToList(inspectionPlanStaffBoList, InspectionPlanStaff.class));
}
}
return flag;

View File

@@ -122,6 +122,12 @@
<version>4.5.2_1</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
</dependencies>
<build>

View File

@@ -1,5 +1,6 @@
package org.dromara.sis.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.sis.domain.SisAuthRecord;
import org.dromara.sis.domain.vo.SisAuthRecordVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@@ -12,6 +13,7 @@ import java.util.List;
* @author lsm
* @since 2025-07-14
*/
@Mapper
public interface SisAuthRecordMapper extends BaseMapperPlus<SisAuthRecord, SisAuthRecordVo> {
List<SisAuthRecordVo> checkAuth(Long personId);
}

View File

@@ -0,0 +1,20 @@
package org.dromara.sis.sdk.smartDevices.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author lsm
* @apiNote PowerFrame
* @since 2025/7/20
*/
@Data
@AllArgsConstructor
public class PowerFrame {
private byte[] address;
private byte controlCode;
private byte[] data;
}

View File

@@ -0,0 +1,139 @@
package org.dromara.sis.sdk.smartDevices.utils;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
/**
* @author lsm
* @apiNote LightingUtil
* @since 2025/7/20
*/
@Slf4j
public class LightingUtil {
private final MqttClient mqttClient;
private final String productKey;
private final String deviceName;
private final Gson gson = new Gson();
// 初始化连接参数
public LightingUtil(String brokerUrl, String productKey, String deviceName,
String username, String password) throws MqttException {
this.productKey = productKey;
this.deviceName = deviceName;
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(username);
options.setPassword(password.toCharArray());
options.setCleanSession(true);
mqttClient = new MqttClient(brokerUrl, deviceName, new MemoryPersistence());
mqttClient.connect(options);
// 订阅网关上报主题
String subscribeTopic = "/sys/" + productKey + "/+/thing/event/+/post";
mqttClient.subscribe(subscribeTopic, this::handleIncomingMessage);
}
// 基础指令构造
private JsonObject createBaseCommand(int code, String area, String address, String action) {
JsonObject command = new JsonObject();
command.addProperty("code", code);
command.addProperty("deviceName", deviceName);
command.addProperty("area", area);
command.addProperty("address", address);
command.addProperty("action", action);
command.addProperty("identity", "");
return command;
}
// 灯具控制指令
public void sendLightCommand(int code, String area, String address, String action, String params)
throws MqttException {
JsonObject command = createBaseCommand(code, area, address, action);
if (params != null) command.addProperty("params", params);
String topic = "/" + productKey + "/" + deviceName + "/user/get";
mqttClient.publish(topic, new MqttMessage(gson.toJson(command).getBytes()));
}
// 常用快捷方法
public void turnOnLight(String area, String groupAddress) throws MqttException {
sendLightCommand(200, area, groupAddress, "lightOn", null);
}
public void turnOffLight(String area, String groupAddress) throws MqttException {
sendLightCommand(200, area, groupAddress, "lightOff", null);
}
public void setBrightness(String area, String address, int brightness) throws MqttException {
sendLightCommand(200, area, address, "setHighBright", String.valueOf(brightness));
}
// 上报数据处理
private void handleIncomingMessage(String topic, MqttMessage message) {
try {
JsonObject payload = gson.fromJson(new String(message.getPayload()), JsonObject.class);
String method = payload.get("method").getAsString();
switch (method) {
case "thing.event.heartbeat.post":
processHeartbeat(payload.getAsJsonObject("params"));
break;
case "thing.event.consumption.post":
processEnergyData(payload.getAsJsonObject("params"));
break;
case "thing.event.trigger.post":
processSensorTrigger(payload.getAsJsonObject("params"));
break;
// 添加其他事件处理...
}
} catch (Exception e) {
log.error("MQTT消息处理异常topic: {}", topic, e);
}
}
// 心跳处理
private void processHeartbeat(JsonObject params) {
JsonObject value = params.getAsJsonObject("value");
String uuid = value.get("uuid").getAsString();
String area = value.get("area").getAsString();
System.out.println("设备在线: " + uuid + " | 区域: " + area);
}
// 能耗处理
private void processEnergyData(JsonObject params) {
JsonObject value = params.getAsJsonObject("value");
String uuid = value.get("uuid").getAsString();
double power = value.get("power").getAsDouble();
System.out.println("能耗报告: " + uuid + " | 功率: " + power + "W");
}
// 传感器触发处理
private void processSensorTrigger(JsonObject params) {
JsonObject value = params.getAsJsonObject("value");
long trigTime = value.get("trig_time").getAsLong();
String area = value.get("area").getAsString();
System.out.println("传感器触发: 区域=" + area + " | 时间=" + trigTime);
}
// 网关管理
public void rebootGateway(int delaySeconds) throws MqttException {
JsonObject command = createBaseCommand(400, "00 00", "FF FF", "reboot");
command.addProperty("params", String.valueOf(delaySeconds));
String topic = "/" + productKey + "/" + deviceName + "/user/get";
mqttClient.publish(topic, new MqttMessage(gson.toJson(command).getBytes()));
}
// 关闭连接
public void disconnect() throws MqttException {
mqttClient.disconnect();
}
}

View File

@@ -0,0 +1,179 @@
package org.dromara.sis.sdk.smartDevices.utils;
import org.dromara.sis.sdk.smartDevices.domain.PowerFrame;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
/**
* @author lsm
* @apiNote PowerMeterUtil
* @since 2025/7/20
*/
public class PowerMeterUtil {
// 协议常量定义
public static final byte FRAME_START = 0x68;
public static final byte FRAME_END = 0x16;
public static final byte[] PREAMBLE = {(byte) 0xFE, (byte) 0xFE, (byte) 0xFE, (byte) 0xFE};
public static final int ADDR_LENGTH = 6;
public static final int MAX_READ_DATA_LEN = 200;
public static final int MAX_WRITE_DATA_LEN = 50;
// 控制码功能定义
public static final byte CTRL_BROADCAST_TIME = 0x08;
public static final byte CTRL_READ_DATA = 0x11;
public static final byte CTRL_READ_FOLLOW_DATA = 0x12;
public static final byte CTRL_WRITE_DATA = 0x14;
public static final byte CTRL_TRIP_CONTROL = 0x1C;
public static final byte CTRL_OUTPUT_CONTROL = 0x1D;
// 地址通配符
public static final byte ADDR_WILDCARD = (byte) 0xAA;
/**
* 构建基础帧结构
*
* @param address 6字节地址(高位在前,低位在后)
* @param ctrlCode 控制码
* @param data 原始数据域(未加33H)
* @param isEncode 是否进行数据域处理
* @return 完整帧数据
*/
public byte[] buildFrame(byte[] address, byte ctrlCode, byte[] data, boolean isEncode) {
if (address.length != ADDR_LENGTH) {
throw new IllegalArgumentException("Address must be 6 bytes");
}
// 处理数据域每个字节加0x33
byte[] processedData = processDataDomain(data, isEncode);
// 计算数据域长度
int dataLen = (data != null) ? data.length : 0;
if (dataLen > MAX_READ_DATA_LEN) {
throw new IllegalArgumentException("Data length exceeds max limit");
}
// 计算总帧长度: 起始符(1) + 地址(6) + 起始符(1) + 控制码(1) + 长度(1) + 数据域 + 校验(1) + 结束符(1)
int totalLength = 11 + dataLen;
ByteBuffer buffer = ByteBuffer.allocate(totalLength)
.order(ByteOrder.LITTLE_ENDIAN);
// 地址域处理 (传输顺序: 低字节在前)
byte[] reversedAddr = reverseAddress(address);
// 构建帧
buffer.put(FRAME_START)
.put(reversedAddr)
.put(FRAME_START)
.put(ctrlCode)
.put((byte) dataLen);
if (dataLen > 0) {
buffer.put(processedData);
}
// 计算校验码 (从第一个0x68到数据域结束)
byte[] frameWithoutCs = Arrays.copyOf(buffer.array(), buffer.position());
byte cs = calculateChecksum(frameWithoutCs);
buffer.put(cs)
.put(FRAME_END);
return buffer.array();
}
/**
* 解析接收到的帧
* @param frame 完整帧数据(包含前导符)
* @return 解析结果对象
*/
public PowerFrame parseFrame(byte[] frame) {
// 跳过前导符 (0-3)
int startIndex = findFrameStart(frame);
if (startIndex == -1) {
throw new IllegalArgumentException("无效帧:未找到起始标记");
}
// 基本长度检查
if (frame.length < startIndex + 12) {
throw new IllegalArgumentException("接受帧太短");
}
// 提取地址域 (传输顺序: 低字节在前)
byte[] reversedAddr = Arrays.copyOfRange(frame, startIndex + 1, startIndex + 7);
byte[] address = reverseAddress(reversedAddr);
// 控制码
byte ctrlCode = frame[startIndex + 8];
// 数据域长度
int dataLen = frame[startIndex + 9] & 0xFF;
// 数据域位置
int dataStart = startIndex + 10;
int dataEnd = dataStart + dataLen;
// 校验位位置
int endPos = dataEnd + 1;
// 验证结束符
if (frame[endPos] != FRAME_END) {
throw new IllegalArgumentException("无效的帧结束标记");
}
// 提取原始数据域 (含33H处理)
byte[] rawData = Arrays.copyOfRange(frame, dataStart, dataEnd);
byte[] processedData = processDataDomain(rawData, false);
// 验证校验和
byte calculatedCs = calculateChecksum(Arrays.copyOfRange(frame, startIndex, dataEnd));
byte receivedCs = frame[dataEnd];
if (calculatedCs != receivedCs) {
throw new IllegalArgumentException("校验和不匹配");
}
return new PowerFrame(address, ctrlCode, processedData);
}
// 数据处理域:加/减33H
private byte[] processDataDomain(byte[] data, boolean isEncode) {
if (data == null || data.length == 0) return data;
byte[] result = new byte[data.length];
for (int i = 0; i < data.length; i++) {
result[i] = (byte) (isEncode ? (data[i] + 0x33) : (data[i] - 0x33));
}
return result;
}
// 地址反转 (传输顺序处理)
private byte[] reverseAddress(byte[] address) {
byte[] reversed = new byte[address.length];
for (int i = 0; i < address.length; i++) {
reversed[i] = address[address.length - 1 - i];
}
return reversed;
}
// 计算校验和 (模256和)
private byte calculateChecksum(byte[] data) {
int sum = 0;
for (byte b : data) {
sum = (sum + (b & 0xFF)) & 0xFF;
}
return (byte) sum;
}
// 在帧数据中查找起始符
private int findFrameStart(byte[] data) {
for (int i = 0; i < data.length - 1; i++) {
if (data[i] == FRAME_START && data[i + 1] != FRAME_START) {
return i;
}
}
return -1;
}
}

View File

@@ -0,0 +1,168 @@
package org.dromara.sis.sdk.smartDevices.utils;
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
* @author lsm
* @apiNote WaterMeterUtil
* @since 2025/7/20
*/
public class WaterMeterUtil {
// 协议常量定义
public static final byte PREAMBLE = (byte) 0xFE;
public static final byte FRAME_START = 0x68;
public static final byte FRAME_END = 0x16;
public static final byte WATER_METER_TYPE = 0x10;
public static final byte CTRL_READ = 0x01;
public static final byte CTRL_RESPONSE = (byte) 0x81;
public static final byte UNIT_TON = 0x2C;
public static final int ADDRESS_LENGTH = 7;
/**
* 构建读表数据命令帧
*
* @param meterAddress 12位表计地址字符串如"000000000000012"
* @param diHighFirst 数据标识字节序true=901Fh(高字节在前), false=1F90h(低字节在前)
* @return 完整的命令帧字节数组
*/
public static byte[] buildReadCommand(String meterAddress, boolean diHighFirst) {
// 1. 地址转换12位字符串 -> 7字节BCD码逆序分组
byte[] addressBytes = convertAddress(meterAddress);
// 2. 构建帧主体(不含前导符和帧尾)
ByteBuffer buffer = ByteBuffer.allocate(32);
buffer.put(FRAME_START);
buffer.put(WATER_METER_TYPE);
buffer.put(addressBytes);
buffer.put(CTRL_READ);
buffer.put((byte) 0x03); // 数据域长度
// 数据标识处理
if (diHighFirst) {
buffer.put((byte) 0x90);
buffer.put((byte) 0x1F);
} else {
buffer.put((byte) 0x1F);
buffer.put((byte) 0x90);
}
buffer.put((byte) 0x00); // 序列号
// 3. 计算校验码从FRAME_START到序列号
byte[] frameBody = Arrays.copyOf(buffer.array(), buffer.position());
byte cs = calculateChecksum(frameBody, 0, frameBody.length);
// 4. 组装完整帧
buffer.put(cs);
buffer.put(FRAME_END);
// 5. 添加前导符
byte[] fullFrame = Arrays.copyOf(buffer.array(), buffer.position());
return addPreamble(fullFrame);
}
/**
* 解析读表响应数据
*
* @param response 完整响应帧(含前导符)
* @return 解析后的累积流量值(单位:吨)
* @throws IllegalArgumentException 响应格式错误
*/
public static double parseReadResponse(byte[] response) {
// 1. 跳过前导符(0xFE x3)
int startIndex = 3;
if (response[startIndex] != FRAME_START) {
throw new IllegalArgumentException("无效帧起始符");
}
// 2. 基础信息解析
int pos = startIndex + 1;
byte meterType = response[pos++];
byte[] address = Arrays.copyOfRange(response, pos, pos + ADDRESS_LENGTH);
pos += ADDRESS_LENGTH;
byte ctrlCode = response[pos++];
if (ctrlCode != CTRL_RESPONSE) {
throw new IllegalArgumentException("无效控制码");
}
// 3. 数据域解析
int dataLen = response[pos++] & 0xFF;
byte[] di = {response[pos++], response[pos++]}; // 数据标识
byte ser = response[pos++]; // 序列号
// 4. 累积流量解析 (4字节BCD)
byte[] currentFlow = Arrays.copyOfRange(response, pos, pos + 4);
pos += 4;
// 5. 单位校验
if (response[pos++] != UNIT_TON) {
throw new IllegalArgumentException("无效计量单位");
}
// 6. 流量值转换
return parseFlowValue(currentFlow);
}
/**
* 计算校验码 (CJ/T188-2004标准)
*
* @param data 待计算数据
* @param offset 起始位置
* @param length 数据长度
* @return 校验码
*/
public static byte calculateChecksum(byte[] data, int offset, int length) {
int sum = 0;
for (int i = offset; i < offset + length; i++) {
sum += (data[i] & 0xFF);
}
return (byte) (sum % 256);
}
// 地址转换12位字符串 -> 7字节BCD码逆序分组
private static byte[] convertAddress(String address) {
if (address.length() != 12) {
throw new IllegalArgumentException("地址长度必须为12位");
}
// 填充为14位7字节*2
String padded = "00" + address;
byte[] result = new byte[ADDRESS_LENGTH];
// 逆序分组转换
for (int i = 0; i < ADDRESS_LENGTH; i++) {
int end = padded.length() - i * 2;
int start = end - 2;
String segment = padded.substring(start, end);
result[i] = (byte) Integer.parseInt(segment, 16);
}
return result;
}
// 添加前导符 0xFE x3
private static byte[] addPreamble(byte[] frame) {
byte[] result = new byte[frame.length + 3];
result[0] = PREAMBLE;
result[1] = PREAMBLE;
result[2] = PREAMBLE;
System.arraycopy(frame, 0, result, 3, frame.length);
return result;
}
// 解析BCD流量值4字节 -> 浮点数)
private static double parseFlowValue(byte[] data) {
// 拼接BCD数字串
StringBuilder sb = new StringBuilder();
for (byte b : data) {
sb.append(String.format("%02X", b));
}
// 转换为数值最后2位是小数位
String numStr = sb.toString();
return Double.parseDouble(numStr.substring(0, numStr.length() - 2) +
Double.parseDouble(numStr.substring(numStr.length() - 2)) / 100.0);
}
}

View File

@@ -2,6 +2,7 @@ package org.dromara.sis.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.domain.TreeNode;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -11,6 +12,8 @@ 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.dromara.property.api.RemoteFloorService;
import org.dromara.property.api.domain.vo.RemoteFloorVo;
import org.dromara.sis.domain.bo.SisAccessControlBo;
import org.dromara.sis.domain.bo.SisElevatorInfoBo;
import org.dromara.sis.domain.vo.SisAccessControlVo;
@@ -25,6 +28,7 @@ import org.dromara.sis.mapper.SisAuthRecordMapper;
import org.dromara.sis.service.ISisAuthRecordService;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collection;
@@ -45,6 +49,9 @@ public class SisAuthRecordServiceImpl implements ISisAuthRecordService {
private final ISisAccessControlService accessControlService;
private final ISisElevatorInfoService elevatorInfoService;
@DubboReference
private RemoteFloorService remoteFloorService;
/**
* 查询授权记录
*
@@ -247,19 +254,36 @@ public class SisAuthRecordServiceImpl implements ISisAuthRecordService {
return node;
}).toList();
List<TreeNode<Long>> eleChildrenList = eleVoList.stream().map(item -> {
TreeNode<Long> node = new TreeNode<>();
node.setLevel(2);
node.setCode(item.getElevatorId());
node.setParentCode(2L);
node.setLabel(item.getElevatorName());
return node;
}).toList();
List<TreeNode<Long>> eleChildrenList = new ArrayList<>();
eleVoList.forEach(item -> {
// 电梯子节点
TreeNode<Long> eleNode = new TreeNode<>();
eleNode.setLevel(2);
eleNode.setParentCode(2L);
eleNode.setCode(item.getElevatorId());
eleNode.setLabel(item.getElevatorName());
// 楼层节点
List<TreeNode<Long>> floorTree = new ArrayList<>();
// 获取楼层
List<RemoteFloorVo> floorInfoList = remoteFloorService.queryByUnitId(item.getUnitId());
floorInfoList.forEach(floor -> {
TreeNode<Long> floorNode = new TreeNode<>();
floorNode.setLevel(3);
floorNode.setCode(floor.getId());
floorNode.setLabel(floor.getFloorName());
floorNode.setParentCode(item.getElevatorId());
floorTree.add(floorNode);
});
eleNode.setChildren(floorTree);
eleChildrenList.add(eleNode);
});
// 将子节点列表分别添加到对应的父节点
accessNode.setChildren(acChildrenList);
elevatorNode.setChildren(eleChildrenList);
// 最后将两个父节点添加到根节点
root.setChildren(List.of(accessNode, elevatorNode));
return List.of(root);

View File

@@ -40,9 +40,9 @@ spring.sql.init.platform=mysql
db.num=1
### Connect URL of DB:
db.url.0=jdbc:mysql://47.109.37.87:3002/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
db.user.0=by
db.password.0=123456
db.url.0=jdbc:mysql://127.0.0.1:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
db.user.0=root
db.password.0=root
### the maximum retry times for push
nacos.config.push.maxRetryTime=50