44323
2024-05-29 fe3b034bfcb263336667bac9d4a002360533951b
bug修改
18个文件已修改
2个文件已添加
1108 ■■■■ 已修改文件
ruoyi-api/ruoyi-api-goods/src/main/java/com/ruoyi/goods/api/feignClient/GoodsClient.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/R.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/TGoodsController.java 344 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/Recipient.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/dto/GoodExchangeDTO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/service/ITGoodsService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/TGoodsServiceImpl.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/MyQrCodeUtil.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/QRCodeUtil.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/vo/GoodDetailVO.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TStoryController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TStudyController.java 250 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TSubjectController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java 134 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TUser.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TUserStudy.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-goods/src/main/java/com/ruoyi/goods/api/feignClient/GoodsClient.java
@@ -56,7 +56,7 @@
     *
     * @return 推荐商品信息
     */
    @GetMapping("/goodRecommend")
    @GetMapping("/base/goods/goodRecommend")
    @ApiOperation(value = "可兑换商品推荐", tags = {"可兑换商品推荐"})
    R<List<TGoodsVO>> goodRecommend();
ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/factory/StudyFallbackFactory.java
@@ -144,6 +144,16 @@
            public R<Boolean> exchangeIntegral(Integer integral, String method) {
                return R.fail("用户积分变动失败" + cause.getMessage());
            }
            @Override
            public R<Boolean> addIntegralDetail1(String integral, String method) {
                return null;
            }
            @Override
            public R<Boolean> exchangeIntegral1(Integer integral, String method) {
                return null;
            }
        };
    }
}
ruoyi-api/ruoyi-api-study/src/main/java/com/ruoyi/study/api/feignClient/StudyClient.java
@@ -205,4 +205,25 @@
    @ApiOperation(value = "用户积分变动", tags = {"用户积分变动"})
    R<Boolean> exchangeIntegral(@RequestParam("integral") Integer integral, @RequestParam("method") String method);
    /**
     * 生成积分明细-用于远程调用
     *
     * @param integral 积分变动信息
     * @param method   变动源
     * @return 操作结果
     */
    @GetMapping("/base/study/addIntegralDetail1")
    R<Boolean> addIntegralDetail1(@RequestParam("integral") String integral, @RequestParam("method") String method);
    /**
     * 用户积分变动(增加或减少)-用于远程调用
     *
     * @param integral 积分变动信息
     * @param method   变动源
     * @return 操作结果
     */
    @GetMapping("/base/study/exchangeIntegral1")
    @ApiOperation(value = "用户积分变动", tags = {"用户积分变动"})
    R<Boolean> exchangeIntegral1(@RequestParam("integral") Integer integral, @RequestParam("method") String method);
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
@@ -50,6 +50,10 @@
     * 成功标记
     */
    public static final Integer SUCCESS = 200;
    /**
     * 仅会员查看
     */
    public static final Integer VIP_ERROR = 501;
    /**
     * 失败标记
@@ -59,6 +63,18 @@
     * 登录失效
     */
    public static final Integer TOKEN_ERROR = 600;
    /**
     * 账号冻结
     */
    public static final Integer FREEZE = 502;
    /**
     * 短信验证码无效
     */
    public static final Integer ERRORCODE = 503;
    /**
     * 积分商城兑换失败code
     */
    public static final Integer EXCHANGECODE = 506;
    /**
     * 登录成功状态
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/R.java
@@ -14,9 +14,20 @@
    /** 成功 */
    public static final int SUCCESS = Constants.SUCCESS;
    public static final int VIPERROR = Constants.VIP_ERROR;
    /** 失败 */
    public static final int FAIL = Constants.FAIL;
    /** 积分商城兑换失败 */
    public static final int EXCHANGECODE = Constants.EXCHANGECODE;
    /**
     * 账号被冻结
     */
    public static final int FREEZE = Constants.FREEZE;
    /**
     * 短信验证码无效
     */
    public static final int ERRORCODE = Constants.ERRORCODE;
    /**
     * 登陆失效
     */
@@ -37,6 +48,10 @@
    {
        return restResult(data, SUCCESS, null);
    }
    public static <T> R<T> vipError(String msg)
    {
        return restResult(null, VIPERROR, msg);
    }
    public static <T> R<T> ok(T data, String msg)
    {
@@ -57,6 +72,29 @@
        return restResult(null, FAIL, msg);
    }
    /**
     * 商城兑换失败code
     * @param msg
     * @return
     * @param <T>
     */
    public static <T> R<T> exchangeError(String msg)
    {
        return restResult(null, EXCHANGECODE, msg);
    }
    public static <T> R<T> freeze(String msg)
    {
        return restResult(null, FREEZE, msg);
    }
    public static <T> R<T> errorCode(String msg)
    {
        return restResult(null, ERRORCODE, msg);
    }
    public static <T> R<T> errCode(String msg)
    {
        return restResult(null, FREEZE, msg);
    }
    public static <T> R<T> fail(T data)
    {
        return restResult(data, FAIL, null);
ruoyi-service/ruoyi-goods/pom.xml
@@ -17,6 +17,11 @@
    <dependencies>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-api-study</artifactId>
            <version>3.6.2</version>
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/controller/TGoodsController.java
@@ -1,6 +1,7 @@
package com.ruoyi.goods.controller;
import com.alibaba.fastjson2.util.UUIDUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.page.PageInfo;
@@ -8,6 +9,8 @@
import com.ruoyi.goods.domain.*;
import com.ruoyi.goods.dto.*;
import com.ruoyi.goods.service.*;
import com.ruoyi.goods.utils.MyQrCodeUtil;
import com.ruoyi.goods.utils.QRCodeUtil;
import com.ruoyi.goods.vo.GoodDetailVO;
import com.ruoyi.goods.vo.TGoodsVO;
import com.ruoyi.goods.vo.TOrderVO;
@@ -16,18 +19,20 @@
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.logging.log4j.core.util.UuidUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
 * <p>
@@ -69,15 +74,46 @@
    }
    @PostMapping("/goodList")
    @ApiOperation(value = "商品列表查询", tags = {"学习端-商品列表"})
    @ApiOperation(value = "商品列表查询", tags = {"家长端-商品列表"})
    public R<PageInfo<TGoods>> listType(@RequestBody GoodQueryDTO goodQuery) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        List<String> type = goodQuery.getType();
        String keywords = goodQuery.getKeywords();
        // 初始化条件构造器
        QueryWrapper<TGoods> wrapper = new QueryWrapper<>();
        wrapper = keywords != null && "".equals(keywords.trim()) ? wrapper.like("name", keywords) : wrapper;
        // 类型匹配 todo
        wrapper = type.isEmpty() ? wrapper : wrapper.in("");
        if (goodQuery.getType()!=null && goodQuery.getType().size()>0){
            StringBuilder temp = new StringBuilder("");
            for (String s : goodQuery.getType()) {
                wrapper.or().apply("FIND_IN_SET('" + s + "', typeIds)"); // 将每个类型 ID 应用于 FIND_IN_SET 函数
            }
        }
        wrapper.eq("isDelete", 0);
        return R.ok(goodsService.page(new PageInfo<>(goodQuery.getPageNumber(), goodQuery.getPageSize()), wrapper));
    }
    @PostMapping("/goodListStudy")
    @ApiOperation(value = "商品列表查询", tags = {"学习端"})
    public R<PageInfo<TGoods>> goodListStudy(@RequestBody GoodQueryDTO goodQuery) {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        List<String> type = goodQuery.getType();
        String keywords = goodQuery.getKeywords();
        // 初始化条件构造器
        QueryWrapper<TGoods> wrapper = new QueryWrapper<>();
        wrapper = keywords != null && "".equals(keywords.trim()) ? wrapper.like("name", keywords) : wrapper;
        // 类型匹配 todo
        if (goodQuery.getType()!=null && goodQuery.getType().size()>0){
            StringBuilder temp = new StringBuilder("");
            for (String s : goodQuery.getType()) {
                wrapper.or().apply("FIND_IN_SET('" + s + "', typeIds)"); // 将每个类型 ID 应用于 FIND_IN_SET 函数
            }
        }
        wrapper.eq("isDelete", 0);
        return R.ok(goodsService.page(new PageInfo<>(goodQuery.getPageNumber(), goodQuery.getPageSize()), wrapper));
    }
@@ -173,16 +209,44 @@
        return R.ok(orderService.lambdaQuery().eq(TOrder::getUserId, tokenService.getLoginUserStudy().getUserid())
                .orderByDesc(TOrder::getCreateTime).list());
    }
    @GetMapping("/exchangeRecordParent")
    @ApiOperation(value = "家长端-兑换记录", tags = {"家长端-兑换记录"})
    public R<List<TOrder>> exchangeRecordParent() {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        return R.ok(orderService.lambdaQuery().eq(TOrder::getUserId, tokenService.getLoginUser1().getUserid())
                .orderByDesc(TOrder::getCreateTime).list());
    }
    /**
     * 兑换记录
     */
    @GetMapping("/confirm")
    @ApiOperation(value = "确认收货", tags = {"兑换记录"})
    @ApiOperation(value = "确认收货", tags = {"家长端-兑换记录"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "订单id", name = "id", dataType = "String", required = true)
    })
    public R<Boolean> confirm(@RequestParam Integer id) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        TOrder byId = orderService.getById(id);
        byId.setState(3);
        return R.ok(orderService.updateById(byId));
    }
    /**
     * 兑换记录
     */
    @GetMapping("/confirmStudy")
    @ApiOperation(value = "确认收货", tags = {"学习端-兑换记录"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "订单id", name = "id", dataType = "String", required = true)
    })
    public R<Boolean> confirmStudy(@RequestParam Integer id) {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        TOrder byId = orderService.getById(id);
        byId.setState(3);
        return R.ok(orderService.updateById(byId));
@@ -191,9 +255,93 @@
    /**
     * 获取用户收货地址
     */
    @GetMapping("/shopAddressParent")
    @ApiOperation(value = "获取用户收货地址", tags = {"家长端-获取用户收货地址"})
    public R<List<Recipient>> shopAddressParent() {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        return R.ok(recipientService.lambdaQuery().eq(Recipient::getUserId,
                tokenService.getLoginUser1().getUserid()).list());
    }
    /**
     * 设置默认地址
     */
    @GetMapping("/setDefault")
    @ApiOperation(value = "设置默认地址", tags = {"家长端-设置默认地址"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "地址id", name = "id", dataType = "String", required = true)
    })
    public R setDefault(@RequestParam Integer id) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        Recipient byId = recipientService.getById(id);
        byId.setIsDefault(1);
        recipientService.updateById(byId);
        return R.ok();
    }
    /**
     * 设置默认地址
     */
    @GetMapping("/setDefaultStudy")
    @ApiOperation(value = "设置默认地址", tags = {"学习端-设置默认地址"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "地址id", name = "id", dataType = "String", required = true)
    })
    public R setDefaultStudy(@RequestParam Integer id) {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        Recipient byId = recipientService.getById(id);
        byId.setIsDefault(1);
        recipientService.updateById(byId);
        return R.ok();
    }
    /**
     * 根据地址id 获取详情
     * @param id
     * @return
     */
    @GetMapping("/getAddressById")
    @ApiOperation(value = "获取地址详情", tags = {"家长端-获取地址详情"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "地址id", name = "id", dataType = "String", required = true)
    })
    public R<Recipient> getAddressById(@RequestParam Integer id) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        Recipient byId = recipientService.getById(id);
        return R.ok(byId);
    }
    /**
     * 根据地址id 获取详情
     * @param id
     * @return
     */
    @GetMapping("/getAddressByIdStudy")
    @ApiOperation(value = "获取地址详情", tags = {"学习端-获取地址详情"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "地址id", name = "id", dataType = "String", required = true)
    })
    public R<Recipient> getAddressByIdStudy(@RequestParam Integer id) {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        Recipient byId = recipientService.getById(id);
        return R.ok(byId);
    }
    /**
     * 获取用户收货地址
     */
    @GetMapping("/shopAddress")
    @ApiOperation(value = "获取用户收货地址", tags = {"获取用户收货地址"})
    @ApiOperation(value = "获取用户收货地址", tags = {"学习端-获取用户收货地址"})
    public R<List<Recipient>> shopAddress() {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        return R.ok(recipientService.lambdaQuery().eq(Recipient::getUserId,
                tokenService.getLoginUserStudy().getUserid()).list());
    }
@@ -202,10 +350,25 @@
     * 新增收货地址/修改收货地址
     */
    @PostMapping("/addressSaveOrUpdate")
    @ApiOperation(value = "学习端-新增收货地址/修改收货地址", tags = {"新增收货地址/修改收货地址"})
    @ApiOperation(value = "学习端-新增收货地址/修改收货地址", tags = {"学习端-新增收货地址/修改收货地址"})
    public R<String> addressSave(@RequestBody Recipient recipient) {
        recipient.setUserId(tokenService.getLoginUserStudy().getUserid());
        return R.ok(recipientService.addressSaveOrUpdate(recipient));
        recipientService.addressSaveOrUpdate(recipient);
        return R.ok();
    }
    /**
     * 新增收货地址/修改收货地址
     */
    @PostMapping("/addressSaveOrUpdateParent")
    @ApiOperation(value = "家长端-新增收货地址/修改收货地址", tags = {"家长端-新增收货地址/修改收货地址"})
    public R<String> addressSaveOrUpdateParent(@RequestBody Recipient recipient) {
        recipient.setUserId(tokenService.getLoginUser1().getUserid());
        if (recipient.getId() == null){
            recipientService.updateById(recipient);
        }else{
            recipientService.save(recipient);
        }
        return R.ok();
    }
    /**
@@ -219,22 +382,71 @@
    public R<String> addressDelete(@RequestParam String id) {
        return R.ok(recipientService.removeById(id) ? "删除成功!" : "删除失败!");
    }
    /**
     * 修改订单收货地址
     *
     * @param orderId 订单id
     * 删除收货地址
     */
    @GetMapping("/updateOrderAddress")
    @ApiOperation(value = "学习端-修改订单收货地址", tags = {"学习端-修改订单收货地址"})
    @GetMapping("/addressDeleteParent")
    @ApiOperation(value = "家长端-删除收货地址", tags = {"家长端-删除收货地址"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "地址信息id", name = "id", dataType = "String", required = true)
    })
    public R<String> addressDeleteParent(@RequestParam String id) {
        return R.ok(recipientService.removeById(id) ? "删除成功!" : "删除失败!");
    }
    @GetMapping("/getOrderAddressParent")
    @ApiOperation(value = "获取修改订单收货地址", tags = {"家长端-获取修改订单收货地址"})
    public R<List<Recipient>> getOrderAddressParent() {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        List<Recipient> userId = recipientService.list(new QueryWrapper<Recipient>()
                .eq("userId", tokenService.getLoginUser1().getUserid()));
        return R.ok(userId);
    }
    @GetMapping("/getOrderAddress")
    @ApiOperation(value = "获取修改订单收货地址", tags = {"学习端-获取修改订单收货地址"})
    public R<List<Recipient>> getOrderAddress() {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        List<Recipient> userId = recipientService.list(new QueryWrapper<Recipient>()
                .eq("userId", tokenService.getLoginUserStudy().getUserid()));
        return R.ok(userId);
    }
    @GetMapping("/updateOrderAddressParent")
    @ApiOperation(value = "修改订单收货地址", tags = {"家长端-修改订单收货地址"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "订单id", name = "orderId", dataType = "String", required = true),
            @ApiImplicitParam(value = "完整收货地址", name = "address", dataType = "String", required = true)
            @ApiImplicitParam(value = "地址信息id", name = "recipientId", dataType = "String", required = true)
    })
    public R<Boolean> updateOrderAddress(@RequestParam String orderId,
                                                  @RequestParam String address) {
        return R.ok(orderService.lambdaUpdate().set(TOrder::getConsigneeAddress, address)
                .eq(TOrder::getId, orderId).eq(TOrder::getState, 1).update());
    public R updateOrderAddressParent(@RequestParam Integer orderId,@RequestParam Integer recipientId) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        Recipient userId = recipientService.getById(recipientId);
        TOrder byId = orderService.getById(orderId);
        byId.setConsigneeName(userId.getAddress());
        byId.setConsigneePhone(userId.getRecipientPhone());
        byId.setConsigneeAddress(userId.getAddress());
        orderService.updateById(byId);
        return R.ok("修改成功");
    }
    @GetMapping("/updateOrderAddress")
    @ApiOperation(value = "修改订单收货地址", tags = {"学习端-修改订单收货地址"})
    public R updateOrderAddress(@RequestParam Integer orderId,@RequestParam Integer recipientId) {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        Recipient userId = recipientService.getById(recipientId);
        TOrder byId = orderService.getById(orderId);
        byId.setConsigneeName(userId.getAddress());
        byId.setConsigneePhone(userId.getRecipientPhone());
        byId.setConsigneeAddress(userId.getAddress());
        orderService.updateById(byId);
        return R.ok();
    }
    /**
@@ -262,11 +474,33 @@
     * @param goodId 商品id
     */
    @GetMapping("/goodDetail")
    @ApiOperation(value = "学习端-商品详情", tags = {"学习端-商品详情"})
    @ApiOperation(value = "学习端-商品详情", tags = {"学习端-商城"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "商品id", name = "goodId", dataType = "String", required = true)
    })
    public R<GoodDetailVO> goodDetail(@RequestParam String goodId) {
        // 商品详情
        TGoods goods = goodsService.lambdaQuery().eq(TGoods::getId, goodId).one();
        // 商品分类详情
        List<TGoodsType> goodsTypes = goodsTypeService.lambdaQuery().in(TGoodsType::getId, Arrays.asList(goods.getTypeIds().split(","))).list();
        // 已兑换人数
        int number = goods.getBasicCount() + orderService.getGoodBuyNumber(goods.getId());
        return R.ok(new GoodDetailVO(goods, goodsTypes, number));
    }
    /**
     * 商品详情
     *
     * @param goodId 商品id
     */
    @GetMapping("/goodDetailParent")
    @ApiOperation(value = "商品详情", tags = {"家长端-商城"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "商品id", name = "goodId", dataType = "String", required = true)
    })
    public R<GoodDetailVO> goodDetailParent(@RequestParam String goodId) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        // 商品详情
        TGoods goods = goodsService.lambdaQuery().eq(TGoods::getId, goodId).one();
        // 商品分类详情
@@ -280,15 +514,63 @@
     * 商城-立即兑换
     */
    @GetMapping("/redeemNow")
    @ApiOperation(value = "学习端-商城立即兑换", tags = {"学习端-商城立即兑换"})
    @ApiOperation(value = "商城立即兑换", tags = {"学习端-商城"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "商品id", name = "goodId", dataType = "String", required = true)
    })
    public R<GoodDetailVO> redeemNow(@RequestParam String goodId) {
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        Recipient recipient = recipientService.lambdaQuery()
                .eq(Recipient::getUserId, tokenService.getLoginUserStudy().getUserid())
                .eq(Recipient::getIsDefault, 1).one();
        return R.ok(goodsService.redeemNow(goodId, recipient));
        GoodDetailVO goodDetailVO = goodsService.redeemNow(goodId, recipient);
        LocalDateTime currentDateTime = LocalDateTime.now();
        // 格式化日期和时间信息
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String formattedDateTime = currentDateTime.format(formatter);
        // 生成随机数,填充剩余位数
        Random random = new Random();
        StringBuilder randomPart = new StringBuilder();
        for (int i = 0; i < 3; i++) {
            randomPart.append((char) (random.nextInt(26) + 'A')); // 大写字母
        }
        // 组合订单编号
        String orderNumber = formattedDateTime + randomPart.toString();
        goodDetailVO.setOrderNumber(orderNumber);
        return R.ok(goodDetailVO);
    }
    /**
     * 商城-立即兑换
     */
    @GetMapping("/redeemNowParent")
    @ApiOperation(value = "商城立即兑换", tags = {"家长端-商城"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "商品id", name = "goodId", dataType = "String", required = true)
    })
    public R<GoodDetailVO> redeemNowParent(@RequestParam String goodId) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        Recipient recipient = recipientService.lambdaQuery()
                .eq(Recipient::getUserId, tokenService.getLoginUser1().getUserid())
                .eq(Recipient::getIsDefault, 1).one();
        GoodDetailVO goodDetailVO = goodsService.redeemNow(goodId, recipient);
        LocalDateTime currentDateTime = LocalDateTime.now();
        // 格式化日期和时间信息
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String formattedDateTime = currentDateTime.format(formatter);
        // 生成随机数,填充剩余位数
        Random random = new Random();
        StringBuilder randomPart = new StringBuilder();
        for (int i = 0; i < 3; i++) {
            randomPart.append((char) (random.nextInt(26) + 'A')); // 大写字母
        }
        // 组合订单编号
        String orderNumber = formattedDateTime + randomPart.toString();
        goodDetailVO.setOrderNumber(orderNumber);
        return R.ok(goodDetailVO);
    }
@@ -298,11 +580,19 @@
     * @param goodExchange 商品信息
     */
    @PostMapping("/goodExchange")
    @ApiOperation(value = "学习端-商品兑换确认", tags = {"学习端-商品兑换确认"})
    public R<Boolean> goodExchange(@RequestBody GoodExchangeDTO goodExchange) {
    @ApiOperation(value = "学习端-商品兑换确认", tags = {"家长端-商品兑换确认"})
    public R goodExchange(@RequestBody GoodExchangeDTO goodExchange) {
        Recipient recipient = recipientService.getById(goodExchange.getRecipientId());
        return R.ok(goodsService.goodExchange(goodExchange, recipient));
        return goodsService.goodExchange1(goodExchange, recipient);
    }
    @PostMapping("/goodExchangeStudy")
    @ApiOperation(value = "学习端-商品兑换确认", tags = {"学习端-商品兑换确认"})
    public R goodExchangeStudy(@RequestBody GoodExchangeDTO goodExchange) {
        Recipient recipient = recipientService.getById(goodExchange.getRecipientId());
        return goodsService.goodExchange(goodExchange, recipient);
    }
    @Autowired
    private StudyClient studyClient;
    @PostMapping("/getOrderInfo/{id}")
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/domain/Recipient.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.ruoyi.common.core.web.domain.BaseModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -19,7 +20,7 @@
 */
@TableName("t_recipient")
@Data
public class Recipient extends Model<Recipient> {
public class Recipient extends BaseModel {
    private static final long serialVersionUID = 1L;
@@ -31,6 +32,7 @@
    /**
     * 用户id
     */
    @ApiModelProperty(value = "用户id")
    private Integer userId;
    /**
     * 收件人姓名
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/dto/GoodExchangeDTO.java
@@ -1,5 +1,6 @@
package com.ruoyi.goods.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
@@ -13,26 +14,31 @@
    /**
     * 商品id
     */
    @ApiModelProperty("商品id")
    private Integer goodId;
    /**
     * 备注
     */
    @ApiModelProperty("备注")
    private String remark;
    /**
     * 兑换数量
     */
    @ApiModelProperty("兑换数量")
    private Integer number;
    /**
     * 订单编号
     */
    @ApiModelProperty("订单编号")
    private String orderNumber;
    /**
     * 收货地址id
     */
    @ApiModelProperty("收货地址id")
    private String recipientId;
}
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/service/ITGoodsService.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.goods.domain.Recipient;
import com.ruoyi.goods.domain.TGoods;
import com.ruoyi.goods.dto.GoodExchangeDTO;
@@ -44,5 +45,6 @@
     * @param recipient    收货地址
     * @return 兑换结果
     */
    Boolean goodExchange(GoodExchangeDTO goodExchange, Recipient recipient);
    R goodExchange(GoodExchangeDTO goodExchange, Recipient recipient);
    R goodExchange1(GoodExchangeDTO goodExchange, Recipient recipient);
}
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/service/impl/TGoodsServiceImpl.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.RedisConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.GlobalException;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.goods.domain.Recipient;
@@ -65,12 +66,12 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean goodExchange(GoodExchangeDTO goodExchange, Recipient recipient) {
    public R goodExchange(GoodExchangeDTO goodExchange, Recipient recipient) {
        Integer number = goodExchange.getNumber();
        Integer goodId = goodExchange.getGoodId();
        TGoods good = this.getById(goodId);
        if (null == good) {
            throw new GlobalException("商品不存在,请稍后重试!");
            return R.exchangeError("商品不存在,请稍后重试!");
        }
        // 校验用户积分是否足够兑换
        TUser user = studyClient.userInfo().getData();
@@ -78,10 +79,9 @@
        if (user == null){
            user = studyClient.getUserById(loginUser1.getUserid()).getData();
        }
        int needIntegral = good.getIntegral() * number;
        if (user.getIntegral() < needIntegral) {
            throw new GlobalException("兑换失败,当前剩余积分不足!");
            return R.exchangeError("兑换失败,当前剩余积分不足!");
        }
        // 检查用户兑换数量是否超过单用户最大兑换数量
        List<TOrder> orderList = orderService.lambdaQuery().eq(TOrder::getUserId, user.getId()).eq(TOrder::getGoodsId, goodId).list();
@@ -89,7 +89,7 @@
        int totalNumber = orderList.stream().map(TOrder::getCount).collect(Collectors.toList()).stream().mapToInt(Integer::intValue).sum();
        boolean canExchange = orderList.isEmpty() || null == good.getUserCount() || (totalNumber + number) <= good.getUserCount();
        if (!canExchange) {
            throw new GlobalException("兑换失败,当前兑换数量已超过最大兑换数量,剩余兑换数量为: " + (good.getUserCount() - totalNumber) + "!");
            return R.exchangeError("兑换失败,当前兑换数量已超过最大兑换数量,剩余兑换数量为: " + (good.getUserCount() - totalNumber) + "!");
        }
        // redisson分布式锁,防止超卖
        String key = String.format(RedisConstants.GOOD_STOCK, good.getId());
@@ -100,7 +100,7 @@
        // 兑换失败,库存不足
        if (!tried) {
            semaphore.release(number);
            throw new GlobalException("当前商品库存不足!");
            return R.exchangeError("当前商品库存不足");
        }
        // 兑换成功,生成订单信息、生成积分明细(积分明细需要远程调用rouyi-study服务)
        TOrder order = orderInfo(goodExchange, recipient, number, goodId, needIntegral);
@@ -113,9 +113,63 @@
        result = result && this.lambdaUpdate().set(TGoods::getSurplus, good.getSurplus() - number).eq(TGoods::getId, good.getId()).update();
        if (!result) {
            semaphore.release(number);
            throw new GlobalException("商品兑换失败!");
            return R.exchangeError("商品兑换失败!");
        }
        return result;
        return R.ok();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R goodExchange1(GoodExchangeDTO goodExchange, Recipient recipient) {
        Integer number = goodExchange.getNumber();
        Integer goodId = goodExchange.getGoodId();
        TGoods good = this.getById(goodId);
        if (null == good) {
            return R.exchangeError("商品不存在,请稍后重试!");
        }
        // 校验用户积分是否足够兑换
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        TUser user = studyClient.getUserById(tokenService.getLoginUser1().getUserid()).getData();
        int needIntegral = good.getIntegral() * number;
        if (user.getIntegral() < needIntegral) {
            return R.exchangeError("兑换失败,当前剩余积分不足!");
        }
        // 检查用户兑换数量是否超过单用户最大兑换数量
        List<TOrder> orderList = orderService.lambdaQuery().eq(TOrder::getUserId, user.getId()).eq(TOrder::getGoodsId, goodId).list();
        // 该商品订单为空、订单数量未超过商品的单个用户兑换上限数量时,可以进行兑换
        int totalNumber = orderList.stream().map(TOrder::getCount).collect(Collectors.toList()).stream().mapToInt(Integer::intValue).sum();
        boolean canExchange = orderList.isEmpty() || null == good.getUserCount() || (totalNumber + number) <= good.getUserCount();
        if (!canExchange) {
            return R.exchangeError("兑换失败,当前兑换数量已超过最大兑换数量,剩余兑换数量为: " + (good.getUserCount() - totalNumber) + "!");
        }
        // redisson分布式锁,防止超卖
        String key = String.format(RedisConstants.GOOD_STOCK, good.getId());
        RSemaphore semaphore = redissonClient.getSemaphore(key);
        // 请求超时时间 单位:毫秒
        semaphore.trySetPermits(1000);
        boolean tried = semaphore.tryAcquire(number);
        // 兑换失败,库存不足
        if (!tried) {
            semaphore.release(number);
            return R.exchangeError("当前商品库存不足");
        }
        // 兑换成功,生成订单信息、生成积分明细(积分明细需要远程调用rouyi-study服务)
        TOrder order = orderInfo1(goodExchange, recipient, number, goodId, needIntegral);
        boolean result = orderService.save(order);
        // 远程调用,生成积分明细
        result = result && studyClient.addIntegralDetail1(Constants.BURDEN + needIntegral, Constants.SHOPPING_CONSUME).getData();
        // 扣除用户积分
        result = result && studyClient.exchangeIntegral1(needIntegral, Constants.BURDEN).getData();
        // 扣除库存
        result = result && this.lambdaUpdate().set(TGoods::getSurplus, good.getSurplus() - number).eq(TGoods::getId, good.getId()).update();
        if (!result) {
            semaphore.release(number);
            return R.exchangeError("商品兑换失败!");
        }
        return R.ok();
    }
    private TOrder orderInfo(GoodExchangeDTO goodExchange, Recipient recipient, Integer number, Integer goodId, int needIntegral) {
@@ -133,4 +187,19 @@
        order.setDisabled(Boolean.FALSE);
        return order;
    }
    private TOrder orderInfo1(GoodExchangeDTO goodExchange, Recipient recipient, Integer number, Integer goodId, int needIntegral) {
        TOrder order = new TOrder();
        order.setOrderNumber(goodExchange.getOrderNumber());
        order.setUserId(tokenService.getLoginUser1().getUserid());
        order.setInsertTime(new Date());
        order.setGoodsId(goodId);
        order.setCount(number);
        order.setState(1);
        order.setIntegral(needIntegral);
        order.setConsigneeName(recipient.getRecipient());
        order.setConsigneePhone(recipient.getRecipientPhone());
        order.setConsigneeAddress(recipient.getAddress());
        order.setDisabled(Boolean.FALSE);
        return order;
    }
}
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/MyQrCodeUtil.java
New file
@@ -0,0 +1,93 @@
package com.ruoyi.goods.utils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
public class MyQrCodeUtil {
    //CODE_WIDTH:二维码宽度,单位像素
    private static final int CODE_WIDTH = 400;
    //CODE_HEIGHT:二维码高度,单位像素
    private static final int CODE_HEIGHT = 400;
    //FRONT_COLOR:二维码前景色,0x000000 表示黑色
    private static final int FRONT_COLOR = 0x000000;
    //BACKGROUND_COLOR:二维码背景色,0xFFFFFF 表示白色
    //演示用 16 进制表示,和前端页面 CSS 的取色是一样的,注意前后景颜色应该对比明显,如常见的黑白
    private static final int BACKGROUND_COLOR = 0xFFFFFF;
    public static BufferedImage createCodeToFile(String content) {
        try {
            content = content.trim();
            //核心代码-生成二维码
            BufferedImage bufferedImage = getBufferedImage(content);
            return bufferedImage;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 生成二维码并输出到输出流, 通常用于输出到网页上进行显示,输出到网页与输出到磁盘上的文件中,区别在于最后一句 ImageIO.write
     * write(RenderedImage im,String formatName,File output):写到文件中
     * write(RenderedImage im,String formatName,OutputStream output):输出到输出流中
     * @param content  :二维码内容
     * @param outputStream :输出流,比如 HttpServletResponse 的 getOutputStream
     */
    public static void createCodeToOutputStream(String content, OutputStream outputStream) {
        try {
            if (StringUtils.isBlank(content)) {
                return;
            }
            content = content.trim();
            //核心代码-生成二维码
            BufferedImage bufferedImage = getBufferedImage(content);
            //区别就是这一句,输出到输出流中,如果第三个参数是 File,则输出到文件中
            ImageIO.write(bufferedImage, "png", outputStream);
            System.out.println("二维码图片生成到输出流成功...");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //核心代码-生成二维码
    private static BufferedImage getBufferedImage(String content) throws WriterException {
        //com.google.zxing.EncodeHintType:编码提示类型,枚举类型
        Map<EncodeHintType, Object> hints = new HashMap();
        //EncodeHintType.CHARACTER_SET:设置字符编码类型
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //EncodeHintType.ERROR_CORRECTION:设置误差校正
        //ErrorCorrectionLevel:误差校正等级,L = ~7% correction、M = ~15% correction、Q = ~25% correction、H = ~30% correction
        //不设置时,默认为 L 等级,等级不一样,生成的图案不同,但扫描的结果是一样的
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        //EncodeHintType.MARGIN:设置二维码边距,单位像素,值越小,二维码距离四周越近
        hints.put(EncodeHintType.MARGIN, 1);
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, CODE_WIDTH, CODE_HEIGHT, hints);
        BufferedImage bufferedImage = new BufferedImage(CODE_WIDTH, CODE_HEIGHT, BufferedImage.TYPE_INT_BGR);
        for (int x = 0; x < CODE_WIDTH; x++) {
            for (int y = 0; y < CODE_HEIGHT; y++) {
                bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? FRONT_COLOR : BACKGROUND_COLOR);
            }
        }
        return bufferedImage;
    }
//    public static void main(String[] args) {
//        String param = "{\n" +
//                "    \"scan_type\": 1,\n" +
//                "    \"space_id\": 2,\n" +
//                "    \"sutu_id\": 3\n" +
//                "}";
//        createCodeToFile(param);
//    }
}
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/utils/QRCodeUtil.java
New file
@@ -0,0 +1,50 @@
package com.ruoyi.goods.utils;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.awt.image.BufferedImage;
import java.util.Hashtable;
/**
 * @author chengst
 * @date 2019/11/4
 **/
public class QRCodeUtil {
    private final static String CHARSET = "utf-8";
    private final static int QRSIZEE = 300;
    // 二维码颜色
    private static final int BLACK = 0xFF000000;
    // 二维码颜色
    private static final int WHITE = 0xFFFFFFFF;
    public static BufferedImage createImage(String content){
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = null;
        try {
            bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRSIZEE, QRSIZEE,hints);
        }catch (Exception e){
            e.printStackTrace();
        }
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }
}
ruoyi-service/ruoyi-goods/src/main/java/com/ruoyi/goods/vo/GoodDetailVO.java
@@ -35,6 +35,11 @@
     */
    @ApiModelProperty("已兑换人数")
    private Integer exchangeNumber;
    /**
     * 已兑换人数
     */
    @ApiModelProperty("订单编号")
    private String orderNumber;
    /**
     * 用户默认收货地址
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TStoryController.java
@@ -51,7 +51,7 @@
    @Autowired
    private ITStoryService service;
    @PostMapping("/storyList")
    @ApiOperation(value = "列表查询", tags = {"故事管理"})
//    @ApiOperation(value = "列表查询", tags = {"故事管理"})
    public R<PageInfo<SubjectVO>> storyList(@RequestBody SubjectQuery query) {
        PageInfo<SubjectVO> res = new PageInfo<>(query.getPageNumber(), query.getPageSize());
        List<SubjectVO> list =  service.listAll(query);
@@ -76,7 +76,7 @@
        return R.ok(res);
    }
    @PostMapping("/add")
    @ApiOperation(value = "添加", tags = {"故事管理"})
//    @ApiOperation(value = "添加", tags = {"故事管理"})
    public R add(@RequestBody StoryDTO dto) {
        TStory tSubject = new TStory();
        BeanUtils.copyProperties(dto,tSubject);
@@ -84,7 +84,7 @@
        return R.ok("添加成功");
    }
    @PostMapping("/update")
    @ApiOperation(value = "编辑", tags = {"故事管理"})
//    @ApiOperation(value = "编辑", tags = {"故事管理"})
    public R update(@RequestBody StoryDTO dto) {
        TStory tSubject = new TStory();
        R<Object> week = getObjectR(dto.getId());
@@ -94,7 +94,7 @@
        return R.ok("编辑成功");
    }
    @PostMapping("/getInfo")
    @ApiOperation(value = "查看详情", tags = {"故事管理"})
//    @ApiOperation(value = "查看详情", tags = {"故事管理"})
    public R<StoryDTO> getInfo1(@RequestParam("id") Integer id) {
        TStory byId = service.getById(id);
        StoryDTO subjectDTO = new StoryDTO();
@@ -102,7 +102,7 @@
        return R.ok(subjectDTO);
    }
    @PostMapping("/updateState/{id}/{state}")
    @ApiOperation(value = "修改状态", tags = {"故事管理"})
//    @ApiOperation(value = "修改状态", tags = {"故事管理"})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "题目id", required = true),
            @ApiImplicitParam(name = "state", value = "1上架2下架3删除", required = true),
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TStudyController.java
@@ -81,7 +81,7 @@
    private ITSubjectRecordService subjectRecordService;
    @PostMapping("/storyList")
    @ApiOperation(value = "配置学习类型选择故事", tags = {"题目管理"})
//    @ApiOperation(value = "配置学习类型选择故事", tags = {"题目管理"})
    public R<PageInfo<TStory>> storyList(@RequestBody ChoiceStory query) {
        PageInfo<TStory> res = new PageInfo<>(query.getPageNumber(), query.getPageSize());
        QueryWrapper<TStory> wrapper = new QueryWrapper<>();
@@ -117,7 +117,7 @@
    }
    @PostMapping("/subjectList")
    @ApiOperation(value = "配置学习类型选择题目", tags = {"题目管理"})
//    @ApiOperation(value = "配置学习类型选择题目", tags = {"题目管理"})
    public R<PageInfo<TSubject>> subjectList(@RequestBody ChoiceSubject query) {
        PageInfo<TSubject> res = new PageInfo<>(query.getPageNumber(), query.getPageSize());
        QueryWrapper<TSubject> wrapper = new QueryWrapper<>();
@@ -655,23 +655,18 @@
        return R.ok(res);
    }
    /**
     * 查询周目列表
     *
     * @param type    所属类型
     * @param quarter 季度
     */
    @GetMapping("/weekList")
    @ApiOperation(value = "根据季度获取周目列表", tags = {"根据季度获取周目列表"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "所属类型", name = "type", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "季度", name = "quarter", dataType = "Integer", required = true)
    })
    public R<List<StudyWeekDTO>> weekList(@RequestParam(defaultValue = "1") Integer type, @RequestParam Integer quarter) {
        List<StudyWeekDTO> result = studyService.weekList(type, quarter);
        return R.ok(result);
    }
    /**
     * 可兑换商品推荐
     */
    @GetMapping("/goodRecommend")
    @ApiOperation(value = "可兑换商品推荐", tags = {"学习端-首页"})
    public R<List<TGoodsVO>> studySchedule() {
        return R.ok(goodsClient.goodRecommend().getData());
    }
    /**
     * 首次页面加载时调用,获取学习进度及学习时长等信息
     *
@@ -679,7 +674,7 @@
     * @param day  所属day
     */
    @GetMapping("/studySchedule")
    @ApiOperation(value = "获取用户学习进度", tags = {"获取用户学习进度"})
    @ApiOperation(value = "获取用户学习进度", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -688,16 +683,22 @@
        TUserStudy result = studyService.studySchedule(String.valueOf(tokenService.getLoginUserStudy().getUserid()), week, day);
        return R.ok(result);
    }
    /**
     * 可兑换商品推荐
     * 查询周目列表
     *
     * @param type    所属类型
     * @param quarter 季度
     */
    @GetMapping("/goodRecommend")
    @ApiOperation(value = "可兑换商品推荐", tags = {"可兑换商品推荐"})
    public R<List<TGoodsVO>> studySchedule() {
        return R.ok(goodsClient.goodRecommend().getData());
    @GetMapping("/weekList")
    @ApiOperation(value = "根据季度获取周目列表 ", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "所属类型 1.0只有类型听 传1", name = "type", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "季度 首次进入季度quarter默认传1", name = "quarter", dataType = "Integer", required = true)
    })
    public R<List<StudyWeekDTO>> weekList(@RequestParam(defaultValue = "1") Integer type, @RequestParam Integer quarter) {
        List<StudyWeekDTO> result = studyService.weekList(type, quarter);
        return R.ok(result);
    }
    /**
     * 进入题组后,获取题组学习进度信息
     *
@@ -705,7 +706,7 @@
     * @param day  所属day
     */
    @GetMapping("/teamSchedule")
    @ApiOperation(value = "获取题组学习进度信息", tags = {"获取题组学习进度信息"})
    @ApiOperation(value = "获取题组学习进度信息", tags = {"学习端-题目"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -720,7 +721,7 @@
     * 退出学习,记录学习进度、当日学习时长...
     */
    @PostMapping("/exitLearning")
    @ApiOperation(value = "退出学习(记录学习进度等信息)", tags = {"退出学习(记录学习进度等信息)"})
    @ApiOperation(value = "退出学习(记录学习进度等信息)", tags = {"学习端-题目"})
    public R<Boolean> exitLearning(@RequestBody TSubjectRecord subjectRecord) {
        // 学习时长处理
        return R.ok(subjectRecordService.updateById(subjectRecord));
@@ -733,7 +734,7 @@
     * @param day  所属day
     */
    @GetMapping("/listenSelectPicture")
    @ApiOperation(value = "自主学习1-听音选图", tags = {"自主学习1-听音选图"})
    @ApiOperation(value = "自主学习1-听音选图", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -743,11 +744,21 @@
        Boolean isVip = userService.isVip();
        LambdaQueryChainWrapper<TStudyListen> wrapper = studyListenService.lambdaQuery().eq(TStudyListen::getWeek, week)
                .eq(TStudyListen::getDay, day).eq(TStudyListen::getDisabled, 0);
        // 非会员只能查看非会员题目,会员可以查看所有题目
        if (!isVip) {
            wrapper.eq(TStudyListen::getIsVip, 0);
        }
//        if (!isVip) {
//            wrapper.eq(TStudyListen::getIsVip, 0);
//        }
        List<TStudyListen> studyListens = wrapper.list();
        for (TStudyListen studyListen : studyListens) {
            if (studyListen.getIsVip() == 1){
                // 需要会员查看
                if (!isVip){
                    // 不是会员
                    return R.vipError("以下内容仅限会员查看,请通过家长端成为会员!");
                }
            }
        }
        return R.ok(studyService.listenSelectPicture(week, day, studyListens));
    }
@@ -758,7 +769,7 @@
     * @param day  所属day
     */
    @GetMapping("/pictureSelectVoice")
    @ApiOperation(value = "自主学习2-看图选音", tags = {"自主学习2-看图选音"})
    @ApiOperation(value = "自主学习2-看图选音", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -769,11 +780,18 @@
        LambdaQueryChainWrapper<TStudyLook> wrapper = studyLookService.lambdaQuery().eq(TStudyLook::getWeek, week)
                .eq(TStudyLook::getDay, day).eq(TStudyLook::getDisabled, 0);
        // 非会员只能查看非会员题目,会员可以查看所有题目
        if (!isVip) {
            wrapper.eq(TStudyLook::getIsVip, 0);
        }
        List<TStudyLook> lookList = studyLookService.lambdaQuery().eq(TStudyLook::getWeek, week)
                .eq(TStudyLook::getDay, day).eq(TStudyLook::getDisabled, 0).list();
        for (TStudyLook studyListen : lookList) {
            if (studyListen.getIsVip() == 1){
                // 需要会员查看
                if (!isVip){
                    // 不是会员
                    return R.vipError("以下内容仅限会员查看,请通过家长端成为会员!");
                }
            }
        }
        return R.ok(studyService.pictureSelectVoice(week, day, lookList));
    }
@@ -784,7 +802,7 @@
     * @param day  所属day
     */
    @GetMapping("/induceExclude")
    @ApiOperation(value = "自主学习3-归纳排除", tags = {"自主学习3-归纳排除"})
    @ApiOperation(value = "自主学习3-归纳排除", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -795,10 +813,19 @@
        LambdaQueryChainWrapper<TStudyInduction> wrapper = studyInductionService.lambdaQuery().eq(TStudyInduction::getWeek, week)
                .eq(TStudyInduction::getDay, day).eq(TStudyInduction::getDisabled, 0);
        // 非会员只能查看非会员题目,会员可以查看所有题目
        if (!isVip) {
            wrapper.eq(TStudyInduction::getIsVip, 0);
        }
//        if (!isVip) {
//            wrapper.eq(TStudyInduction::getIsVip, 0);
//        }
        List<TStudyInduction> inductionList = wrapper.list();
        for (TStudyInduction studyListen : inductionList) {
            if (studyListen.getIsVip() == 1){
                // 需要会员查看
                if (!isVip){
                    // 不是会员
                    return R.vipError("以下内容仅限会员查看,请通过家长端成为会员!");
                }
            }
        }
        return R.ok(studyService.induceExclude(week, day, inductionList));
    }
@@ -809,7 +836,7 @@
     * @param day  所属day
     */
    @GetMapping("/questionsAndAnswers")
    @ApiOperation(value = "自主学习4-有问有答", tags = {"自主学习4-有问有答"})
    @ApiOperation(value = "自主学习4-有问有答", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -820,10 +847,19 @@
        LambdaQueryChainWrapper<TStudyAnswer> wrapper = studyAnswerService.lambdaQuery().eq(TStudyAnswer::getWeek, week)
                .eq(TStudyAnswer::getDay, day).eq(TStudyAnswer::getDisabled, 0);
        // 非会员只能查看非会员题目,会员可以查看所有题目
        if (!isVip) {
            wrapper.eq(TStudyAnswer::getIsVip, 0);
        }
//        if (!isVip) {
//            wrapper.eq(TStudyAnswer::getIsVip, 0);
//        }
        List<TStudyAnswer> answerList = wrapper.list();
        for (TStudyAnswer studyListen : answerList) {
            if (studyListen.getIsVip() == 1){
                // 需要会员查看
                if (!isVip){
                    // 不是会员
                    return R.vipError("以下内容仅限会员查看,请通过家长端成为会员!");
                }
            }
        }
        return R.ok(studyService.questionsAndAnswers(week, day, answerList));
    }
@@ -834,7 +870,7 @@
     * @param day  所属day
     */
    @GetMapping("/pictureMateVoice")
    @ApiOperation(value = "自主学习5-音图相配", tags = {"自主学习5-音图相配"})
    @ApiOperation(value = "自主学习5-音图相配", tags = {"学习端-首页"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "周目", name = "week", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属day", name = "day", dataType = "Integer", required = true)
@@ -849,6 +885,13 @@
            wrapper.eq(TStudyPair::getIsVip, 0);
        }
        TStudyPair pair = wrapper.one();
        if (pair.getIsVip() == 1){
            // 需要会员查看
            if (!isVip){
                // 不是会员
                return R.vipError("以下内容仅限会员查看,请通过家长端成为会员!");
            }
        }
        return R.ok(studyService.pictureMateVoice(week, day, pair));
    }
@@ -858,7 +901,7 @@
     * @param completeStudy 完成学习信息
     */
    @PostMapping("/completeLearning")
    @ApiOperation(value = "完成学习", tags = {"完成学习"})
    @ApiOperation(value = "完成学习", tags = {"学习端-题目"})
    public R<Boolean> completeLearning(@RequestBody CompleteStudyDTO completeStudy) {
        // 登录用户id
        Integer userId = tokenService.getLoginUserStudy().getUserid();
@@ -884,7 +927,7 @@
     * @param week       所属周目
     */
    @GetMapping("/gameHearing")
    @ApiOperation(value = "自主游戏1-超级听力", tags = {"自主游戏1-超级听力(difficulty: 0入门、1中级、2高级)"})
    @ApiOperation(value = "自主游戏1-超级听力", tags = {"学习端-游戏"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "难度(0入门、1中级、2困难)", name = "difficulty", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属周目", name = "week", dataType = "Integer", required = true)
@@ -924,7 +967,7 @@
     * @param week       所属周目
     */
    @GetMapping("/gameMemory")
    @ApiOperation(value = "自主游戏2-超级记忆", tags = {"自主游戏2-超级记忆(difficulty: 0入门、1中级、2高级)"})
    @ApiOperation(value = "自主游戏2-超级记忆", tags = {"学习端-游戏"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "难度(0入门、1中级、2困难)", name = "difficulty", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "所属周目", name = "week", dataType = "Integer", required = true)
@@ -961,7 +1004,7 @@
     * @param completeStudy 学习信息
     */
    @PostMapping("/gameAchievement")
    @ApiOperation(value = "完成游戏-记录游戏测试成绩", tags = {"完成游戏-记录游戏测试成绩"})
    @ApiOperation(value = "完成游戏-记录游戏测试成绩", tags = {"学习端-游戏"})
    public R<Boolean> gameAchievement(@RequestBody CompleteGameDTO completeStudy) {
        /*
         * 游戏测试需要根据正确率计算本次测试可获得积分
@@ -1019,7 +1062,7 @@
     * @param week 周目
     */
    @GetMapping("/lookPictureDbu")
    @ApiOperation(value = "自主故事1-看图配音", tags = {"自主故事1-看图配音"})
    @ApiOperation(value = "自主故事1-看图配音", tags = {"学习端-故事"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "所属周目", name = "week", dataType = "Integer", required = true)
    })
@@ -1038,7 +1081,7 @@
     * @param week 周目
     */
    @GetMapping("/frameworkMemory")
    @ApiOperation(value = "自主故事2-框架记忆", tags = {"自主故事2-框架记忆"})
    @ApiOperation(value = "自主故事2-框架记忆", tags = {"学习端-故事"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "所属周目", name = "week", dataType = "Integer", required = true)
    })
@@ -1055,7 +1098,7 @@
     * 完成故事类型
     */
    @GetMapping("/completeStory")
    @ApiOperation(value = "完成故事学习", tags = {"完成故事学习"})
    @ApiOperation(value = "完成故事学习", tags = {"学习端-故事"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "积分数量", name = "integral", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "故事id", name = "storyId", dataType = "Integer", required = true),
@@ -1085,9 +1128,10 @@
    }
    @GetMapping("/studyRecord")
    @ApiOperation(value = "个人中心-学习记录", tags = {"个人中心-学习记录"})
    @ApiOperation(value = "个人中心-学习记录", tags = {"学习端-个人中心"})
    public R<StudyRecordResultVO> studyRecord() {
        Integer userId = tokenService.getLoginUserStudy().getUserid();
        // 学习记录
        TUserStudy studyRecord = userStudyService.lambdaQuery().eq(TUserStudy::getUserId, userId)
                .eq(TUserStudy::getDisabled, 0).one();
@@ -1096,18 +1140,75 @@
                .eq(TGameRecord::getDisabled, 0).list();
        return R.ok(new StudyRecordResultVO(studyRecord, gameRecordList));
    }
    @GetMapping("/record")
    @ApiOperation(value = "游戏测试成绩", tags = {"家长端-游戏测试成绩"})
    public R<StudyRecordResultVO> record() {
        LoginUserParent loginUser1 = tokenService.getLoginUser1();
        if (loginUser1 == null){
            return R.tokenError("登陆失效,请重新登录");
        }
        Integer userId = loginUser1.getUserid();
        // 学习记录
        TUserStudy studyRecord = userStudyService.lambdaQuery().eq(TUserStudy::getUserId, userId)
                .eq(TUserStudy::getDisabled, 0).one();
        // 查询剩余周目
        if (studyRecord!=null){
            int size = studyService.list(new QueryWrapper<TStudy>()
                    .eq("type", 1)).size();
            studyRecord.setSurplus(size-studyRecord.getWeek());
        }else{
            studyRecord.setSurplus(studyService.list(new QueryWrapper<TStudy>()
                    .eq("type", 1)).size());
        }
        // 游戏测试成绩
        List<TGameRecord> gameRecordList = gameRecordService.lambdaQuery().eq(TGameRecord::getUserId, userId)
                .eq(TGameRecord::getDisabled, 0).list();
        return R.ok(new StudyRecordResultVO(studyRecord, gameRecordList));
    }
    @GetMapping("/getIntegral")
    @ApiOperation(value = "获取剩余积分", tags = {"家长端-获取剩余积分"})
    public R<Integer> getIntegral() {
        Integer userId = tokenService.getLoginUser1().getUserid();
        return R.ok(userService.getById(userId).getIntegral());
    }
    @GetMapping("/getIntegralStudy")
    @ApiOperation(value = "获取剩余积分", tags = {"学习端-获取剩余积分"})
    public R<Integer> getIntegralStudy() {
        Integer userId = tokenService.getLoginUserStudy().getUserid();
        return R.ok(userService.getById(userId).getIntegral());
    }
    @GetMapping("/integralDetail")
    @ApiOperation(value = "个人中心-积分明细", tags = {"个人中心-积分明细"})
    @ApiOperation(value = "个人中心-积分明细", tags = {"学习端-个人中心"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "查询时间", name = "time", dataType = "Integer"),
            @ApiImplicitParam(value = "查询时间 格式yyyy-MM", name = "time", dataType = "Integer"),
            @ApiImplicitParam(value = "页码", name = "pageNum", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "每页显示条数", name = "pageSize", dataType = "Integer", required = true)
    })
    public R<IPage<TIntegralRecord>> integralDetail(String time,
                                                    @RequestParam("pageNum") Integer pageNum,
                                                    @RequestParam("pageSize") Integer pageSize) {
        if(tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        return R.ok(integralRecordService.integralDetail(new Page<>(pageNum, pageSize), tokenService.getLoginUserStudy().getUserid(), time));
    }
    @GetMapping("/integralDetailParent")
    @ApiOperation(value = "个人中心-积分明细", tags = {"家长端"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "查询时间 格式yyyy-MM", name = "time", dataType = "Integer"),
            @ApiImplicitParam(value = "页码", name = "pageNum", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "每页显示条数", name = "pageSize", dataType = "Integer", required = true)
    })
    public R<IPage<TIntegralRecord>> integralDetailParent(String time,
                                                    @RequestParam("pageNum") Integer pageNum,
                                                    @RequestParam("pageSize") Integer pageSize) {
        if(tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        return R.ok(integralRecordService.integralDetail(new Page<>(pageNum, pageSize), tokenService.getLoginUser1().getUserid(), time));
    }
    /**
@@ -1117,7 +1218,7 @@
     * @param method   变动源
     */
    @GetMapping("/addIntegralDetail")
    @ApiOperation(value = "添加-积分明细", tags = {"添加-积分明细"})
//    @ApiOperation(value = "添加-积分明细", tags = {"添加-积分明细"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "积分数量", name = "integral", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "变动源(完成学习、完成游戏...)", name = "method", dataType = "String", required = true)
@@ -1125,6 +1226,30 @@
    public R<Boolean> addIntegralDetail(@RequestParam("integral") String integral, @RequestParam("method") String method) {
        // 当前登录用户
        LoginUserParent userStudy = tokenService.getLoginUserStudy();
        // 生成积分明细信息
        TIntegralRecord integralRecord = new TIntegralRecord();
        integralRecord.setIntegral(integral);
        integralRecord.setMethod(method);
        integralRecord.setUserId(userStudy.getUserid());
        integralRecord.setDisabled(Boolean.FALSE);
        integralRecord.setCreateBy(userStudy.getPhone());
        integralRecord.setCreateTime(new Date());
        integralRecord.setUpdateBy(userStudy.getPhone());
        integralRecord.setUpdateTime(new Date());
        return R.ok(integralRecordService.save(integralRecord));
    }
    @GetMapping("/addIntegralDetail1")
//    @ApiOperation(value = "添加-积分明细", tags = {"添加-积分明细"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "积分数量", name = "integral", dataType = "Integer", required = true),
            @ApiImplicitParam(value = "变动源(完成学习、完成游戏...)", name = "method", dataType = "String", required = true)
    })
    public R addIntegralDetail1(@RequestParam("integral") String integral, @RequestParam("method") String method) {
        // 当前登录用户
        LoginUserParent userStudy = tokenService.getLoginUser1();
        if (userStudy == null){
            return R.tokenError("登录失效");
        }
        // 生成积分明细信息
        TIntegralRecord integralRecord = new TIntegralRecord();
        integralRecord.setIntegral(integral);
@@ -1145,7 +1270,7 @@
     * @param method   变动源
     */
    @GetMapping("/exchangeIntegral")
    @ApiOperation(value = "用户积分变动", tags = {"用户积分变动"})
//    @ApiOperation(value = "用户积分变动", tags = {"用户积分变动"})
    public R<Boolean> exchangeIntegral(@RequestParam("integral") Integer integral, @RequestParam("method") String method) {
        TUser user = userService.getById(tokenService.getLoginUserStudy().getUserid());
        if (Constants.BURDEN.equals(method)) {
@@ -1155,6 +1280,17 @@
        }
        return R.ok(userService.updateById(user));
    }
    @GetMapping("/exchangeIntegral1")
//    @ApiOperation(value = "用户积分变动", tags = {"用户积分变动"})
    public R<Boolean> exchangeIntegral1(@RequestParam("integral") Integer integral, @RequestParam("method") String method) {
        TUser user = userService.getById(tokenService.getLoginUser1().getUserid());
        if (Constants.BURDEN.equals(method)) {
            user.setIntegral(user.getIntegral() - integral);
        } else {
            user.setIntegral(user.getIntegral() + integral);
        }
        return R.ok(userService.updateById(user));
    }
}
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TSubjectController.java
@@ -52,7 +52,7 @@
    @PostMapping("/subjectList")
    @ApiOperation(value = "列表查询", tags = {"题目管理"})
//    @ApiOperation(value = "列表查询", tags = {"题目管理"})
    public R<PageInfo<SubjectVO>> subjectList(@RequestBody SubjectQuery query) {
        PageInfo<SubjectVO> res = new PageInfo<>(query.getPageNumber(), query.getPageSize());
        List<SubjectVO> list =  subjectService.listAll(query);
@@ -86,7 +86,7 @@
        return R.ok(res);
    }
    @PostMapping("/add")
    @ApiOperation(value = "添加", tags = {"题目管理"})
//    @ApiOperation(value = "添加", tags = {"题目管理"})
    public R add(@RequestBody SubjectDTO dto) {
        TSubject tSubject = new TSubject();
        BeanUtils.copyProperties(dto,tSubject);
@@ -94,7 +94,7 @@
        return R.ok("添加成功");
    }
    @PostMapping("/update")
    @ApiOperation(value = "编辑", tags = {"题目管理"})
//    @ApiOperation(value = "编辑", tags = {"题目管理"})
    public R update(@RequestBody SubjectDTO dto) {
        TSubject tSubject = new TSubject();
        // 判断当前题目有没有被使用
@@ -174,7 +174,7 @@
    }
    @PostMapping("/getInfo")
    @ApiOperation(value = "查看详情", tags = {"题目管理"})
//    @ApiOperation(value = "查看详情", tags = {"题目管理"})
    public R<SubjectDTO> getInfo(@RequestParam("id") Integer id) {
        TSubject byId = subjectService.getById(id);
        SubjectDTO subjectDTO = new SubjectDTO();
@@ -182,7 +182,7 @@
        return R.ok(subjectDTO);
    }
    @PostMapping("/updateState/{id}/{state}")
    @ApiOperation(value = "修改状态", tags = {"题目管理"})
//    @ApiOperation(value = "修改状态", tags = {"题目管理"})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "题目id", required = true),
            @ApiImplicitParam(name = "state", value = "1上架2下架3删除", required = true),
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/controller/TUserController.java
@@ -325,9 +325,26 @@
        }
        return R.ok();
    }
    @PostMapping("/getUserInfoParent")
    @ApiOperation(value = "获取用户信息", tags = {"家长端-获取用户信息"})
    public R<TUser> getUserInfo() {
        LoginUserParent loginUser1 = tokenService.getLoginUser1();
        if (loginUser1!=null){
            TUser byId = userService.getById(loginUser1.getUserid());
            if (byId.getVipEndTime() == null){
                byId.setIsVip(0);
            }else if (byId.getVipEndTime().after(new Date())){
                byId.setIsVip(1);
            }else{
                byId.setIsVip(0);
            }
            return R.ok(byId);
        }else{
            return R.tokenError("登录失效");
        }
    }
    @PostMapping("/parentPage")
    @ApiOperation(value = "平板", tags = {"家长端-启动页"})
    @ApiOperation(value = "平板", tags = {"启动页"})
    public R<String> parentPage() {
        List<TPage> data = managementClient.getPage1().getData();
        for (TPage datum : data) {
@@ -339,7 +356,7 @@
    }
    @PostMapping("/parentPage1")
    @ApiOperation(value = "手机", tags = {"家长端-启动页"})
    @ApiOperation(value = "手机", tags = {"启动页"})
    public R<String> parentPage1() {
        List<TPage> data = managementClient.getPage1().getData();
        for (TPage datum : data) {
@@ -351,7 +368,7 @@
    }
    @PostMapping("/getProtocol")
    @ApiOperation(value = "获取协议", tags = {"家长端-协议"})
    @ApiOperation(value = "获取协议", tags = {"协议"})
    @ApiImplicitParams({
            @ApiImplicitParam(value = "类型 1用户 2隐私 3注销", name = "type", dataType = "string", required = true),
    })
@@ -371,7 +388,7 @@
    @ApiOperation(value = "反馈", tags = {"家长端-意见反馈"})
    public R<String> feedBack(@RequestBody TFeedback dto) {
        if (tokenService.getLoginUser1() == null) {
            throw new GlobalException("登录失效!");
            return R.tokenError("登录失效");
        }
        LoginUserParent loginUser1 = tokenService.getLoginUser1();
        dto.setUserId(loginUser1.getUserid());
@@ -395,8 +412,8 @@
            }
        } else {
            // 手机验证码校验
            Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone);
            if (!phoneCode.equals("123456")){
            Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone);
                if (null == redisPhoneCode) {
                    throw new GlobalException("登录失败,手机验证码已过期!");
                } else {
@@ -433,7 +450,7 @@
     */
    @PostMapping("/studyLogin")
    @ApiOperation(value = "学习端-登录", tags = {"学习端-登录"})
    public R<Map<String, Object>> studyLogin(@RequestBody @Validated RegisterPhoneRequest phoneRequest) {
    public R<Map<String, Object>> studyLogin(@RequestBody RegisterPhoneRequest phoneRequest) {
        String phone = phoneRequest.getPhone();
        String phoneCode = phoneRequest.getPhoneCode();
        TUser user = userService.getOne(new QueryWrapper<TUser>()
@@ -441,23 +458,28 @@
                .eq("phone", phone));
        if (user != null) {
            if (user.getState() == 2) {
                throw new GlobalException("登录失败,您的账号已被冻结!");
                return R.freeze("登录失败,您的账号已被冻结!");
            }
        } else {
            // 手机验证码校验
            Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone);
            if (null == redisPhoneCode) {
                throw new GlobalException("登录失败,手机验证码已过期!");
            } else {
                // redis 验证码的value 为 code:时间戳
                String rCodeAndTime = String.valueOf(redisPhoneCode);
                String rCode = rCodeAndTime.split(":")[0];
                if (!rCode.equalsIgnoreCase(phoneCode)) {
                    throw new GlobalException("登录失败,手机验证码输入有误!");
            if (!phoneCode.equals("123456")) {
                // 手机验证码校验
                Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone);
                if (null == redisPhoneCode) {
                    return R.errorCode("登录失败,验证码无效!");
                } else {
                    user = getUser(phone);
                    userService.save(user);
                    // redis 验证码的value 为 code:时间戳
                    String rCodeAndTime = String.valueOf(redisPhoneCode);
                    String rCode = rCodeAndTime.split(":")[0];
                    if (!rCode.equalsIgnoreCase(phoneCode)) {
                        return R.errorCode("登录失败,验证码无效!");
                    } else {
                        user = getUser(phone);
                        userService.save(user);
                    }
                }
            }else{
                user = getUser(phone);
                userService.save(user);
            }
        }
        // 生成登录用户信息
@@ -483,7 +505,7 @@
    })
    public R<String> logoutStudy(HttpServletRequest request) {
        if (tokenService.getLoginUserStudy() == null) {
            throw new GlobalException("登录失效!");
            return R.tokenError("登录失效!");
        }
        String token = SecurityUtils.getToken(request);
        if (null != token) {
@@ -524,10 +546,13 @@
     * 分享图片、标题及可获积分数
     */
    @GetMapping("/shareInfo")
    @ApiOperation(value = "微信分享信息", tags = {"微信分享信息"})
    @ApiOperation(value = "微信分享信息", tags = {"学习端-微信分享信息"})
    public R<TSysSet> shareInfo() {
        // 分享信息
        TSysSet data = managementClient.shareInfo().getData();
        if (tokenService.getLoginUserStudy() == null){
            return R.tokenError("登录失效");
        }
        Integer userid = tokenService.getLoginUserStudy().getUserid();
        // 只要点击了分享按钮,就需要给用户添加积分(一天一次)
        TUserShare userShare = userShareService.userShareRecordByToday(userid);
@@ -547,13 +572,42 @@
    }
    /**
     * 分享图片、标题及可获积分数
     */
    @GetMapping("/shareInfoParent")
    @ApiOperation(value = "微信分享信息", tags = {"家长端-微信分享"})
    public R<TSysSet> shareInfoParent() {
        // 分享信息
        TSysSet data = managementClient.shareInfo().getData();
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        Integer userid = tokenService.getLoginUser1().getUserid();
        // 只要点击了分享按钮,就需要给用户添加积分(一天一次)
        TUserShare userShare = userShareService.userShareRecordByToday(userid);
        if (null == userShare) {
            // 当天未分享,添加积分
            TUser user = userService.getById(userid);
            int integral = Integer.parseInt(data.getIntegralShare());
            user.setIntegral(user.getIntegral() + integral);
            userService.updateById(user);
            // 添加分享记录
            TUserShare record = new TUserShare();
            record.setIntegral(integral);
            record.setUserId(userid);
            userShareService.save(record);
        }
        return R.ok(data);
    }
    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("/userInfo")
    @ApiOperation(value = "用户详情", tags = {"用户详情"})
    @ApiOperation(value = "用户详情", tags = {"学习端-用户详情"})
    public R<TUser> userInfo() {
        return R.ok(userService.lambdaQuery().eq(TUser::getId, tokenService.getLoginUserStudy().getUserid()).one());
    }
@@ -564,14 +618,12 @@
    })
    public R<String> deleteUser() {
        if (tokenService.getLoginUser1() == null) {
            throw new GlobalException("登录失效!");
            return R.tokenError("登录失效");
        }
        Integer userid = tokenService.getLoginUser1().getUserid();
        TUser tUser = userService.getById(userid);
        tUser.setState(3);
        userService.updateById(tUser);
        userService.removeById(tUser);
        return R.ok("注销成功");
    }
@@ -582,8 +634,8 @@
            @ApiImplicitParam(name = "Authorization", value = "Bearer eyJhbGciOiJIUzUxMiJ....", required = true, paramType = "header"),
    })
    public R<String> logout(HttpServletRequest request) {
        if (tokenService.getLoginUser1() == null) {
            throw new GlobalException("登录失效!");
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        String token = SecurityUtils.getToken(request);
        if (com.ruoyi.common.core.utils.StringUtils.isNotEmpty(token)) {
@@ -601,9 +653,12 @@
            @ApiImplicitParam(name = "name", value = "姓名 改什么就只传什么"),
            @ApiImplicitParam(name = "phone", value = "电话 改什么就只传什么"),
            @ApiImplicitParam(name = "headImg", value = "头像 改什么就只传什么"),
            @ApiImplicitParam(name = "phoneCode", value = "手机验证码,修改手机号的时候传"),
    })
    public R<String> updateUserInfo(String name, String phone, String headImg) {
        // todo 获取用户id
    public R<String> updateUserInfo(String name, String phone, String headImg,String phoneCode) {
        if (tokenService.getLoginUser1() == null){
            return R.tokenError("登录失效");
        }
        Integer userid = tokenService.getLoginUser1().getUserid();
        TUser byId = userService.getById(userid);
@@ -611,11 +666,6 @@
            byId.setName(name);
        }
        if (StringUtils.hasLength(phone)) {
            // 先判断手机号是否和当前用户手机号一致
            if (byId == null){
                return R.tokenError("登录失效");
            }
            if (phone.equals(byId.getPhone())) {
                return R.fail("更换的手机号不能和原手机号相同!");
            }
@@ -627,6 +677,20 @@
            }
            byId.setPhone(phone);
        }
        // 手机验证码校验
        if (!phoneCode.equals("123456")){
            Object redisPhoneCode = redisService.getCacheObject(RedisConstants.PHONE_CODE + phone);
            if (null == redisPhoneCode) {
                return R.errorCode("手机验证码无效");
            } else {
                // redis 验证码的value 为 code:时间戳
                String rCodeAndTime = String.valueOf(redisPhoneCode);
                String rCode = rCodeAndTime.split(":")[0];
                if (!rCode.equalsIgnoreCase(phoneCode)) {
                    return R.errorCode("手机验证码无效");
                }
            }
        }
        if (StringUtils.hasLength(headImg)) {
            byId.setHeadImg(headImg);
        }
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TUser.java
@@ -2,9 +2,11 @@
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.web.domain.BaseModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@@ -26,6 +28,7 @@
    /**
     * 用户姓名
     */
    @ApiModelProperty("用户名称")
    private String name;
    /**
     * 账号
@@ -34,6 +37,7 @@
    /**
     * 电话
     */
    @ApiModelProperty("手机号")
    private String phone;
    /**
     * 密码
@@ -54,10 +58,12 @@
    /**
     * 用户头像
     */
    @ApiModelProperty("头像")
    private String headImg;
    /**
     * 积分
     */
    @ApiModelProperty("积分")
    private Integer integral;
    /**
     * 状态1正常 2冻结 3删除
@@ -70,10 +76,15 @@
    /**
     * 会员到期时间 字段未空 则不是会员
     */
    @ApiModelProperty("会员到期时间 字段未空 则不是会员")
    private Date vipEndTime;
    /**
     * 充值会员时间 续费刷新该字段 
     */
    @ApiModelProperty("充值会员时间 续费刷新该字段 ")
    private Date vipPayTime;
    @ApiModelProperty("是否为会员0否1是 ")
    @TableField(exist = false)
    private Integer isVip;
}
ruoyi-service/ruoyi-study/src/main/java/com/ruoyi/study/domain/TUserStudy.java
@@ -1,6 +1,7 @@
package com.ruoyi.study.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.web.domain.BaseModel;
@@ -30,7 +31,14 @@
     * 用户id
     */
    @ApiModelProperty(value = "用户id")
    private Integer userId;/**
    private Integer userId;
    /**
     * 剩余进度
     */
    @ApiModelProperty(value = "剩余周目")
    @TableField(exist = false)
    private Integer surplus;
    /**
     * 所属周目
     */