记得上下班打卡 | git大法好,push需谨慎

Commit 73369bc4 authored by 胡佳晨's avatar 胡佳晨

盲盒下单 判断逻辑完成

parent d246f201
...@@ -266,7 +266,7 @@ public class GoblinMixServiceImpl implements IGoblinMixService { ...@@ -266,7 +266,7 @@ public class GoblinMixServiceImpl implements IGoblinMixService {
if (isHit && hitRatioCount.doubleValue() < 100.00 && map.size() > 0) { if (isHit && hitRatioCount.doubleValue() < 100.00 && map.size() > 0) {
nftBoxUtils.arrangeHitRatioMap(map, hitRatioCount); nftBoxUtils.arrangeHitRatioMap(map, hitRatioCount);
} }
Map<String, Integer> skuMap = nftBoxUtils.getSkuHitRatio(stock, map); Map<String, Integer> skuMap = nftBoxUtils.getSkuHitRatio(stock * item.getCount(), map);
for (String key : skuMap.keySet()) { for (String key : skuMap.keySet()) {
Integer stockNum = skuMap.get(key); Integer stockNum = skuMap.get(key);
//库存 //库存
...@@ -283,12 +283,12 @@ public class GoblinMixServiceImpl implements IGoblinMixService { ...@@ -283,12 +283,12 @@ public class GoblinMixServiceImpl implements IGoblinMixService {
} }
} else { } else {
//库存 //库存
int skuStock = redisUtils.decrSkuStock(null, skuId, stock); int skuStock = redisUtils.decrSkuStock(null, skuId, stock * item.getCount());
if (skuStock < 0) { if (skuStock < 0) {
redisUtils.incrSkuStock(null, skuId, stock); redisUtils.incrSkuStock(null, skuId, stock * item.getCount());
errorNameList.add(item.getSkuName()); errorNameList.add(item.getSkuName());
} else { } else {
redisUtils.setSkuStock(mixId, skuId, stock); redisUtils.setSkuStock(mixId, skuId, stock * item.getCount());
sucSkuId.add(skuId); sucSkuId.add(skuId);
} }
}//普通商品 }//普通商品
......
...@@ -1756,7 +1756,7 @@ public class GoblinMongoUtils { ...@@ -1756,7 +1756,7 @@ public class GoblinMongoUtils {
public HashMap<String, Object> getGoblinMixListVo(String name, String uid, Integer pageNum) { public HashMap<String, Object> getGoblinMixListVo(String name, String uid, Integer pageNum) {
int pageSize = 20; int pageSize = 20;
Criteria criteria = Criteria.where("uid").is(uid); Criteria criteria = Criteria.where("userId").is(uid);
if (name != null && !name.equals("")) { if (name != null && !name.equals("")) {
criteria = criteria.and("name").regex("^.*" + name + ".*$"); criteria = criteria.and("name").regex("^.*" + name + ".*$");
} }
......
package com.liquidnet.service.order.service.impl; package com.liquidnet.service.order.service.impl;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.CurrentUtil; import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.base.ResponseDto; import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.constant.NftAccStatusEnum; import com.liquidnet.service.goblin.constant.NftAccStatusEnum;
import com.liquidnet.service.goblin.dto.GoblinUserNftAccInfoVo; import com.liquidnet.service.goblin.dto.GoblinUserNftAccInfoVo;
import com.liquidnet.service.goblin.dto.manage.MixOrderParam; import com.liquidnet.service.goblin.dto.manage.MixOrderParam;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo; import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.dto.vo.GoblinMixDetailsItemVo;
import com.liquidnet.service.goblin.dto.vo.GoblinMixDetailsVo;
import com.liquidnet.service.goblin.dto.vo.GoblinPayInnerResultVo;
import com.liquidnet.service.goblin.param.SyncOrderParam; import com.liquidnet.service.goblin.param.SyncOrderParam;
import com.liquidnet.service.goblin.service.IMixOrderService; import com.liquidnet.service.goblin.service.IMixOrderService;
import com.liquidnet.service.order.utils.*; import com.liquidnet.service.order.utils.*;
...@@ -49,6 +47,9 @@ public class MixOrderServiceImpl implements IMixOrderService { ...@@ -49,6 +47,9 @@ public class MixOrderServiceImpl implements IMixOrderService {
GoblinMixDetailsVo mixVo = redisUtils.getMixDetails(param.getMixId()); GoblinMixDetailsVo mixVo = redisUtils.getMixDetails(param.getMixId());
String mixId = mixVo.getMixId(); String mixId = mixVo.getMixId();
String mobile = StringUtils.defaultString(((String) CurrentUtil.getTokenClaims().get(CurrentUtil.TOKEN_MOBILE)), ""); String mobile = StringUtils.defaultString(((String) CurrentUtil.getTokenClaims().get(CurrentUtil.TOKEN_MOBILE)), "");
List<String> canBuyIds = CollectionUtil.linkedListString();//有库存的id
String boxSkuId = "";//盲盒种的skuid
String stockSkuId = ""; // 盲盒id
//判断 活动状态 //判断 活动状态
LocalDateTime st = LocalDateTime.parse(mixVo.getTimeStart(), DTF_YMD_HMS); LocalDateTime st = LocalDateTime.parse(mixVo.getTimeStart(), DTF_YMD_HMS);
LocalDateTime et = LocalDateTime.parse(mixVo.getTimeEnd(), DTF_YMD_HMS); LocalDateTime et = LocalDateTime.parse(mixVo.getTimeEnd(), DTF_YMD_HMS);
...@@ -72,7 +73,42 @@ public class MixOrderServiceImpl implements IMixOrderService { ...@@ -72,7 +73,42 @@ public class MixOrderServiceImpl implements IMixOrderService {
List<GoblinGoodsSkuInfoVo> skuInfoList = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo(); List<GoblinGoodsSkuInfoVo> skuInfoList = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
List<GoblinGoodsSkuInfoVo> nftInfoList = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo(); List<GoblinGoodsSkuInfoVo> nftInfoList = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
for (GoblinMixDetailsItemVo itemVo : mixVo.getItem()) { for (GoblinMixDetailsItemVo itemVo : mixVo.getItem()) {
GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(itemVo.getSkuId()); String skuId = itemVo.getSkuId();
GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(skuId);
//库存处理
if (skuInfoVo.getUnbox().equals("1")) {//盲盒
GoblinGoodsInfoVo spuInfoVo = redisUtils.getGoodsInfoVo(skuInfoVo.getSpuId());
List<String> skuIdList = spuInfoVo.getSkuIdList();
if (CollectionUtil.isEmpty(skuIdList)) {
return ResponseDto.failure("该商品SPU不存在~");
} else {
GoblinGoodsSkuInfoVo boxSkuInfo = nftOrderUtils.lotteryDraw(skuIdList, itemVo.getCount(), nt, null);
if (null == boxSkuInfo) {
return ResponseDto.failure("盲盒库存不足啦~");
} else {
canBuyIds.add(boxSkuInfo.getSkuId() + "," + itemVo.getCount());
}
boxSkuId = skuInfoVo.getSkuId();
stockSkuId = boxSkuId;
}
} else {//正常
if (skuInfoVo.getSkuType() == 1) {
stockSkuId = skuId;
}
int stock = redisUtils.decrSkuStock(mixId, skuId, itemVo.getCount());
if (stock < 0) {
redisUtils.incrSkuStock(mixId, skuId, itemVo.getCount());
for (String canBuyId : canBuyIds) {
String[] data = canBuyId.split(",");
String skuIdSingle = data[0];
int count = Integer.parseInt(data[1]);
redisUtils.incrSkuStock(mixId, skuIdSingle, count);
}
return ResponseDto.failure("库存不足");
} else {
canBuyIds.add(skuId + "," + itemVo.getCount());
}
}
if (skuInfoVo.getSkuType() == 0) { if (skuInfoVo.getSkuType() == 0) {
skuInfoList.add(skuInfoVo); skuInfoList.add(skuInfoVo);
} else if (skuInfoVo.getSkuType() == 1) { } else if (skuInfoVo.getSkuType() == 1) {
...@@ -85,11 +121,10 @@ public class MixOrderServiceImpl implements IMixOrderService { ...@@ -85,11 +121,10 @@ public class MixOrderServiceImpl implements IMixOrderService {
if (nftInfoList.size() > 0) { if (nftInfoList.size() > 0) {
GoblinUserNftAccInfoVo openAccountInfo = redisUtils.getOpenAccountInfo(uid); GoblinUserNftAccInfoVo openAccountInfo = redisUtils.getOpenAccountInfo(uid);
if (null == openAccountInfo || !NftAccStatusEnum.StatusAcc.SUCCESS.getCode().equals(openAccountInfo.getCode())) { if (null == openAccountInfo || !NftAccStatusEnum.StatusAcc.SUCCESS.getCode().equals(openAccountInfo.getCode())) {
return ResponseDto.failure("您还未开通数字账户"); return ResponseDto.failure("您还未开通数字账户");
} }
} }
//库存处理
return null; return null;
} }
......
...@@ -18,10 +18,10 @@ import org.springframework.stereotype.Component; ...@@ -18,10 +18,10 @@ import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap; import java.util.*;
import java.util.List; import java.util.stream.Collectors;
import java.util.Objects;
@Component @Component
@Slf4j @Slf4j
...@@ -86,6 +86,7 @@ public class GoblinNftOrderUtils { ...@@ -86,6 +86,7 @@ public class GoblinNftOrderUtils {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_ID_OF_CODE.concat(orderCode); String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_ID_OF_CODE.concat(orderCode);
redisUtil.set(redisKey, orderId); redisUtil.set(redisKey, orderId);
} }
// code换id // code换id
public String getNftOrderIdOfCode(String orderCode) { public String getNftOrderIdOfCode(String orderCode) {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_ID_OF_CODE.concat(orderCode); String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_ID_OF_CODE.concat(orderCode);
...@@ -163,17 +164,19 @@ public class GoblinNftOrderUtils { ...@@ -163,17 +164,19 @@ public class GoblinNftOrderUtils {
return (GoblinNftExCodeVo) obj; return (GoblinNftExCodeVo) obj;
} }
} }
public void setGoblinNftExCodeVo(GoblinNftExCodeVo codeVo) { public void setGoblinNftExCodeVo(GoblinNftExCodeVo codeVo) {
String redisKey = GoblinRedisConst.ACTIVITY_SKU_CODE.concat(codeVo.getCode()); String redisKey = GoblinRedisConst.ACTIVITY_SKU_CODE.concat(codeVo.getCode());
redisUtil.set(redisKey, codeVo); redisUtil.set(redisKey, codeVo);
} }
public int incrExCountByUid(String uid, String skuId, String activityId, int number) { public int incrExCountByUid(String uid, String skuId, String activityId, int number) {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId+':').concat(skuId+':').concat(uid); String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId + ':').concat(skuId + ':').concat(uid);
return (int) redisUtil.incr(redisKey, number); return (int) redisUtil.incr(redisKey, number);
} }
public int decrExCountByUid(String uid, String skuId, String activityId, int number) { public int decrExCountByUid(String uid, String skuId, String activityId, int number) {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId+':').concat(skuId+':').concat(uid); String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId + ':').concat(skuId + ':').concat(uid);
return (int) redisUtil.decr(redisKey, number); return (int) redisUtil.decr(redisKey, number);
} }
...@@ -185,10 +188,11 @@ public class GoblinNftOrderUtils { ...@@ -185,10 +188,11 @@ public class GoblinNftOrderUtils {
if (obj == null) { if (obj == null) {
return false; return false;
} else { } else {
GoblinGoodsAnticipateValueVo anticipateValueVo = (GoblinGoodsAnticipateValueVo)obj; GoblinGoodsAnticipateValueVo anticipateValueVo = (GoblinGoodsAnticipateValueVo) obj;
return anticipateValueVo.getType() != 1; return anticipateValueVo.getType() != 1;
} }
} }
// 是否预约过 没开启true // 是否预约过 没开启true
public boolean getUserAboutAut(String skuId, String uid) { public boolean getUserAboutAut(String skuId, String uid) {
boolean valueBySkuId = getValueBySkuId(skuId); boolean valueBySkuId = getValueBySkuId(skuId);
...@@ -400,37 +404,37 @@ public class GoblinNftOrderUtils { ...@@ -400,37 +404,37 @@ public class GoblinNftOrderUtils {
} }
/** /**
* private int skuType 商品类型[0-常规|1-数字藏品] * private int skuType 商品类型[0-常规|1-数字藏品]
* private String status 审核状态[0-初始编辑|1-审核中|2-审核不通过|3-审核通过]; * private String status 审核状态[0-初始编辑|1-审核中|2-审核不通过|3-审核通过];
* private String shelvesStatus 单品上架状态[0-待上架|1-下架|2-违规|3-上架]; * private String shelvesStatus 单品上架状态[0-待上架|1-下架|2-违规|3-上架];
* private String skuAppear 是否隐藏[0-默认展示|1-隐藏]; 隐藏款 拼参数可购买 盲盒可抽 * private String skuAppear 是否隐藏[0-默认展示|1-隐藏]; 隐藏款 拼参数可购买 盲盒可抽
* private String delFlg 删除标记[0-未删除|1-删除]; * private String delFlg 删除标记[0-未删除|1-删除];
* * <p>
* private LocalDateTime saleStartTime 开售时间; * private LocalDateTime saleStartTime 开售时间;
* private LocalDateTime saleStopTime 停售时间 预留 暂时不做处理; * private LocalDateTime saleStopTime 停售时间 预留 暂时不做处理;
* private String soldoutStatus 是否售罄[0-否|1-是]; * private String soldoutStatus 是否售罄[0-否|1-是];
* * <p>
* private String skuCanbuy 是否购买[0-否|1-是] 这个用来预览 前端自己判断; * private String skuCanbuy 是否购买[0-否|1-是] 这个用来预览 前端自己判断;
* * <p>
* Integer upchain NFT上传声明状态[0-待上传|1-已声明|2-声明失败|9-声明中] * Integer upchain NFT上传声明状态[0-待上传|1-已声明|2-声明失败|9-声明中]
* * <p>
* 根据概率判断是否过滤当前sku 没设置概率或者设置了的返回true * 根据概率判断是否过滤当前sku 没设置概率或者设置了的返回true
* * <p>
* String unbox; 是否盲盒[0-否|1-是] * String unbox; 是否盲盒[0-否|1-是]
*/ */
// 获取盲盒下藏品的库存 各种状态下不能算库存的排除掉 // 获取盲盒下藏品的库存 各种状态下不能算库存的排除掉
public int getSkuAllStatusStock(String listId, GoblinGoodsSkuInfoVo info) { public int getSkuAllStatusStock(String listId, GoblinGoodsSkuInfoVo info) {
if ( if (
info != null info != null
// && LocalDateTime.now().isAfter(info.getSaleStartTime()) // && LocalDateTime.now().isAfter(info.getSaleStartTime())
&& (null == info.getSoldoutStatus() || info.getSoldoutStatus().equals("0")) && (null == info.getSoldoutStatus() || info.getSoldoutStatus().equals("0"))
&& (null == info.getSkuCanbuy() || info.getSkuCanbuy().equals("1")) && (null == info.getSkuCanbuy() || info.getSkuCanbuy().equals("1"))
&& (null == info.getHitRatio() || info.getHitRatio().compareTo(BigDecimal.ZERO) > 0) && (null == info.getHitRatio() || info.getHitRatio().compareTo(BigDecimal.ZERO) > 0)
) {// 可以返回库存 ) {// 可以返回库存
// 外面只有盲盒才能请求进来 里面只有不是分批购才判断盲盒里藏品的开售时间 // 外面只有盲盒才能请求进来 里面只有不是分批购才判断盲盒里藏品的开售时间
if (null == listId) { if (null == listId) {
// if (LocalDateTime.now().isAfter(info.getSaleStartTime())) { // if (LocalDateTime.now().isAfter(info.getSaleStartTime())) {
return goblinRedisUtils.getSkuStock(listId, info.getSkuId()); return goblinRedisUtils.getSkuStock(listId, info.getSkuId());
// } else { // } else {
// return 0; // return 0;
// } // }
...@@ -441,16 +445,17 @@ public class GoblinNftOrderUtils { ...@@ -441,16 +445,17 @@ public class GoblinNftOrderUtils {
return 0; return 0;
} }
} }
// 各种状态下判断藏品是否可以展示 // 各种状态下判断藏品是否可以展示
public boolean getSkuAllStatusShow(GoblinGoodsSkuInfoVo info) { public boolean getSkuAllStatusShow(GoblinGoodsSkuInfoVo info) {
if ( if (
info != null info != null
&& info.getSkuType() == 1 && info.getSkuType() == 1
&& info.getStatus().equals("3") && info.getStatus().equals("3")
&& info.getShelvesStatus().equals("3") && info.getShelvesStatus().equals("3")
// && (info.getSkuAppear() == null || info.getSkuAppear().equals("0")) // && (info.getSkuAppear() == null || info.getSkuAppear().equals("0"))
&& info.getDelFlg().equals("0") && info.getDelFlg().equals("0")
&& ((info.getUnbox().equals("0") && info.getUpchain() == 1) || info.getUnbox().equals("1")) && ((info.getUnbox().equals("0") && info.getUpchain() == 1) || info.getUnbox().equals("1"))
) { ) {
return true; return true;
} else { } else {
...@@ -458,4 +463,110 @@ public class GoblinNftOrderUtils { ...@@ -458,4 +463,110 @@ public class GoblinNftOrderUtils {
} }
} }
public GoblinGoodsSkuInfoVo lotteryDraw(List<String> skuIdList, int number, LocalDateTime nowTime, String listId) {
// private HashMap<String, Object> lotteryDraw(List<String> skuIdList, int number, LocalDateTime nowTime) {
try {
ArrayList<GoblinGoodsSkuInfoVo> skuInfoVos = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
// ArrayList<String> listIds = ObjectUtil.cloneArrayListString();
for (String kid : skuIdList) {
HashMap<String, Object> map = goblinRedisUtils.getGoodsSkuInfoVo(nowTime, kid);
GoblinGoodsSkuInfoVo skuInfoVo = (GoblinGoodsSkuInfoVo) map.get("vo");
// String listId = (String) map.get("listId");
// 是盲盒的扔掉
if (skuInfoVo.getUnbox().equals("1")) {
continue;
}
// 不能购买的 没库存的 概率是0的 过滤
if (getSkuAllStatusShow(skuInfoVo) && getSkuAllStatusStock(listId, skuInfoVo) > 0) {
skuInfoVos.add(skuInfoVo);
// listIds.add(listId);
}
}
if (CollectionUtil.isEmpty(skuInfoVos)) {
return null;
} else {
// 计算总概率 和 剩余没填概率的平均概率
int size = 0;
BigDecimal sumHitRatio = BigDecimal.ZERO;
for (GoblinGoodsSkuInfoVo skuInfoVo : skuInfoVos) {
if (null == skuInfoVo.getHitRatio()) {
size++;
} else {
sumHitRatio = sumHitRatio.add(skuInfoVo.getHitRatio());
}
}
/**
* 剔除掉没库存的商品再去算未设置概率商品的平均概率 会导致未设置概率的商品的概率增加
* 如果不剔除掉没库存的商品去算未设置概率商品的平均概率 会导致总概率小于100 如果随机数还是0-100的话就有可能会中奖溢出
* 想保持概率 1.不剔除无库存商品算平均概率 2.随机数最大值为排序后概率的最后一个值
*/
BigDecimal avgHitRatio = BigDecimal.ZERO;
if (size > 0) {// 说明有未设置抽奖概率的
avgHitRatio = new BigDecimal(100).subtract(sumHitRatio).divide(new BigDecimal(size), 2, RoundingMode.HALF_UP);
}
// 未设置概率的写入概率
ArrayList<GoblinGoodsSkuInfoVo> newSkuInfoVos = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
// ArrayList<String> newListIds = ObjectUtil.cloneArrayListString();
int skuListSize = skuInfoVos.size();
for (int i = 0; i < skuListSize; i++) {
GoblinGoodsSkuInfoVo infoVo = skuInfoVos.get(i);
if (null == infoVo.getHitRatio() || infoVo.getHitRatio().compareTo(BigDecimal.ZERO) < 0) {
/**
* 算所得平均概率是0 即中不了 剔除掉
* 但是这么处理会导致前端页面显示有库存 买的时候显示没有
* 所以要么概率加起来必须100 要么前端计算盲盒总概率的时候也要同样处理
*/
if (avgHitRatio.compareTo(BigDecimal.ZERO) <= 0) {
continue;
} else {
infoVo.setHitRatio(avgHitRatio);
}
}
// 等于0的最终概率就是设置的值 大于0最终的概率是自己的+上面的
if (i > 0) {
infoVo.setHitRatio(skuInfoVos.get(i - 1).getHitRatio().add(infoVo.getHitRatio()));
}
newSkuInfoVos.add(infoVo);
// newListIds.add(listIds.get(i));
}
if (CollectionUtil.isEmpty(newSkuInfoVos)) {
log.info("该盲盒概率超过100导致不能卖 skuIdList:{}", skuIdList);
return null;
}
// 按照概率排序 按照上面的运算最后一定是最大的不用排序了
// List<GoblinGoodsSkuInfoVo> listSort = newSkuInfoVos.stream().sorted(Comparator.comparing(GoblinGoodsSkuInfoVo::getHitRatio)).collect(Collectors.toList());
List<BigDecimal> hitRatioList = newSkuInfoVos.stream().map(GoblinGoodsSkuInfoVo::getHitRatio).collect(Collectors.toList());
// 根据区块值来获取抽取到的物品索引
double nextDouble = Math.random();
BigDecimal nextDoubleNew = BigDecimal.valueOf(nextDouble);
nextDoubleNew = nextDoubleNew.multiply(hitRatioList.get(hitRatioList.size() - 1)).setScale(4, RoundingMode.HALF_UP);
hitRatioList.add(nextDoubleNew);
Collections.sort(hitRatioList);
int index = hitRatioList.indexOf(nextDoubleNew);
GoblinGoodsSkuInfoVo goodsSkuInfoVo = newSkuInfoVos.get(index);
// String endListId = newListIds.get(index);
// 判断库存
int surplusGeneral = goblinRedisUtils.decrSkuStock(listId, goodsSkuInfoVo.getSkuId(), number);
if (surplusGeneral < 0) {
goblinRedisUtils.incrSkuStock(listId, goodsSkuInfoVo.getSkuId(), number);
return lotteryDraw(skuIdList, number, nowTime, listId);
} else {
// HashMap<String, Object> map = CollectionUtil.mapStringObject();
// map.put("goodsSkuInfoVo", goodsSkuInfoVo);
// map.put("listId", endListId);
// return map;
return goodsSkuInfoVo;
}
}
} catch (Exception e) {
log.error("NFT下单-抽盲盒异常", e);
return null;
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment