| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- package com.ruoyi.app.user;
- import java.text.ParseException;
- import java.text.SimpleDateFormat;
- import java.time.LocalDate;
- import java.time.format.DateTimeFormatter;
- import java.util.*;
- import java.util.stream.Collectors;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
- import com.baomidou.mybatisplus.core.metadata.IPage;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.github.pagehelper.PageHelper;
- import com.ruoyi.app.user.dto.ReceiveQuanyiInput;
- import com.ruoyi.common.annotation.Anonymous;
- import com.ruoyi.common.annotation.RepeatSubmit;
- import com.ruoyi.common.core.domain.R;
- import com.ruoyi.common.exception.ServiceException;
- import com.ruoyi.common.utils.MessageUtils;
- import com.ruoyi.common.utils.StringUtils;
- import com.ruoyi.system.domain.SalesPromotion;
- import com.ruoyi.system.domain.VipQuanyi;
- import com.ruoyi.system.service.ISalesPromotionService;
- import com.ruoyi.system.service.IVipQuanyiService;
- import com.ruoyi.system.utils.Auth;
- import com.ruoyi.system.utils.JwtUtil;
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
- import org.apache.commons.lang3.time.DateUtils;
- import org.springframework.security.access.prepost.PreAuthorize;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.web.bind.annotation.*;
- import com.ruoyi.common.core.controller.BaseController;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.system.domain.VipUserQuanyi;
- import com.ruoyi.system.service.IVipUserQuanyiService;
- import com.ruoyi.common.core.page.TableDataInfo;
- import redis.clients.jedis.Jedis;
- /**
- * 用户优惠券
- * Controller
- *
- * @author ruoyi
- * @date 2025-05-09
- */
- @Api("用户优惠券管理")
- @RestController
- @RequestMapping("/system/userQuanyi")
- public class VipUserQuanyiController extends BaseController {
- @Autowired
- private IVipUserQuanyiService vipUserQuanyiService;
- @Autowired
- private IVipQuanyiService vipQuanyiService;
- @Autowired
- private ISalesPromotionService promotionService;
- @Anonymous
- @Auth
- @ApiOperation("可用活动分页列表")
- @GetMapping("/promotionList")
- public R<IPage<SalesPromotion>> promotionList(@RequestHeader String token,
- @RequestParam Integer pageNum,
- @RequestParam Integer pageSize,
- // @RequestParam String language,
- @RequestParam(defaultValue = "") String mdId,
- @RequestParam(defaultValue = "") String price
- ) {
- System.out.println("promotionList");
- JwtUtil jwtUtil = new JwtUtil();
- String uid = jwtUtil.getusid(token);
- String language = getLanguage(uid);
- IPage<SalesPromotion> stlist = new Page<>(pageNum, pageSize);
- LambdaQueryWrapper<SalesPromotion> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(SalesPromotion::getSalesState, "0");
- queryWrapper.ge(SalesPromotion::getEndTime,
- DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH));
- queryWrapper.eq(SalesPromotion::getDeleted, "0");
- queryWrapper.eq(SalesPromotion::getLanguage, language);
- if (!"".equals(price)) {
- queryWrapper.and(is -> is.le(SalesPromotion::getSalesCondition, price).or().isNull(SalesPromotion::getSalesCondition));
- }
- if (!"".equals(mdId)) {
- // 查询平台优惠券(mdId为空)或当前商家的优惠券
- queryWrapper.and(wrapper -> wrapper.isNull(SalesPromotion::getShId)
- .or()
- .eq(SalesPromotion::getShId, mdId));
- }
- IPage<SalesPromotion> list = promotionService.page(stlist, queryWrapper);
- return R.ok(list);
- }
- private String getLanguage(String uid) {
- Jedis jedis = new Jedis("localhost", 6379);
- String lang = jedis.get(uid);
- System.out.println("从redis获取的语言是:" + lang);
- String result = "0";
- if ("zh-CN".equals(lang)) {
- result = "2";
- }
- if ("zh-TW".equals(lang)) {
- result = "3";
- }
- if ("en-US".equals(lang)) {
- result = "1";
- }
- System.out.println("获取的语言是:" + result);
- return result;
- }
- /**
- * @param token
- * @param mdId
- * @param price
- * @param yfPrice
- * @return
- */
- @ApiOperation("用户生成订单时可用优惠券列表")
- @GetMapping("/orderyhList")
- @Anonymous
- @Auth
- public R<List<VipUserQuanyi>> orderyhList(@RequestHeader String token,
- @RequestParam(defaultValue = "") String mdId,
- @RequestParam(defaultValue = "") String price,
- @RequestParam(defaultValue = "") String yfPrice) {
- JwtUtil jwtUtil = new JwtUtil();
- String uid = jwtUtil.getusid(token);
- String language = getLanguage(uid);
- LambdaQueryWrapper<VipUserQuanyi> queryWrapper = new LambdaQueryWrapper<>();
- // 基础必选条件
- queryWrapper.eq(VipUserQuanyi::getUserId, uid)
- .eq(VipUserQuanyi::getDeleted, "0")
- .eq(VipUserQuanyi::getLanguage, language)
- .gt(VipUserQuanyi::getValidity, DateUtils.truncate(new Date(), Calendar.DAY_OF_MONTH))
- .eq(VipUserQuanyi::getState, "0");
- //传0 表示自提,去掉运费优惠券
- if (yfPrice.equals("0")) {
- queryWrapper.ne(VipUserQuanyi::getYhfangs, "1");
- }
- // 门店ID条件
- if (StringUtils.isNotBlank(mdId)) {
- queryWrapper.and(wrapper ->
- wrapper.eq(VipUserQuanyi::getShId, mdId)
- .or()
- .isNull(VipUserQuanyi::getShId)
- );
- }
- queryWrapper.and(sub -> {
- sub.nested(nonShip ->
- nonShip.nested(cond -> cond.le(VipUserQuanyi::getTiaojian, price)
- .or()
- .nested(cn -> cn.isNull(VipUserQuanyi::getTiaojian))
- )
- );
- }
- );
- // // 动态构建价格条件
- // boolean hasPrice = StringUtils.isNotBlank(price);
- // boolean hasYfPrice = StringUtils.isNotBlank(yfPrice);
- // if (hasPrice || hasYfPrice) {
- // queryWrapper.and(wrap -> {
- // // 非运费条件块(sales_type <> 1)
- // if (hasPrice) {
- // wrap.and(sub ->
- // sub.nested(nonShip ->
- // nonShip.nested(cond -> cond.le(VipUserQuanyi::getTiaojian, price).ne(VipUserQuanyi::getYhfangs, "1"))
- // .or()
- // .nested(cond -> cond.isNull(VipUserQuanyi::getTiaojian).ne(VipUserQuanyi::getYhfangs, "1"))
- // )
- // );
- // }
- //
- // // 运费条件块(sales_type = 1)
- // if (hasYfPrice) {
- // wrap.or(sub ->
- // sub.nested(ship ->
- // ship.nested(cond -> cond.le(VipUserQuanyi::getTiaojian, yfPrice).eq(VipUserQuanyi::getYhfangs, "1"))
- // .or()
- // .nested(cond -> cond.isNull(VipUserQuanyi::getTiaojian).eq(VipUserQuanyi::getYhfangs, "1"))
- // )
- // );
- // }
- // });
- // }
- // 排序
- queryWrapper.orderByDesc(VipUserQuanyi::getValidity);
- List<VipUserQuanyi> list = vipUserQuanyiService.list(queryWrapper);
- List<VipUserQuanyi> result = list.stream()
- .filter(item -> item.getQuanyiId() != null) // 可选:过滤掉quanyiId为null的
- .collect(Collectors.groupingBy(
- VipUserQuanyi::getQuanyiId,
- Collectors.minBy(Comparator.comparing(VipUserQuanyi::getValidity))
- ))
- .values().stream()
- .filter(Optional::isPresent)
- .map(Optional::get)
- .collect(Collectors.toList());
- return R.ok(result);
- }
- @ApiOperation("用户总的可用、过期优惠券分页列表")
- @GetMapping("/list")
- @Anonymous
- @Auth
- public R<IPage<VipUserQuanyi>> expiredList(@RequestHeader String token,
- @RequestParam Integer pageNum,
- @RequestParam Integer pageSize,
- @RequestParam int listType
- ) {
- JwtUtil jwtUtil = new JwtUtil();
- String uid = jwtUtil.getusid(token);
- String language = getLanguage(uid);
- IPage<VipUserQuanyi> stlist = new Page<>(pageNum, pageSize);
- LambdaQueryWrapper<VipUserQuanyi> queryWrapper = new LambdaQueryWrapper<>();
- queryWrapper.eq(VipUserQuanyi::getUserId, uid);
- queryWrapper.eq(VipUserQuanyi::getLanguage, language);
- if (listType == 2) {
- queryWrapper.lt(VipUserQuanyi::getValidity, DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH));
- queryWrapper.eq(VipUserQuanyi::getState, "0");
- }
- if (listType == 1) {
- queryWrapper.ge(VipUserQuanyi::getValidity, DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH));
- queryWrapper.eq(VipUserQuanyi::getState, "0");
- }
- queryWrapper.orderBy(true, false, VipUserQuanyi::getValidity);
- IPage<VipUserQuanyi> list = vipUserQuanyiService.page(stlist, queryWrapper);
- return R.ok(list);
- }
- @Anonymous
- @Auth
- @ApiOperation("待领取优惠券列表")
- @GetMapping("/userUnclaimedList")
- public TableDataInfo userUnclaimedList(@RequestHeader String token,
- @RequestParam Integer pageNum,
- @RequestParam Integer pageSize,
- @RequestParam(required = false) Long mdId
- ) {
- JwtUtil jwtUtil = new JwtUtil();
- String uid = jwtUtil.getusid(token);
- String language = getLanguage(uid);
- PageHelper.startPage(pageNum, pageSize);
- List<VipQuanyi> list = vipQuanyiService.userUnclaimedList(Long.valueOf(uid), language, mdId);
- return getDataTable(list);
- }
- @Anonymous
- @Auth
- @ApiOperation("用户领取优惠券")
- @PostMapping("/receive")
- @RepeatSubmit(interval = 1000, message = "请求过于频繁")
- @Transactional(rollbackFor = Exception.class)
- public R<String> receive(@RequestHeader String token, @RequestBody ReceiveQuanyiInput input) {
- JwtUtil jwtUtil = new JwtUtil();
- String userId = jwtUtil.getusid(token);
- LambdaQueryWrapper<VipQuanyi> query = new LambdaQueryWrapper<>();
- query.eq(VipQuanyi::getId, input.getQuanyiId());
- query.eq(VipQuanyi::getDeleted, "0");
- VipQuanyi quanyi = vipQuanyiService.getOne(query);
- if (quanyi == null) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqnodata"));
- }
- if ("1".equals(quanyi.getState())) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqyhqgb"));
- }
- if (quanyi.getTotal() != null && quanyi.getTotal().equals(quanyi.getClaimedCount())) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqyhqolqw"));
- }
- // 3. 检查用户输入数量是否合法
- if (input.num <= 0) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqyhqdy"));
- }
- // 4. 检查用户还能领取多少
- // 4.1 检查每人领取限制
- LambdaQueryWrapper<VipUserQuanyi> userCouponQuery = new LambdaQueryWrapper<>();
- userCouponQuery.eq(VipUserQuanyi::getUserId, userId)
- .eq(VipUserQuanyi::getQuanyiId, input.quanyiId);
- long userAlreadyClaimed = vipUserQuanyiService.count(userCouponQuery);
- int remainingPerUser = quanyi.getLqxz() - (int) userAlreadyClaimed;
- if (remainingPerUser <= 0) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqyhqysx"));
- }
- // 4.2 检查剩余库存
- long remainingStock = quanyi.getTotal() - quanyi.getClaimedCount();
- if (remainingStock <= 0) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqyhqolqw"));
- }
- // 4.3 确定实际可领取数量
- int actualReceiveNum = Math.min(input.num, remainingPerUser);
- actualReceiveNum = (int) Math.min(actualReceiveNum, remainingStock);
- Long version = quanyi.getVersion() != null ? quanyi.getVersion() + 1 : 0L;
- // 5. 使用乐观锁更新优惠券库存(防止并发超领)
- boolean updateSuccess = vipQuanyiService.update(
- new LambdaUpdateWrapper<VipQuanyi>()
- .eq(VipQuanyi::getId, input.quanyiId)
- .eq(VipQuanyi::getVersion, quanyi.getVersion()) // 乐观锁条件
- .set(VipQuanyi::getClaimedCount, quanyi.getClaimedCount() + actualReceiveNum)
- .set(VipQuanyi::getVersion, version)
- );
- if (!updateSuccess) {
- throw new ServiceException(MessageUtils.message("no.youhuiquan.lqyhqybxg"));
- }
- // 6. 为用户添加优惠券记录
- List<VipUserQuanyi> couponsToAdd = new ArrayList<>();
- Date now = new Date();
- Date expireTime = calculateExpireTime(now, quanyi.getValidity());
- for (int i = 0; i < actualReceiveNum; i++) {
- VipUserQuanyi coupon = new VipUserQuanyi();
- coupon.setUserId(Long.valueOf(userId));
- coupon.setQuanyiId(input.quanyiId);
- coupon.setCode(generateCouponCode());
- coupon.setState("0"); // 0-未使用
- coupon.setCreateTime(now);
- coupon.setValidity(expireTime);
- coupon.setYhfangs(quanyi.getYhfangs());
- coupon.setYhnum(quanyi.getYhnum());
- coupon.setName(quanyi.getName());
- coupon.setShuoming(quanyi.getShuoming());
- coupon.setTiaojian(quanyi.getTiaojian());
- coupon.setDeleted("0");
- coupon.setShId(quanyi.getShId());
- coupon.setSpId(quanyi.getSpId());
- coupon.setLanguage(quanyi.getLanguage());
- coupon.setPoster(quanyi.getPoster());
- coupon.setType(quanyi.getType());
- coupon.setMerchantId(quanyi.getMerchantId());
- couponsToAdd.add(coupon);
- }
- vipUserQuanyiService.saveBatch(couponsToAdd);
- return R.ok();
- }
- // 生成优惠券码
- private String generateCouponCode() {
- return UUID.randomUUID().toString().replace("-", "").substring(0, 12).toUpperCase();
- }
- // 计算过期时间
- private Date calculateExpireTime(Date now, Integer validityDays) {
- if (validityDays == null || validityDays <= 0) {
- return null; // 表示永久有效
- }
- Calendar calendar = Calendar.getInstance();
- calendar.setTime(now);
- calendar.add(Calendar.DAY_OF_MONTH, validityDays);
- return calendar.getTime();
- }
- /**
- * 获取用户优惠券
- * 详细信息
- */
- @Anonymous
- @Auth
- @ApiOperation("用户领取优惠券详情")
- @GetMapping(value = "/{id}")
- public AjaxResult getInfo(@PathVariable("id") Long id) {
- return success(vipUserQuanyiService.selectVipUserQuanyiById(id));
- }
- }
|