套餐配置

This commit is contained in:
墨大叔 2024-08-13 17:01:49 +08:00
parent bfbd6847d3
commit 7b5692787b
17 changed files with 392 additions and 71 deletions

View File

@ -0,0 +1,31 @@
package com.ruoyi.system.mapper.typehandler;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author wjh
* 2024/8/13
*/
public class DecimalSplitListTypeHandler extends AbstractSplitListTypeHandler<BigDecimal> {
/**
* 转换为列表
*
* @param data
* @param delimiter
*/
@Override
public List<BigDecimal> parseToList(String data, String delimiter) {
if (StringUtils.isBlank(data)) {
return new ArrayList<>();
}
String[] split = data.split(delimiter);
return Arrays.stream(split).map(BigDecimal::new).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.system.mapper.typehandler;
import com.ruoyi.common.utils.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author wjh
* 2024/8/13
*/
public class IntegerSplitListTypeHandler extends AbstractSplitListTypeHandler<Integer>{
/**
* 转换为列表
*
* @param data
* @param delimiter
*/
@Override
public List<Integer> parseToList(String data, String delimiter) {
if (StringUtils.isBlank(data)) {
return new ArrayList<>();
}
String[] split = data.split(delimiter);
return Arrays.stream(split).map(Integer::valueOf).collect(Collectors.toList());
}
}

View File

@ -1,5 +1,8 @@
package com.ruoyi.system.mapper.typehandler;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -15,6 +18,9 @@ public class StringSplitListTypeHandler extends AbstractSplitListTypeHandler<Str
*/
@Override
public List<String> parseToList(String data, String delimiter) {
if (StringUtils.isBlank(data)) {
return new ArrayList<>();
}
String[] split = data.split(delimiter);
return Arrays.asList(split);
}

View File

@ -15,4 +15,8 @@ public class DictTypeConstants {
public static final String WITHDRAW_TYPE = "withdraw_type";
// API收费标准类型
public static final String API_PRICE_TYPE = "api_price_type";
// 套餐收费模式
public static final String SUIT_FEE_MODE = "suit_fee_mode";
// 套餐收费类型
public static final String SUIT_FEE_TYPE = "suit_fee_type";
}

View File

@ -0,0 +1,45 @@
package com.ruoyi.common.validRule.allowSize;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* 判断列表大小
* @author wjh
* 2024/6/13
*/
@Documented
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(AllowSize.List.class)
@Constraint(validatedBy = { AllowSizeValidator.class })
public @interface AllowSize {
String message() default "{*.validation.constraint.Enum.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* 是否允许null值默认是允许
*/
boolean allowNull() default true;
/**
* 是否过滤null的元素
*/
boolean filterNull() default true;
/**
* 允许的大小
*/
int[] sizes() default {};
@Documented
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@interface List {
AllowSize[] value();
}
}

View File

@ -0,0 +1,53 @@
package com.ruoyi.common.validRule.allowSize;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ss.apiPrice.domain.ApiPriceQuery;
import com.ruoyi.ss.apiPrice.service.ApiPriceService;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 2023/10/20
* 枚举值校验
*/
public class AllowSizeValidator implements ConstraintValidator<AllowSize, List> {
private AllowSize annotation;
@Override
public void initialize(AllowSize constraintAnnotation) {
this.annotation = constraintAnnotation;
}
/**
* 判断是否校验成功
* @param value 待校验的值
* @return 校验结果
*/
@Override
public boolean isValid(List value, ConstraintValidatorContext context) {
// 如果待校验的值为null是否校验通过
if (value == null) {
return annotation.allowNull();
}
try {
int size = value.size();
if (annotation.filterNull()) {
size = (int) value.stream().filter(Objects::nonNull).count();
}
for (int s : annotation.sizes()) {
if (s == size) {
return true;
}
}
return false;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -66,6 +66,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{item}
</foreach>
</if>
<if test="modelIds != null and modelIds.size() > 0">
and sd.moidel_id in
<foreach collection="modelIds" open="(" close=")" separator="," item="item">
#{item}
</foreach>
</if>
<if test="deleted == null">and sd.deleted = false</if>
<if test="deleted != null">and sd.deleted = #{deleted}</if>
</sql>

View File

@ -524,7 +524,6 @@ public class DeviceServiceImpl implements DeviceService
return Collections.emptyMap();
}
DeviceQuery dto = new DeviceQuery();
dto.setDeleted(false);
dto.setModelIds(modelIds);
List<DeviceVO> list = deviceMapper.selectSmDeviceList(dto);
if (CollectionUtils.isEmpty(list)) {

View File

@ -6,14 +6,17 @@ import com.ruoyi.common.constants.DictTypeConstants;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.JsonViewProfile;
import com.ruoyi.common.core.domain.ValidGroup;
import com.ruoyi.system.valid.DictValid;
import com.ruoyi.common.validRule.allowSize.AllowSize;
import com.ruoyi.common.validRule.suitExist.SuitExist;
import com.ruoyi.common.validRule.suitValidator.SuitValidation;
import com.ruoyi.system.valid.DictValid;
import com.ruoyi.ss.device.domain.DeviceView;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.List;
/**
* 套餐对象 sm_suit
@ -28,7 +31,8 @@ public class Suit extends BaseEntity
/** 套餐id */
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@NotNull(message = "套餐id不允许为空", groups = {ValidGroup.Update.class, ValidGroup.FrontUpdate.class})
@SuitExist(message = "套餐不存在", allowNull = false, checkBelong = true, groups = {ValidGroup.FrontUpdate.class})
@SuitExist(message = "套餐不存在", allowNull = false, checkBelong = false, groups = {ValidGroup.Update.class})
private Long suitId;
/** 套餐名称 */
@ -38,18 +42,18 @@ public class Suit extends BaseEntity
@Size(min = 1, max = 50, message = "套餐名称长度在1~50个字符之间")
private String name;
/** 通电时间(分) */
@Excel(name = "通电时间")
/** 通电时间/度 */
@Excel(name = "通电时间/度")
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@NotNull(message = "通电时间不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@Min(value = 1, message = "通电时间不允许小于1")
private Long value;
// @NotNull(message = "通电时间/度不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@Min(value = 1, message = "通电时间/度不允许小于1")
private Integer value;
/** 价格(元) */
@Excel(name = "价格(元)")
@Excel(name = "价格/押金")
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@NotNull(message = "价格不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@Min(value = 0, message = "价格不允许小于0")
@NotNull(message = "价格/押金不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@Min(value = 0, message = "价格/押金不允许小于0")
private BigDecimal price;
/** 详细说明 */
@ -60,7 +64,7 @@ public class Suit extends BaseEntity
@ApiModelProperty("套餐时长单位")
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@NotBlank(message = "套餐时长单位不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
// @NotBlank(message = "套餐时长单位不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@DictValid(type = DictTypeConstants.TIME_UNIT, message = "非法的套餐时长单位")
private String timeUnit;
@ -71,4 +75,31 @@ public class Suit extends BaseEntity
@ApiModelProperty("排序顺序,越小越靠前")
@JsonView(JsonViewProfile.AppMch.class)
private Integer sort;
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@Excel(name = "收费模式")
@ApiModelProperty("收费模式")
@NotBlank(message = "收费模式不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@DictValid(type = DictTypeConstants.SUIT_FEE_MODE, message = "非法的收费方式")
private String feeMode;
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@Excel(name = "收费类型")
@ApiModelProperty("收费类型")
@NotBlank(message = "收费类型不允许为空", groups = {ValidGroup.Create.class, ValidGroup.FrontCreate.class})
@DictValid(type = DictTypeConstants.SUIT_FEE_TYPE, message = "非法的收费类型")
private String feeType;
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@Excel(name = "档位金额列表")
@ApiModelProperty("档位金额列表")
@AllowSize(sizes = {0, 4}, message = "档位金额必须填入24个")
private List<BigDecimal> gearAmount;
@JsonView({DeviceView.SuitList.class, JsonViewProfile.AppMch.class})
@Excel(name = "时段档位列表")
@ApiModelProperty("时段档位列表")
@AllowSize(sizes = {0, 24}, message = "时段档位必须填入24个")
private List<Integer> gearTime;
}

View File

@ -3,7 +3,6 @@ package com.ruoyi.ss.suit.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Set;
/**
@ -30,6 +29,10 @@ public class SuitBO extends Suit {
bo.setTimeUnit(getTimeUnit());
bo.setUserId(getUserId());
bo.setDeviceIds(getDeviceIds());
bo.setFeeMode(getFeeMode());
bo.setFeeType(getFeeType());
bo.setGearAmount(getGearAmount());
bo.setGearTime(getGearTime());
return bo;
}
@ -46,6 +49,10 @@ public class SuitBO extends Suit {
bo.setDescription(getDescription());
bo.setTimeUnit(getTimeUnit());
bo.setDeviceIds(getDeviceIds());
bo.setFeeMode(getFeeMode());
bo.setFeeType(getFeeType());
bo.setGearAmount(getGearAmount());
bo.setGearTime(getGearTime());
return bo;
}
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.ss.suit.domain.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 收费模式
* @author wjh
* 2024/8/13
*/
@Getter
@AllArgsConstructor
public enum SuitFeeMode {
SINGLE("1", "单次收费"),
SMART("2", "智能收费");
private final String mode;
private final String msg;
}

View File

@ -0,0 +1,58 @@
package com.ruoyi.ss.suit.domain.enums;
import com.ruoyi.ss.model.domain.enums.ModelTag;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author wjh
* 2024/8/13
*/
@Getter
@AllArgsConstructor
public enum SuitFeeType {
TIME("1", "计时收费"),
COUNT("2", "按量收费"),
TIMING_COUNT("3", "分时段按量收费"),
TIMING_TIME("4", "分时段按时收费");
private final String type;
private final String msg;
public static List<String> asList(SuitFeeType ...types) {
return Arrays.stream(types).map(SuitFeeType::getType).collect(Collectors.toList());
}
/**
* 允许单次收费的类型
*/
public static List<String> allowSingle() {
return asList(TIME, COUNT);
}
/**
* 需要设置分时的类型
*/
public static List<String> needConfigTime() {
return asList(TIMING_COUNT, TIMING_TIME);
}
/**
* 需要配置单次购买时长/度的类型
*/
public static List<String> needConfigSingleValue() {
return asList(TIME, COUNT);
}
/**
* 需要配置时长单位的类型
*/
public static List<String> needConfigTimeUnit() {
return asList(TIME);
}
}

View File

@ -81,11 +81,6 @@ public interface SuitMapper
*/
SuitVO selectOne(SuitQuery query);
/**
* 批量新增
*/
int batchInsert(@Param("list") List<Suit> list);
/**
* 批量修改排序
*/

View File

@ -4,7 +4,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.ss.suit.mapper.SuitMapper">
<resultMap type="SuitVO" id="SuitResult" autoMapping="true"/>
<resultMap type="SuitVO" id="SuitResult" autoMapping="true">
<result property="gearAmount" column="gear_amount" typeHandler="com.ruoyi.system.mapper.typehandler.DecimalSplitListTypeHandler"/>
<result property="gearTime" column="gear_time" typeHandler="com.ruoyi.system.mapper.typehandler.IntegerSplitListTypeHandler"/>
</resultMap>
<sql id="selectSuitVo">
select
@ -21,6 +24,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ss.time_unit,
ss.user_id,
ss.sort,
ss.fee_mode,
ss.fee_type,
ss.gear_amount,
ss.gear_time,
su.user_name as user_name
from <include refid="searchTables"/>
</sql>
@ -39,6 +46,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deleted == null"> and ss.deleted = false</if>
<if test="deleted != null"> and ss.deleted = #{deleted}</if>
<if test="userId != null"> and ss.user_id = #{userId}</if>
<if test="feeMode != null and feeMode != ''"> and fee_mode = #{feeMode}</if>
<if test="feeType != null and feeType != ''"> and fee_type = #{feeType}</if>
<if test="deviceId != null">
and ss.suit_id in (
select distinct sds.suit_id from ss_device_suit sds where sds.device_id = #{deviceId}
@ -107,6 +116,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="timeUnit != null">time_unit,</if>
<if test="userId != null">user_id,</if>
<if test="sort != null">sort,</if>
<if test="feeMode != null and feeMode != ''">fee_mode,</if>
<if test="feeType != null and feeType != ''">fee_type,</if>
<if test="gearAmount != null">gear_amount,</if>
<if test="gearTime != null">gear_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="name != null and name != ''">#{name},</if>
@ -121,57 +134,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="timeUnit != null">#{timeUnit},</if>
<if test="userId != null">#{userId},</if>
<if test="sort != null">#{sort},</if>
<if test="feeMode != null and feeMode != ''">#{feeMode},</if>
<if test="feeType != null and feeType != ''">#{feeType},</if>
<if test="gearAmount != null">#{gearAmount,typeHandler=com.ruoyi.system.mapper.typehandler.DecimalSplitListTypeHandler},</if>
<if test="gearTime != null">#{gearTime,typeHandler=com.ruoyi.system.mapper.typehandler.IntegerSplitListTypeHandler},</if>
</trim>
</insert>
<insert id="batchInsert">
insert into sm_suit(
device_id,
name,
value,
price,
description,
create_time,
create_by,
update_time,
update_by,
deleted,
time_unit,
user_id,
sort
)
values
<foreach collection="list" item="i" separator=",">
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="i.name != null and i.name != ''">#{i.name},</if>
<if test="i.name == null or i.name == ''">default,</if>
<if test="i.value != null">#{i.value},</if>
<if test="i.value == null">default,</if>
<if test="i.price != null">#{i.price},</if>
<if test="i.price == null">default,</if>
<if test="i.description != null">#{i.description},</if>
<if test="i.description == null">default,</if>
<if test="i.createTime != null">#{i.createTime},</if>
<if test="i.createTime == null">default,</if>
<if test="i.createBy != null">#{i.createBy},</if>
<if test="i.createBy == null">default,</if>
<if test="i.updateTime != null">#{i.updateTime},</if>
<if test="i.updateTime == null">default,</if>
<if test="i.updateBy != null">#{i.updateBy},</if>
<if test="i.updateBy == null">default,</if>
<if test="i.deleted != null">#{i.deleted},</if>
<if test="i.deleted == null">default,</if>
<if test="i.timeUnit != null">#{i.timeUnit},</if>
<if test="i.timeUnit == null">default,</if>
<if test="i.userId != null">#{i.userId},</if>
<if test="i.userId == null">default,</if>
<if test="i.sort != null">#{i.sort},</if>
<if test="i.sort == null">default,</if>
</trim>
</foreach>
</insert>
<update id="updateSuit" parameterType="Suit">
update sm_suit
<trim prefix="SET" suffixOverrides=",">
@ -190,6 +159,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="timeUnit != null">time_unit = #{timeUnit},</if>
<if test="userId != null">user_id = #{userId},</if>
<if test="sort != null">sort = #{sort},</if>
<if test="feeMode != null and feeMode != ''">fee_mode = #{feeMode},</if>
<if test="feeType != null and feeType != ''">fee_type = #{feeType},</if>
<if test="gearAmount != null">gear_amount = #{gearAmount,typeHandler=com.ruoyi.system.mapper.typehandler.DecimalSplitListTypeHandler},</if>
<if test="gearTime != null">gear_time = #{gearTime,typeHandler=com.ruoyi.system.mapper.typehandler.IntegerSplitListTypeHandler},</if>
</sql>
<update id="logicDel">

View File

@ -38,4 +38,9 @@ public interface SuitValidator {
* 判断这些套餐是否是指定客户的
*/
boolean isBelong(Collection<Long> ids, Long userId);
/**
* 创建更新公共校验
*/
ValidateResult preCreateOrUpdate(SuitBO suit);
}

View File

@ -2,16 +2,22 @@ package com.ruoyi.ss.suit.service.impl;
import com.ruoyi.common.core.domain.BaseValidator;
import com.ruoyi.common.core.domain.ValidateResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ss.device.service.DeviceValidator;
import com.ruoyi.ss.suit.domain.SuitBO;
import com.ruoyi.ss.suit.domain.SuitQuery;
import com.ruoyi.ss.suit.domain.SuitVO;
import com.ruoyi.ss.suit.domain.enums.SuitFeeMode;
import com.ruoyi.ss.suit.domain.enums.SuitFeeType;
import com.ruoyi.ss.suit.service.SuitService;
import com.ruoyi.ss.suit.service.SuitValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
/**
@ -63,8 +69,10 @@ public class SuitValidatorImpl extends BaseValidator implements SuitValidator {
*/
@Override
public ValidateResult preCreateByApp(SuitBO suit) {
if (suit == null) {
return error("数据不允许为空");
// 公共校验
ValidateResult result = this.preCreateOrUpdate(suit);
if (result.isError()) {
return result;
}
// 设备校验
@ -83,9 +91,12 @@ public class SuitValidatorImpl extends BaseValidator implements SuitValidator {
*/
@Override
public ValidateResult preUpdateByApp(SuitBO suit) {
if (suit == null) {
return error("数据不允许为空");
// 公共校验
ValidateResult result = this.preCreateOrUpdate(suit);
if (result.isError()) {
return result;
}
Long userId = SecurityUtils.getUserId();
// 判断套餐是否属于用户
@ -114,4 +125,48 @@ public class SuitValidatorImpl extends BaseValidator implements SuitValidator {
query.setUserId(userId);
return suitService.selectCount(query) == ids.size();
}
@Override
public ValidateResult preCreateOrUpdate(SuitBO suit) {
if (suit == null) {
return error("参数不允许为空");
}
SuitService suitService = SpringUtils.getBean(SuitService.class);
SuitVO old = suitService.selectSuitBySuitId(suit.getSuitId());
boolean create = old == null; // 是否新建
// 创建或者修改其中一个时
if (create || suit.getFeeType() != null || suit.getFeeMode() != null) {
String feeMode = suit.getFeeMode() == null && old != null ? old.getFeeMode() : suit.getFeeMode();
String feeType = suit.getFeeType() == null && old != null ? old.getFeeType() : suit.getFeeType();
List<BigDecimal> gearAmount = suit.getGearAmount() == null && old != null ? old.getGearAmount() : suit.getGearAmount();
List<Integer> gearTime = suit.getGearTime() == null && old != null ? old.getGearTime() : suit.getGearTime();
Integer value = suit.getValue() == null && old != null ? old.getValue() : suit.getValue();
String timeUnit = suit.getTimeUnit() == null && old != null ? old.getTimeUnit() : suit.getTimeUnit();
// 判断收费方式是否被允许
if (SuitFeeMode.SINGLE.getMode().equals(feeMode) && !SuitFeeType.allowSingle().contains(feeType)) {
return error("该收费模式下,收费方式不被允许");
}
// 判断分时电价是否设置
if (SuitFeeType.needConfigTime().contains(feeType) && (CollectionUtils.isEmptyElement(gearAmount) || CollectionUtils.isEmptyElement(gearTime))) {
return error("需要配置分时电价");
}
// 判断单次购买时长/度是否设置
if (SuitFeeType.needConfigSingleValue().contains(feeType) && value == null) {
return error("需要配置单次购买时长/度");
}
// 判断时长单位是否设置
if (SuitFeeType.needConfigTimeUnit().contains(feeType) && timeUnit == null) {
return error("需要配置时长单位");
}
}
return success();
}
}

View File

@ -99,6 +99,7 @@ public class SuitController extends BaseController
@PostMapping
public AjaxResult add(@RequestBody @Validated(ValidGroup.Create.class) SuitBO suit)
{
ServiceUtil.assertion(suitValidator.preCreateOrUpdate(suit));
return toAjax(suitService.insertSuit(suit));
}
@ -110,6 +111,7 @@ public class SuitController extends BaseController
@PutMapping
public AjaxResult edit(@RequestBody @Validated(ValidGroup.Update.class) SuitBO suit)
{
ServiceUtil.assertion(suitValidator.preCreateOrUpdate(suit));
return toAjax(suitService.updateSuit(suit));
}