소스 검색

add:抽奖

yonge 4 년 전
부모
커밋
40c5936e39
22개의 변경된 파일1251개의 추가작업 그리고 0개의 파일을 삭제
  1. 9 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawCountDao.java
  2. 8 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawGroupDao.java
  3. 8 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawLogDao.java
  4. 23 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawPrizeDao.java
  5. 56 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawCount.java
  6. 75 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawGroup.java
  7. 77 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawLog.java
  8. 148 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawPrize.java
  9. 68 0
      mec-biz/src/main/java/com/ym/mec/biz/dal/page/LuckDrawQueryInfo.java
  10. 33 0
      mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawCountService.java
  11. 8 0
      mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawGroupService.java
  12. 16 0
      mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawLogService.java
  13. 15 0
      mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawPrizeService.java
  14. 82 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawCountServiceImpl.java
  15. 23 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawGroupServiceImpl.java
  16. 35 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawLogServiceImpl.java
  17. 147 0
      mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawPrizeServiceImpl.java
  18. 63 0
      mec-biz/src/main/resources/config/mybatis/LuckDrawCountMapper.xml
  19. 63 0
      mec-biz/src/main/resources/config/mybatis/LuckDrawGroupMapper.xml
  20. 108 0
      mec-biz/src/main/resources/config/mybatis/LuckDrawLogMapper.xml
  21. 116 0
      mec-biz/src/main/resources/config/mybatis/LuckDrawPrizeMapper.xml
  22. 70 0
      mec-web/src/main/java/com/ym/mec/web/controller/LuckDrawController.java

+ 9 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawCountDao.java

@@ -0,0 +1,9 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.ym.mec.biz.dal.entity.LuckDrawCount;
+import com.ym.mec.common.dal.BaseDAO;
+
+public interface LuckDrawCountDao extends BaseDAO<Long, LuckDrawCount> {
+
+	public LuckDrawCount getLock(Long userId);
+}

+ 8 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawGroupDao.java

@@ -0,0 +1,8 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.ym.mec.biz.dal.entity.LuckDrawGroup;
+import com.ym.mec.common.dal.BaseDAO;
+
+public interface LuckDrawGroupDao extends BaseDAO<Integer, LuckDrawGroup> {
+
+}

+ 8 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawLogDao.java

@@ -0,0 +1,8 @@
+package com.ym.mec.biz.dal.dao;
+
+import com.ym.mec.biz.dal.entity.LuckDrawLog;
+import com.ym.mec.common.dal.BaseDAO;
+
+public interface LuckDrawLogDao extends BaseDAO<Long, LuckDrawLog> {
+	
+}

+ 23 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dao/LuckDrawPrizeDao.java

@@ -0,0 +1,23 @@
+package com.ym.mec.biz.dal.dao;
+
+import java.util.List;
+
+import com.ym.mec.biz.dal.entity.LuckDrawPrize;
+import com.ym.mec.common.dal.BaseDAO;
+
+public interface LuckDrawPrizeDao extends BaseDAO<Integer, LuckDrawPrize> {
+
+	/**
+	 * 查询所有可用记录
+	 * @param group
+	 * @return
+	 */
+	List<LuckDrawPrize> queryEnabledList(int group);
+
+	/**
+	 * 获取锁
+	 * @param id
+	 * @return
+	 */
+	LuckDrawPrize getLock(Integer id);
+}

+ 56 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawCount.java

@@ -0,0 +1,56 @@
+package com.ym.mec.biz.dal.entity;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+public class LuckDrawCount {
+	private Long userId;
+
+	private Integer usedCount;
+
+	private Integer availableCount;
+
+	private BigDecimal availableAmount = new BigDecimal(0);
+
+	private Date modifyOn;
+
+	public Long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	public Integer getUsedCount() {
+		return usedCount == null ? 0 : usedCount;
+	}
+
+	public void setUsedCount(Integer usedCount) {
+		this.usedCount = usedCount;
+	}
+
+	public Integer getAvailableCount() {
+		return availableCount == null ? 0 : availableCount;
+	}
+
+	public void setAvailableCount(Integer availableCount) {
+		this.availableCount = availableCount;
+	}
+
+	public BigDecimal getAvailableAmount() {
+		return availableAmount;
+	}
+
+	public void setAvailableAmount(BigDecimal availableAmount) {
+		this.availableAmount = availableAmount;
+	}
+
+	public Date getModifyOn() {
+		return modifyOn;
+	}
+
+	public void setModifyOn(Date modifyOn) {
+		this.modifyOn = modifyOn;
+	}
+}

+ 75 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawGroup.java

@@ -0,0 +1,75 @@
+package com.ym.mec.biz.dal.entity;
+
+import java.util.Date;
+
+public class LuckDrawGroup {
+    private Integer id;
+
+    private String name;
+
+    private String consumeType;
+    
+    private Integer consumeValue;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Date createOn;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name == null ? null : name.trim();
+    }
+
+    public String getConsumeType() {
+        return consumeType;
+    }
+
+    public void setConsumeType(String consumeType) {
+        this.consumeType = consumeType == null ? null : consumeType.trim();
+    }
+
+    public Integer getConsumeValue() {
+		return consumeValue;
+	}
+
+	public void setConsumeValue(Integer consumeValue) {
+		this.consumeValue = consumeValue;
+	}
+
+	public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Date getCreateOn() {
+        return createOn;
+    }
+
+    public void setCreateOn(Date createOn) {
+        this.createOn = createOn;
+    }
+}

+ 77 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawLog.java

@@ -0,0 +1,77 @@
+package com.ym.mec.biz.dal.entity;
+
+import java.util.Date;
+
+import com.ym.mec.auth.api.entity.SysUser;
+
+public class LuckDrawLog {
+	private Long id;
+
+	private Integer prizeId;
+
+	private Long userId;
+
+	private Date createOn;
+
+	private LuckDrawPrize luckDrawPrize = new LuckDrawPrize();
+
+	private SysUser user = new SysUser();
+
+	private Integer groupId;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Integer getPrizeId() {
+		return prizeId;
+	}
+
+	public void setPrizeId(Integer prizeId) {
+		this.prizeId = prizeId;
+	}
+
+	public Long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	public Date getCreateOn() {
+		return createOn;
+	}
+
+	public void setCreateOn(Date createOn) {
+		this.createOn = createOn;
+	}
+
+	public LuckDrawPrize getLuckDrawPrize() {
+		return luckDrawPrize;
+	}
+
+	public void setLuckDrawPrize(LuckDrawPrize luckDrawPrize) {
+		this.luckDrawPrize = luckDrawPrize;
+	}
+
+	public SysUser getUser() {
+		return user;
+	}
+
+	public void setUser(SysUser user) {
+		this.user = user;
+	}
+
+	public Integer getGroupId() {
+		return groupId;
+	}
+
+	public void setGroupId(Integer groupId) {
+		this.groupId = groupId;
+	}
+}

+ 148 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/entity/LuckDrawPrize.java

@@ -0,0 +1,148 @@
+package com.ym.mec.biz.dal.entity;
+
+import java.util.Date;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.ym.mec.common.enums.BaseEnum;
+
+public class LuckDrawPrize {
+
+	public enum ActiveRewardType implements BaseEnum<String, ActiveRewardType> {
+
+		/** 优惠券 */
+		COUPON("优惠券"),
+		/** 积分 */
+		POINTS("积分"),
+		/** 现金 */
+		CASH("现金"),
+		/** 抽奖 */
+		LUCK_DRAW("抽奖"),
+		/** 其他 */
+		OTHER("其他");
+
+		private String description;
+
+		private ActiveRewardType(String description) {
+			this.description = description;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		@Override
+		public String getCode() {
+			return this.name();
+		}
+
+		public static ActiveRewardType codeOf(String name) {
+			for (ActiveRewardType type : ActiveRewardType.values()) {
+				if (StringUtils.equals(type.name(), name)) {
+					return type;
+				}
+			}
+			return null;
+		}
+	}
+
+	private Integer id;
+
+	private String name;
+
+	private Double chances;
+
+	private Integer stock;
+
+	private Boolean enabled;
+
+	private ActiveRewardType rewardType;
+
+	private String memo;
+
+	private Date createOn;
+
+	private Date modifyOn;
+
+	private Integer groupId;
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name == null ? null : name.trim();
+	}
+
+	public Double getChances() {
+		return chances;
+	}
+
+	public void setChances(Double chances) {
+		this.chances = chances;
+	}
+
+	public Integer getStock() {
+		return stock;
+	}
+
+	public void setStock(Integer stock) {
+		this.stock = stock;
+	}
+
+	public Boolean getEnabled() {
+		return enabled;
+	}
+
+	public void setEnabled(Boolean enabled) {
+		this.enabled = enabled;
+	}
+
+	public ActiveRewardType getRewardType() {
+		return rewardType;
+	}
+
+	public void setRewardType(ActiveRewardType rewardType) {
+		this.rewardType = rewardType;
+	}
+
+	public String getMemo() {
+		return memo;
+	}
+
+	public void setMemo(String memo) {
+		this.memo = memo;
+	}
+
+	public Date getCreateOn() {
+		return createOn;
+	}
+
+	public void setCreateOn(Date createOn) {
+		this.createOn = createOn;
+	}
+
+	public Date getModifyOn() {
+		return modifyOn;
+	}
+
+	public void setModifyOn(Date modifyOn) {
+		this.modifyOn = modifyOn;
+	}
+
+	public Integer getGroupId() {
+		return groupId;
+	}
+
+	public void setGroupId(Integer groupId) {
+		this.groupId = groupId;
+	}
+}

+ 68 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/page/LuckDrawQueryInfo.java

@@ -0,0 +1,68 @@
+package com.ym.mec.biz.dal.page;
+
+import java.util.Date;
+
+import com.ym.mec.common.page.QueryInfo;
+
+public class LuckDrawQueryInfo extends QueryInfo {
+
+	private String name;
+
+	private Integer id;
+
+	private Long userId;
+
+	private Date startDate;
+
+	private Date endDate;
+
+	private Integer groupId;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Integer getId() {
+		return id;
+	}
+
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public Long getUserId() {
+		return userId;
+	}
+
+	public void setUserId(Long userId) {
+		this.userId = userId;
+	}
+
+	public Date getStartDate() {
+		return startDate;
+	}
+
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+
+	public Date getEndDate() {
+		return endDate;
+	}
+
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+
+	public Integer getGroupId() {
+		return groupId;
+	}
+
+	public void setGroupId(Integer groupId) {
+		this.groupId = groupId;
+	}
+}

+ 33 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawCountService.java

@@ -0,0 +1,33 @@
+package com.ym.mec.biz.service;
+
+import com.ym.mec.biz.dal.entity.LuckDrawCount;
+import com.ym.mec.common.service.BaseService;
+
+public interface LuckDrawCountService extends BaseService<Long, LuckDrawCount> {
+
+	public LuckDrawCount getLock(Long userId);
+
+	/**
+	 * 免费赠送次数
+	 * @param userId
+	 * @param times
+	 * @return
+	 */
+	public boolean freeGive(Long userId, int times);
+
+	/**
+	 * 更新抽奖次数
+	 * @param userId
+	 * @param times
+	 * @return
+	 */
+	public boolean updateTimes(Long userId, int times);
+
+	/**
+	 * 更新抽奖金额
+	 * @param userId
+	 * @param amount 以分为单位
+	 * @return
+	 */
+	public boolean updateAmount(Long userId, Long amount);
+}

+ 8 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawGroupService.java

@@ -0,0 +1,8 @@
+package com.ym.mec.biz.service;
+
+import com.ym.mec.biz.dal.entity.LuckDrawGroup;
+import com.ym.mec.common.service.BaseService;
+
+public interface LuckDrawGroupService extends BaseService<Integer, LuckDrawGroup> {
+
+}

+ 16 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawLogService.java

@@ -0,0 +1,16 @@
+package com.ym.mec.biz.service;
+
+import com.ym.mec.biz.dal.entity.LuckDrawLog;
+import com.ym.mec.common.service.BaseService;
+
+public interface LuckDrawLogService extends BaseService<Long, LuckDrawLog> {
+
+	/**
+	 * 增加中奖记录
+	 * @param userId
+	 * @param prizeId
+	 * @param groupId
+	 * @return
+	 */
+	boolean add(Long userId, Integer prizeId, Integer groupId);
+}

+ 15 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/LuckDrawPrizeService.java

@@ -0,0 +1,15 @@
+package com.ym.mec.biz.service;
+
+import com.ym.mec.biz.dal.entity.LuckDrawPrize;
+import com.ym.mec.common.service.BaseService;
+
+public interface LuckDrawPrizeService extends BaseService<Integer, LuckDrawPrize> {
+
+	/**
+	 * 抽奖
+	 * @param userId 用户编号
+	 * @param group 奖品组
+	 * @return
+	 */
+	public LuckDrawPrize draw(Long userId, int group);
+}

+ 82 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawCountServiceImpl.java

@@ -0,0 +1,82 @@
+package com.ym.mec.biz.service.impl;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.ym.mec.biz.dal.dao.LuckDrawCountDao;
+import com.ym.mec.biz.dal.entity.LuckDrawCount;
+import com.ym.mec.biz.service.LuckDrawCountService;
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.common.service.impl.BaseServiceImpl;
+
+@Service
+public class LuckDrawCountServiceImpl extends BaseServiceImpl<Long, LuckDrawCount> implements LuckDrawCountService {
+
+	@Autowired
+	private LuckDrawCountDao luckDrawCountDao;
+
+	@Override
+	public BaseDAO<Long, LuckDrawCount> getDAO() {
+		return luckDrawCountDao;
+	}
+
+	@Override
+	public LuckDrawCount getLock(Long userId) {
+		return luckDrawCountDao.getLock(userId);
+	}
+
+	@Override
+	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+	public boolean freeGive(Long userId, int times) {
+		boolean isInsert = false;
+		LuckDrawCount luckDrawCount = luckDrawCountDao.getLock(userId);
+		if (luckDrawCount == null) {
+			luckDrawCount = new LuckDrawCount();
+			luckDrawCount.setUserId(userId);
+			isInsert = true;
+		}
+		luckDrawCount.setAvailableCount(luckDrawCount.getAvailableCount() + times);
+		luckDrawCount.setModifyOn(new Date());
+
+		return isInsert ? insert(luckDrawCount) > 0 : update(luckDrawCount) > 0;
+	}
+
+	@Override
+	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+	public boolean updateTimes(Long userId, int times) {
+		boolean isInsert = false;
+		LuckDrawCount luckDrawCount = luckDrawCountDao.getLock(userId);
+		if (luckDrawCount == null) {
+			luckDrawCount = new LuckDrawCount();
+			luckDrawCount.setUserId(userId);
+			isInsert = true;
+		}
+		luckDrawCount.setAvailableCount(luckDrawCount.getAvailableCount() + times);
+		luckDrawCount.setModifyOn(new Date());
+		return isInsert ? insert(luckDrawCount) > 0 : update(luckDrawCount) > 0;
+	}
+
+	@Override
+	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+	public boolean updateAmount(Long userId, Long amount) {
+		boolean isInsert = false;
+		LuckDrawCount luckDrawCount = luckDrawCountDao.getLock(userId);
+		if (luckDrawCount == null) {
+			luckDrawCount = new LuckDrawCount();
+			luckDrawCount.setUserId(userId);
+			isInsert = true;
+		}
+		luckDrawCount.setAvailableAmount(luckDrawCount.getAvailableAmount().add(new BigDecimal(amount)));
+		if (amount < 0) {
+			luckDrawCount.setUsedCount(luckDrawCount.getUsedCount() + 1);
+		}
+		luckDrawCount.setModifyOn(new Date());
+		return isInsert ? insert(luckDrawCount) > 0 : update(luckDrawCount) > 0;
+	}
+
+}

+ 23 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawGroupServiceImpl.java

@@ -0,0 +1,23 @@
+package com.ym.mec.biz.service.impl;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.ym.mec.biz.dal.dao.LuckDrawGroupDao;
+import com.ym.mec.biz.dal.entity.LuckDrawGroup;
+import com.ym.mec.biz.service.LuckDrawGroupService;
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.common.service.impl.BaseServiceImpl;
+
+@Service
+public class LuckDrawGroupServiceImpl extends BaseServiceImpl<Integer, LuckDrawGroup> implements LuckDrawGroupService {
+
+	@Autowired
+	private LuckDrawGroupDao luckDrawGroupDao;
+
+	@Override
+	public BaseDAO<Integer, LuckDrawGroup> getDAO() {
+		return luckDrawGroupDao;
+	}
+
+}

+ 35 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawLogServiceImpl.java

@@ -0,0 +1,35 @@
+package com.ym.mec.biz.service.impl;
+
+import java.util.Date;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.ym.mec.biz.dal.dao.LuckDrawLogDao;
+import com.ym.mec.biz.dal.entity.LuckDrawLog;
+import com.ym.mec.biz.service.LuckDrawLogService;
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.common.service.impl.BaseServiceImpl;
+
+@Service
+public class LuckDrawLogServiceImpl extends BaseServiceImpl<Long, LuckDrawLog> implements LuckDrawLogService {
+
+	@Autowired
+	private LuckDrawLogDao luckDrawLogDao;
+
+	@Override
+	public BaseDAO<Long, LuckDrawLog> getDAO() {
+		return luckDrawLogDao;
+	}
+
+	@Override
+	public boolean add(Long userId, Integer prizeId, Integer groupId) {
+		LuckDrawLog log = new LuckDrawLog();
+		log.setPrizeId(prizeId);
+		log.setUserId(userId);
+		log.setGroupId(groupId);
+		log.setCreateOn(new Date());
+		return luckDrawLogDao.insert(log) > 0;
+	}
+
+}

+ 147 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/impl/LuckDrawPrizeServiceImpl.java

@@ -0,0 +1,147 @@
+package com.ym.mec.biz.service.impl;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.RandomUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.ym.mec.biz.dal.dao.LuckDrawPrizeDao;
+import com.ym.mec.biz.dal.entity.LuckDrawCount;
+import com.ym.mec.biz.dal.entity.LuckDrawGroup;
+import com.ym.mec.biz.dal.entity.LuckDrawPrize;
+import com.ym.mec.biz.service.LuckDrawCountService;
+import com.ym.mec.biz.service.LuckDrawGroupService;
+import com.ym.mec.biz.service.LuckDrawLogService;
+import com.ym.mec.biz.service.LuckDrawPrizeService;
+import com.ym.mec.common.dal.BaseDAO;
+import com.ym.mec.common.exception.BizException;
+import com.ym.mec.common.service.impl.BaseServiceImpl;
+
+@Service
+public class LuckDrawPrizeServiceImpl extends BaseServiceImpl<Integer, LuckDrawPrize> implements LuckDrawPrizeService {
+
+	/** 抽奖概率的固定基数 */
+	private final int DRAW_BASE_NUMBER = 100000;
+
+	@Autowired
+	private LuckDrawPrizeDao luckDrawPrizeDao;
+
+	@Autowired
+	private LuckDrawLogService luckDrawLogService;
+
+	@Autowired
+	private LuckDrawCountService luckDrawCountService;
+
+	@Autowired
+	private LuckDrawGroupService luckDrawGroupService;
+
+	@Override
+	public BaseDAO<Integer, LuckDrawPrize> getDAO() {
+		return luckDrawPrizeDao;
+	}
+
+	@Override
+	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+	public LuckDrawPrize draw(final Long userId, int group) {
+		final LuckDrawGroup luckDrawGroup = luckDrawGroupService.get(group);
+		if (luckDrawGroup == null) {
+			throw new BizException("系统出错");
+		}
+		Date currentDate = new Date();
+		// 是否过期
+		if (currentDate.before(luckDrawGroup.getStartTime()) || currentDate.after(luckDrawGroup.getEndTime())) {
+			throw new BizException("抽奖未开始或已结束");
+		}
+
+		int consumeValue = luckDrawGroup.getConsumeValue();
+		String consumeType = luckDrawGroup.getConsumeType();
+
+		if (StringUtils.equalsIgnoreCase("TIMES", consumeType)) {
+			// 判断是否有抽奖机会
+			LuckDrawCount luckDrawCount = luckDrawCountService.getLock(userId);
+			if (luckDrawCount == null) {
+				throw new BizException("当前没有抽奖机会");
+			}
+			if (luckDrawCount.getAvailableCount() <= 0) {
+				throw new BizException("当前没有抽奖机会");
+			}
+			// 更新抽奖机会
+			luckDrawCount.setAvailableCount(luckDrawCount.getAvailableCount() - consumeValue);
+			luckDrawCount.setModifyOn(currentDate);
+			if (luckDrawCount.getUsedCount() == null) {
+				luckDrawCount.setUsedCount(1);
+			} else {
+				luckDrawCount.setUsedCount(luckDrawCount.getUsedCount() + consumeValue);
+			}
+			luckDrawCountService.update(luckDrawCount);
+		} else {
+			throw new BizException("系统数据异常");
+		}
+		// 抽奖逻辑
+		List<LuckDrawPrize> luckDraws = luckDrawPrizeDao.queryEnabledList(group);
+		if (luckDraws != null) {
+			int randomNum = RandomUtils.nextInt(DRAW_BASE_NUMBER);
+			double start = 0;
+			double chances = 0;
+			ExecutorService executor = Executors.newCachedThreadPool();
+			for (LuckDrawPrize luckDraw : luckDraws) {
+				chances += luckDraw.getChances();
+				// 抽中了
+				if (start <= randomNum && randomNum < (chances * DRAW_BASE_NUMBER)) {
+					final LuckDrawPrize syncLuckDraw = luckDrawPrizeDao.getLock(luckDraw.getId());
+					// 检查库存
+					if (syncLuckDraw.getStock() > 0) {
+						Date date = new Date();
+						// 减库存
+						syncLuckDraw.setStock(syncLuckDraw.getStock() - 1);
+						syncLuckDraw.setModifyOn(date);
+						update(syncLuckDraw);
+						// 抽奖记录
+						luckDrawLogService.add(userId, syncLuckDraw.getId(), group);
+
+						// 给奖励
+						FutureTask<String> task = new FutureTask<String>(new Callable<String>() {
+							@Override
+							public String call() throws Exception {
+
+								switch (syncLuckDraw.getRewardType()) {
+								case COUPON:
+									break;
+
+								case POINTS:
+									break;
+
+								case CASH:
+									break;
+
+								default:
+									break;
+								}
+
+								return null;
+							}
+						});
+						executor.submit(task);
+						executor.shutdown();
+
+						return syncLuckDraw;
+					} else {
+						throw new BizException("系统繁忙,请重试");
+					}
+				}
+				start = luckDraw.getChances() * DRAW_BASE_NUMBER;
+			}
+		}
+		return null;
+	}
+
+}

+ 63 - 0
mec-biz/src/main/resources/config/mybatis/LuckDrawCountMapper.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.ym.mec.biz.dal.dao.LuckDrawCountDao" >
+  <resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.LuckDrawCount" >
+    <id column="user_id_" property="userId" jdbcType="BIGINT" />
+    <result column="used_count_" property="usedCount" jdbcType="INTEGER" />
+    <result column="available_count_" property="availableCount" jdbcType="INTEGER" />
+    <result column="available_amount_" property="availableAmount.cent" jdbcType="BIGINT" />
+    <result column="modify_on_" property="modifyOn" jdbcType="TIMESTAMP" />
+  </resultMap>
+  <sql id="Base_Column_List" >
+    user_id_, used_count_, available_count_, available_amount_, modify_on_
+  </sql>
+  
+  <select id="get" resultMap="BaseResultMap" parameterType="java.lang.Long" >
+    select 
+    <include refid="Base_Column_List" />
+    from luck_draw_count
+    where user_id_ = #{userId,jdbcType=BIGINT}
+  </select>
+  
+  <select id="getLock" resultMap="BaseResultMap" parameterType="java.lang.Long" >
+    select 
+    <include refid="Base_Column_List" />
+    from luck_draw_count
+    where user_id_ = #{userId,jdbcType=BIGINT} for update
+  </select>
+  
+  <select id="findAll" resultMap="BaseResultMap">
+    select * from luck_draw_count
+  </select>
+  
+  <delete id="delete" parameterType="java.lang.Long" >
+    delete from luck_draw_count
+    where user_id_ = #{userId,jdbcType=BIGINT}
+  </delete>
+  
+  <insert id="insert" parameterType="com.ym.mec.biz.dal.entity.LuckDrawCount" >
+    insert into luck_draw_count (user_id_, used_count_, available_count_, available_amount_,
+      modify_on_)
+    values (#{userId,jdbcType=BIGINT}, #{usedCount,jdbcType=INTEGER}, #{availableCount,jdbcType=INTEGER}, #{availableAmount.cent,jdbcType=BIGINT}, 
+      #{modifyOn,jdbcType=TIMESTAMP})
+  </insert>
+  
+  <update id="update" parameterType="com.ym.mec.biz.dal.entity.LuckDrawCount" >
+    update luck_draw_count
+    <set >
+      <if test="usedCount != null" >
+        used_count_ = #{usedCount,jdbcType=INTEGER},
+      </if>
+      <if test="availableCount != null" >
+        available_count_ = #{availableCount,jdbcType=INTEGER},
+      </if>
+      <if test="availableAmount != null" >
+        available_amount_ = #{availableAmount.cent,jdbcType=BIGINT},
+      </if>
+      <if test="modifyOn != null" >
+        modify_on_ = #{modifyOn,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where user_id_ = #{userId,jdbcType=BIGINT}
+  </update>
+</mapper>

+ 63 - 0
mec-biz/src/main/resources/config/mybatis/LuckDrawGroupMapper.xml

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.ym.mec.biz.dal.dao.LuckDrawGroupDao" >
+  <resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.LuckDrawGroup" >
+    <id column="id_" property="id" jdbcType="INTEGER" />
+    <result column="name_" property="name" jdbcType="VARCHAR" />
+    <result column="consume_type_" property="consumeType" jdbcType="VARCHAR" />
+    <result column="consume_value_" property="consumeValue" jdbcType="INTEGER" />
+    <result column="start_time_" property="startTime" jdbcType="TIMESTAMP" />
+    <result column="end_time_" property="endTime" jdbcType="TIMESTAMP" />
+    <result column="create_on_" property="createOn" jdbcType="TIMESTAMP" />
+  </resultMap>
+  
+  <sql id="Base_Column_List" >
+    id_, name_, consume_type_, consume_value_, start_time_, end_time_, create_on_
+  </sql>
+  
+  <select id="get" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
+    select 
+    <include refid="Base_Column_List" />
+    from luck_draw_group
+    where id_ = #{id,jdbcType=INTEGER}
+  </select>
+  
+  <delete id="delete" parameterType="java.lang.Integer" >
+    delete from luck_draw_group
+    where id_ = #{id,jdbcType=INTEGER}
+  </delete>
+  
+  <insert id="insert" parameterType="com.ym.mec.biz.dal.entity.LuckDrawGroup" >
+    insert into luck_draw_group (id_, name_, consume_type_, consume_value_,
+      start_time_, end_time_, create_on_
+      )
+    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{consumeType,jdbcType=VARCHAR}, #{consumeValue,jdbcType=INTEGER},
+      #{startTime,jdbcType=TIMESTAMP}, #{endTime,jdbcType=TIMESTAMP}, #{createOn,jdbcType=TIMESTAMP}
+      )
+  </insert>
+
+  <update id="update" parameterType="com.ym.mec.biz.dal.entity.LuckDrawGroup" >
+    update luck_draw_group
+    <set >
+      <if test="name != null" >
+        name_ = #{name,jdbcType=VARCHAR},
+      </if>
+      <if test="consumeType != null" >
+        consume_type_ = #{consumeType,jdbcType=VARCHAR},
+      </if>
+      <if test="consumeValue != null" >
+        consume_value_ = #{consumeValue,jdbcType=INTEGER},
+      </if>
+      <if test="startTime != null" >
+        start_time_ = #{startTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="endTime != null" >
+        end_time_ = #{endTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="createOn != null" >
+        create_on_ = #{createOn,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where id_ = #{id,jdbcType=INTEGER}
+  </update>
+</mapper>

+ 108 - 0
mec-biz/src/main/resources/config/mybatis/LuckDrawLogMapper.xml

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.ym.mec.biz.dal.dao.LuckDrawLogDao">
+	<resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.LuckDrawLog">
+		<id column="id_" property="id" jdbcType="BIGINT" />
+		<result column="group_id_" property="groupId" jdbcType="INTEGER" />
+		<result column="prize_id_" property="prizeId" jdbcType="INTEGER" />
+		<result column="user_id_" property="userId" jdbcType="BIGINT" />
+		<result column="create_on_" property="createOn" jdbcType="TIMESTAMP" />
+		<result column="name_" property="luckDrawPrize.name" jdbcType="VARCHAR" />
+		<result column="reward_type_" property="luckDrawPrize.rewardType" typeHandler="com.ym.mec.common.dal.CustomEnumTypeHandler" />
+	</resultMap>
+	
+	<resultMap id="BaseResultMapExt" type="com.ym.mec.biz.dal.entity.LuckDrawLog" extends="BaseResultMap">
+		<result column="nickname_" property="user.nickname" jdbcType="VARCHAR" />
+		<result column="mobile_no_" property="user.mobileNo" jdbcType="VARCHAR" />
+	</resultMap>
+
+	<sql id="Base_Column_List">
+		l.id_,l.group_id_, l.prize_id_,d.name_,d.reward_type_, l.user_id_, l.create_on_
+	</sql>
+
+	<sql id="queryCondition">
+		<where>
+			<if test="prizeId != null">
+				and l.prize_id_ = #{id}
+			</if>
+			<if test="userId != null">
+				and l.user_id_ = #{userId}
+			</if>
+			<if test="name != null">
+				and d.name_ like '%' #{name} '%'
+			</if>
+			<if test="rewardType != null">
+				and d.reward_type_ like '%' #{rewardType} '%'
+			</if>
+			<if test="groupId != null">
+				and l.group_id_ = #{groupId}
+			</if>
+			<if test="startDate != null">
+				and l.create_on_ &gt;= #{startDate}
+			</if>
+			<if test="endDate != null">
+				and l.create_on_ &lt;= #{endDate}
+			</if>
+		</where>
+	</sql>
+
+	<select id="get" resultMap="BaseResultMap" parameterType="java.lang.Long">
+		select
+		<include refid="Base_Column_List" />
+		from luck_draw_log l left join luck_draw_prize d on
+		l.prize_id_ = d.id_
+		where l.id_ = #{id,jdbcType=BIGINT}
+	</select>
+
+	<delete id="delete" parameterType="java.lang.Long">
+		delete from
+		luck_draw_log
+		where id_ = #{id,jdbcType=BIGINT}
+	</delete>
+
+	<insert id="insert" parameterType="com.ym.mec.biz.dal.entity.LuckDrawLog">
+		insert into
+		luck_draw_log (id_,group_id_, prize_id_, user_id_,
+		create_on_)
+		values
+		(#{id,jdbcType=BIGINT}, #{groupId,jdbcType=INTEGER}, #{prizeId,jdbcType=INTEGER},
+		#{userId,jdbcType=BIGINT},
+		#{createOn,jdbcType=TIMESTAMP})
+	</insert>
+
+	<update id="update" parameterType="com.ym.mec.biz.dal.entity.LuckDrawLog">
+		update luck_draw_log
+		<set>
+			<if test="groupId != null">
+				group_id_ = #{groupId,jdbcType=INTEGER},
+			</if>
+			<if test="prizeId != null">
+				prize_id_ = #{prizeId,jdbcType=INTEGER},
+			</if>
+			<if test="userId != null">
+				user_id_ = #{userId,jdbcType=BIGINT},
+			</if>
+			<if test="createOn != null">
+				create_on_ = #{createOn,jdbcType=TIMESTAMP},
+			</if>
+		</set>
+		where id_ = #{id,jdbcType=BIGINT}
+	</update>
+
+	<select id="findCount" parameterType="map" resultType="int">
+		select count(*)
+		from (luck_draw_log l left join luck_draw_prize d on
+		l.prize_id_ = d.id_) left join sys_user u on u.id_=l.user_id_
+		<include refid="queryCondition" />
+	</select>
+
+	<select id="queryPage" parameterType="map" resultMap="BaseResultMapExt">
+		select
+		<include refid="Base_Column_List" />,nickname_,mobile_no_
+		from (luck_draw_log l left join luck_draw_prize d on
+		l.prize_id_ = d.id_) left join sys_user u on u.id_=l.user_id_
+		<include refid="queryCondition" />
+		<include refid="global.orderby" />
+		<include refid="global.limit" />
+	</select>
+</mapper>

+ 116 - 0
mec-biz/src/main/resources/config/mybatis/LuckDrawPrizeMapper.xml

@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.ym.mec.biz.dal.dao.LuckDrawDao">
+	<resultMap id="BaseResultMap" type="com.ym.mec.biz.dal.entity.LuckDrawPrize">
+		<id column="id_" property="id" jdbcType="INTEGER" />
+		<result column="name_" property="name" jdbcType="VARCHAR" />
+		<result column="chances_" property="chances" jdbcType="DOUBLE" />
+		<result column="stock_" property="stock" jdbcType="INTEGER" />
+		<result column="enabled_" property="enabled" jdbcType="BIT" />
+		<result column="reward_type_" property="rewardType" typeHandler="com.ym.mec.common.dal.CustomEnumTypeHandler" />
+		<result column="memo_" property="memo" jdbcType="VARCHAR" />
+		<result column="group_id_" property="groupId" jdbcType="INTEGER" />
+		<result column="create_on_" property="createOn" jdbcType="TIMESTAMP" />
+		<result column="modify_on_" property="modifyOn" jdbcType="TIMESTAMP" />
+	</resultMap>
+
+	<sql id="Base_Column_List">
+		id_, name_, chances_, stock_, enabled_, reward_type_, memo_, group_id_, create_on_, modify_on_
+	</sql>
+
+	<sql id="queryCondition">
+		<where>
+			<if test="id != null">
+				and id_ = #{id}
+			</if>
+			<if test="name != null">
+				and name_ like '%' #{name} '%'
+			</if>
+			<if test="rewardType != null">
+				and reward_type_ like '%' #{rewardType} '%'
+			</if>
+		</where>
+	</sql>
+
+	<select id="get" resultMap="BaseResultMap" parameterType="java.lang.Integer">
+		select
+		<include refid="Base_Column_List" />
+		from luck_draw_prize
+		where id_ = #{id,jdbcType=INTEGER}
+	</select>
+
+	<select id="getLock" resultMap="BaseResultMap" parameterType="java.lang.Integer">
+		select
+		<include refid="Base_Column_List" />
+		from luck_draw_prize
+		where id_ = #{id,jdbcType=INTEGER} for update
+	</select>
+
+	<delete id="delete" parameterType="java.lang.Integer">
+		delete from luck_draw_prize
+		where id_ = #{id,jdbcType=INTEGER}
+	</delete>
+
+	<insert id="insert" parameterType="com.ym.mec.biz.dal.entity.LuckDrawPrize">
+		insert into luck_draw_prize (id_, name_, chances_,
+		stock_, enabled_, reward_type_, memo_, group_id_, create_on_,
+		modify_on_)
+		values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},
+		#{chances,jdbcType=DOUBLE},
+		#{stock,jdbcType=INTEGER}, #{enabled,jdbcType=BIT},#{rewardType,typeHandler=com.ym.mec.common.dal.CustomEnumTypeHandler}, #{memo,jdbcType=VARCHAR}, #{groupId,jdbcType=INTEGER}, #{createOn,jdbcType=TIMESTAMP},
+		#{modifyOn,jdbcType=TIMESTAMP})
+	</insert>
+
+	<update id="update" parameterType="com.ym.mec.biz.dal.entity.LuckDrawPrize">
+		update luck_draw_prize
+		<set>
+			<if test="name != null">
+				name_ = #{name,jdbcType=VARCHAR},
+			</if>
+			<if test="chances != null">
+				chances_ = #{chances,jdbcType=DOUBLE},
+			</if>
+			<if test="stock != null">
+				stock_ = #{stock,jdbcType=INTEGER},
+			</if>
+			<if test="enabled != null">
+				enabled_ = #{enabled,jdbcType=BIT},
+			</if>
+			<if test="rewardType != null">
+				reward_type_ = #{rewardType,typeHandler=com.ym.mec.common.dal.CustomEnumTypeHandler},
+			</if>
+			<if test="memo != null">
+				memo_ = #{memo,jdbcType=VARCHAR},
+			</if>
+			<if test="groupId != null">
+				group_id_ = #{groupId,jdbcType=INTEGER},
+			</if>
+			<if test="createOn != null">
+				create_on_ = #{createOn,jdbcType=TIMESTAMP},
+			</if>
+			<if test="modifyOn != null">
+				modify_on_ = #{modifyOn,jdbcType=TIMESTAMP},
+			</if>
+		</set>
+		where id_ = #{id,jdbcType=INTEGER}
+	</update>
+
+	<select id="findCount" parameterType="map" resultType="int">
+		select count(*) from luck_draw_prize
+		<include refid="queryCondition" />
+	</select>
+
+	<select id="queryPage" parameterType="map" resultMap="BaseResultMap">
+		select * from luck_draw_prize
+		<include refid="queryCondition" />
+		<include refid="global.orderby" />
+		<include refid="global.limit" />
+	</select>
+
+	<select id="queryEnabledList" resultMap="BaseResultMap" parameterType="int">
+		select
+		<include refid="Base_Column_List" />
+		from luck_draw_prize
+		where enabled_ = 1 and group_id_ = #{group} order by id_ asc
+	</select>
+</mapper>

+ 70 - 0
mec-web/src/main/java/com/ym/mec/web/controller/LuckDrawController.java

@@ -0,0 +1,70 @@
+package com.ym.mec.web.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import java.util.Date;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.ym.mec.biz.dal.entity.LuckDrawPrize;
+import com.ym.mec.biz.dal.page.LuckDrawQueryInfo;
+import com.ym.mec.biz.service.LuckDrawLogService;
+import com.ym.mec.biz.service.LuckDrawPrizeService;
+import com.ym.mec.common.controller.BaseController;
+
+@Api(tags = "抽奖")
+@RestController
+public class LuckDrawController extends BaseController {
+
+	@Autowired
+	private LuckDrawPrizeService luckDrawPrizeService;
+
+	@Autowired
+	private LuckDrawLogService luckDrawLogService;
+
+	@ApiOperation(value = "查询奖品列表")
+	@GetMapping(value = "luckDrawPrize/list", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+	@PreAuthorize("@pcs.hasPermissions('luckDrawPrize/list')")
+	public Object list(LuckDrawQueryInfo queryInfo) {
+		return succeed(luckDrawPrizeService.queryPage(queryInfo));
+	}
+
+	@ApiOperation(value = "新增抽奖奖品")
+	@PostMapping(value = "luckDrawPrize/add", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+	@PreAuthorize("@pcs.hasPermissions('luckDrawPrize/add')")
+	public Object add(@RequestBody LuckDrawPrize luckDrawPrize) {
+		Date date = new Date();
+		luckDrawPrize.setCreateOn(date);
+		luckDrawPrize.setModifyOn(date);
+		return luckDrawPrizeService.insert(luckDrawPrize) > 0 ? succeed() : failed();
+	}
+
+	@ApiOperation(value = "编辑抽奖奖品")
+	@PostMapping(value = "luckDrawPrize/update", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+	@PreAuthorize("@pcs.hasPermissions('luckDrawPrize/update')")
+	public Object update(@RequestBody LuckDrawPrize luckDrawPrize) {
+		LuckDrawPrize oriGoods = luckDrawPrizeService.get(luckDrawPrize.getId());
+		oriGoods.setChances(luckDrawPrize.getChances());
+		oriGoods.setEnabled(luckDrawPrize.getEnabled());
+		oriGoods.setName(luckDrawPrize.getName());
+		oriGoods.setStock(luckDrawPrize.getStock());
+		Date date = new Date();
+		oriGoods.setModifyOn(date);
+		return luckDrawPrizeService.update(oriGoods) > 0 ? succeed() : failed();
+	}
+
+	@ApiOperation(value = "查询抽奖列表")
+	@GetMapping(value = "luckDrawLog/rewardlist", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+	@PreAuthorize("@pcs.hasPermissions('luckDrawLog/rewardlist')")
+	public Object rewardlist(LuckDrawQueryInfo queryInfo) {
+		return succeed(luckDrawLogService.queryPage(queryInfo));
+	}
+
+}