Explorar o código

feat: 小说服务/答题服务 调整

hidewnd hai 3 semanas
pai
achega
1f7a41ccbf
Modificáronse 50 ficheiros con 801 adicións e 170 borrados
  1. 3 0
      yt-common/src/main/java/com/ytpm/agent/param/AppParam.java
  2. 3 0
      yt-common/src/main/java/com/ytpm/agent/view/AgentAppView.java
  3. 3 0
      yt-common/src/main/java/com/ytpm/app/model/YtAppDefaultConfig.java
  4. 7 1
      yt-common/src/main/java/com/ytpm/app/model/YtDyzAnswerRecord.java
  5. 8 5
      yt-common/src/main/java/com/ytpm/app/model/YtNovelAdRecord.java
  6. 20 0
      yt-common/src/main/java/com/ytpm/app/model/YtUser.java
  7. 5 0
      yt-common/src/main/java/com/ytpm/app/param/AnswerRecordParam.java
  8. 25 0
      yt-common/src/main/java/com/ytpm/app/param/AppUserRedPackParam.java
  9. 3 0
      yt-common/src/main/java/com/ytpm/app/view/WxDefaultConfig.java
  10. 2 2
      yt-common/src/main/java/com/ytpm/general/PageMeta.java
  11. 1 1
      yt-gateway/src/main/resources/logback.xml
  12. 133 0
      yt-novel/yt-novel-feign/src/main/java/com/ytpm/novel/feign/base/BaseNovelFeign.java
  13. 4 0
      yt-novel/yt-novel-service/pom.xml
  14. 2 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/NovelApplication.java
  15. 7 6
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/config/interceptor/HttpInterceptor.java
  16. 2 15
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/AdController.java
  17. 15 9
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/NovelController.java
  18. 8 1
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/UserController.java
  19. 2 2
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/WxController.java
  20. 5 1
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/dao/AppUserMapper.java
  21. 7 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/dao/NovelAdRecordMapper.java
  22. 19 5
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/dao/NovelMapper.java
  23. 25 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/YtNovelCategoryDto.java
  24. 29 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/YtNovelChapterDto.java
  25. 31 9
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/YtNovelDto.java
  26. 6 3
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/param/NovelAdRecordParam.java
  27. 16 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/param/NovelPageParam.java
  28. 1 1
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/param/UserStaticParam.java
  29. 6 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/AdService.java
  30. 8 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/AppUserService.java
  31. 28 7
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/NovelService.java
  32. 7 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/UserService.java
  33. 40 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/AdServiceImpl.java
  34. 13 0
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/AppUserServiceImpl.java
  35. 42 22
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/NovelServiceImpl.java
  36. 13 25
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/UserServiceImpl.java
  37. 1 1
      yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/VisitorLoginServiceImpl.java
  38. 15 5
      yt-novel/yt-novel-service/src/main/resources/mapper/AppUserMapper.xml
  39. 12 3
      yt-novel/yt-novel-service/src/main/resources/mapper/NovelAdRecordMapper.xml
  40. 133 28
      yt-novel/yt-novel-service/src/main/resources/mapper/NovelMapper.xml
  41. 8 9
      yt-question/yt-question-feign/src/main/java/com/ytpm/question/base/BaseFeign.java
  42. 7 1
      yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/UserController.java
  43. 4 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/dao/AppUserMapper.java
  44. 7 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/dao/QuestionMapper.java
  45. 7 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/service/AppUserService.java
  46. 13 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/service/impl/AppUserServiceImpl.java
  47. 19 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/service/impl/QuestionServiceImpl.java
  48. 6 0
      yt-question/yt-question-service/src/main/resources/mapper/AppUserMapper.xml
  49. 15 3
      yt-question/yt-question-service/src/main/resources/mapper/QuestionMapper.xml
  50. 5 5
      yt-risk/risk-manage/src/main/java/com/ytpm/service/impl/RiskServiceImpl.java

+ 3 - 0
yt-common/src/main/java/com/ytpm/agent/param/AppParam.java

@@ -91,4 +91,7 @@ public class AppParam {
 
     @ApiModelProperty("收益 显示比例")
     private String revenueDisplayRate;
+
+    @ApiModelProperty("小说解锁定时(秒)")
+    private Integer unlockTimer;
 }

+ 3 - 0
yt-common/src/main/java/com/ytpm/agent/view/AgentAppView.java

@@ -186,4 +186,7 @@ public class AgentAppView {
     @ApiModelProperty("收益 显示比例")
     private String revenueDisplayRate;
 
+    @ApiModelProperty("小说解锁定时(秒)")
+    private Integer unlockTimer;
+
 }

+ 3 - 0
yt-common/src/main/java/com/ytpm/app/model/YtAppDefaultConfig.java

@@ -83,6 +83,9 @@ public class YtAppDefaultConfig {
     @ApiModelProperty("收益 显示比例")
     private String revenueDisplayRate;
 
+    @ApiModelProperty("小说解锁定时(秒)")
+    private Integer unlockTimer;
+
     public YtAppDefaultConfig(Object o, String appName, String wxAppId, String wxSecret, String appId, String appKey, int appType,String ditchId) {
         this.configId = Objects.isNull(o)?null: Integer.parseInt(o.toString());
         this.configName = appName;

+ 7 - 1
yt-common/src/main/java/com/ytpm/app/model/YtDyzAnswerRecord.java

@@ -1,10 +1,10 @@
 package com.ytpm.app.model;
 
-import com.ytpm.custom.CustomField;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 @Data
@@ -22,4 +22,10 @@ public class YtDyzAnswerRecord {
     private Date answerTime;
     @ApiModelProperty("用户ID")
     private String userId;
+
+    @ApiModelProperty("红包收益")
+    private BigDecimal revenue;
+
+    @ApiModelProperty("红包收益比例")
+    private String revenueRate;
 }

+ 8 - 5
yt-common/src/main/java/com/ytpm/app/model/YtNovelAdRecord.java

@@ -3,10 +3,9 @@ package com.ytpm.app.model;
 
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -23,12 +22,16 @@ public class YtNovelAdRecord {
     @ApiModelProperty("用户ID")
     private String userId;
 
-    @ApiModelProperty("该功能高记录ID")
-    private String adRecordId;
-
     @ApiModelProperty("用时|秒")
     private Long duration;
 
     @ApiModelProperty("记录时间")
     private Date recordTime;
+
+    @ApiModelProperty("红包收益")
+    private BigDecimal revenue;
+
+    @ApiModelProperty("红包收益比例")
+    private String revenueRate;
+
 }

+ 20 - 0
yt-common/src/main/java/com/ytpm/app/model/YtUser.java

@@ -1,9 +1,11 @@
 package com.ytpm.app.model;
 
 
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.ytpm.app.enums.LoginType;
 import com.ytpm.custom.CustomField;
 import com.ytpm.general.PageMeta;
+import com.ytpm.handle.BigDecimalSerialize;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -134,6 +136,24 @@ public class YtUser extends PageMeta {
     @ApiModelProperty(value = "今日收益")
     private BigDecimal todayIncome;
 
+    /** 红包余额 */
+    @CustomField(node = 1)
+    @ApiModelProperty("红包余额")
+    @JsonSerialize(using = BigDecimalSerialize.class)
+    private BigDecimal redPacketBalance;
+
+    @CustomField(node = 1)
+    @ApiModelProperty("今日红包余额")
+    @JsonSerialize(using = BigDecimalSerialize.class)
+    private BigDecimal todayRedPacketBalance;
+
+    /** 红包总金额 */
+    @ApiModelProperty("红包总金额")
+    @JsonSerialize(using = BigDecimalSerialize.class)
+    private BigDecimal redPacketAmount;
+
+
+
     /**
      * 登录历史记录
      */

+ 5 - 0
yt-common/src/main/java/com/ytpm/app/param/AnswerRecordParam.java

@@ -5,6 +5,8 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
+
 
 @Data
 @ApiModel("答题记录入参")
@@ -19,4 +21,7 @@ public class AnswerRecordParam {
     private Long duration;
     @ApiModelProperty("用户ID")
     private String userId;
+
+    @ApiModelProperty("红包收益")
+    private BigDecimal revenue;
 }

+ 25 - 0
yt-common/src/main/java/com/ytpm/app/param/AppUserRedPackParam.java

@@ -0,0 +1,25 @@
+package com.ytpm.app.param;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author lih
+ * @date 2025-10-13 11:00
+ */
+@Data
+@ApiModel("用户红包扣减入参")
+public class AppUserRedPackParam {
+    @ApiModelProperty("用户ID")
+    private String userId;
+
+    @ApiModelProperty("扣减余额")
+    private BigDecimal deductRevenue;
+
+    @ApiModelProperty("扣减原因")
+    private String reason;
+}

+ 3 - 0
yt-common/src/main/java/com/ytpm/app/view/WxDefaultConfig.java

@@ -78,4 +78,7 @@ public class WxDefaultConfig {
 
     @ApiModelProperty("收益 显示比例")
     private String revenueDisplayRate;
+
+    @ApiModelProperty("小说解锁定时(秒)")
+    private Integer unlockTimer;
 }

+ 2 - 2
yt-common/src/main/java/com/ytpm/general/PageMeta.java

@@ -30,12 +30,12 @@ public class PageMeta implements Serializable {
      * 当前页数量(查询量)
      */
     @ApiModelProperty(value = "当前页数量(查询量)")
-    private Integer limit;
+    private Integer limit = 20;
     /**
      * 当前页码
      */
     @ApiModelProperty(value = "当前页码")
-    private Integer page;
+    private Integer page = 1;
     /**
      * 总页数
      */

+ 1 - 1
yt-gateway/src/main/resources/logback.xml

@@ -3,7 +3,7 @@
     <!--服务名-->
     <property name="server.name" value="yt-gateway" />
     <!-- 日志存放路径 -->
-    <property name="log.path" value="logs/yt-gateway" />
+    <property name="log.path" value="logs" />
     <!-- 日志输出格式 -->
     <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
 

+ 133 - 0
yt-novel/yt-novel-feign/src/main/java/com/ytpm/novel/feign/base/BaseNovelFeign.java

@@ -1,9 +1,142 @@
 package com.ytpm.novel.feign.base;
 
 
+import com.ytpm.agent.param.AdRecordListParam;
+import com.ytpm.agent.param.AuditCheckParam;
+import com.ytpm.agent.view.AgentAdGroupStaticsVO;
+import com.ytpm.agent.view.AgentTopCountView;
+import com.ytpm.app.model.YtAppDefaultConfig;
+import com.ytpm.app.model.YtDyzAdRecord;
+import com.ytpm.app.model.YtDyzUser;
+import com.ytpm.app.model.YtUser;
+import com.ytpm.app.param.AppConfigUpdateParam;
+import com.ytpm.app.param.AppQueryUserTodayTimeParam;
+import com.ytpm.app.param.AppUserParam;
+import com.ytpm.app.param.AppUserQueryParam;
+import com.ytpm.app.param.AppUserTodayBannedParam;
+import com.ytpm.app.param.YtAppUserListParam;
+import com.ytpm.app.view.WxDefaultConfig;
+import com.ytpm.app.view.YtAppUserListView;
+import com.ytpm.general.Result;
+import com.ytpm.general.ResultTable;
+import com.ytpm.middle.view.DashboardRankingListVO;
+import com.ytpm.middle.view.DashboardRevenueVO;
+import com.ytpm.middle.view.DashboardRiskVO;
+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.RequestParam;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
 /**
  * @author lih
  * @date 2025-09-30 09:09
  */
 public interface BaseNovelFeign {
+
+
+    @GetMapping("/visitor/getLoginDitchCount")
+    int getLoginDitchCount(@RequestParam("deviceId") String deviceId, @RequestParam("hours") Integer hours);
+
+    @GetMapping("/visitor/getDitchCount")
+    int getDitchCount(@RequestParam("deviceId") String deviceId, @RequestParam("hours") Integer hours);
+
+    @GetMapping("/user/getMonthRegistryUser")
+    List<YtDyzUser> getMonthRegistryUser(@RequestParam("appIds") String appIds, @RequestParam("type") Integer type);
+
+    @PostMapping("/user/queryAll")
+    ResultTable<YtAppUserListView> queryAll(@RequestBody YtAppUserListParam param);
+
+    @GetMapping("/user/getUserInfo")
+    Result<YtUser> getUserInfo(@RequestParam("userId") String userId);
+
+    @PostMapping("/user/getUserList")
+    ResultTable<YtUser> getUserList(@RequestBody AppUserParam param);
+
+    @PostMapping("/user/getUserAll")
+    ResultTable<YtUser> getUserAll(@RequestBody AppUserParam param);
+
+    @PostMapping("/user/updateUserInfo")
+    Result<?> updateUserInfo(@RequestBody YtUser ytUser);
+
+    @GetMapping("/user/adRecords")
+    ResultTable<YtDyzAdRecord> adRecords(@RequestParam(name = "userId", required = true) String userId,
+                                         @RequestParam(name = "adsourceType", required = false) Integer adsourceType);
+
+    @PostMapping("/user/adRecords/page")
+    ResultTable<YtDyzAdRecord> adRecordsPage(@RequestBody AdRecordListParam param);
+
+    @GetMapping("/user/adRecords/count/month")
+    Result<Integer> queryRecordMonthCount(@RequestParam(name = "userId") String userId,
+                                          @RequestParam(name = "adSourceType", required = false) Integer adSourceType,
+                                          @RequestParam(name = "startTime", required = false) String startTime);
+
+    @PostMapping("/user/queryUserByTime")
+    List<YtUser> queryUserByTime(@RequestBody AppUserQueryParam appUserQueryParam);
+
+    @PostMapping("/user/queryUserByTodayTime")
+    int[] queryUserByTodayTime(@RequestBody AppQueryUserTodayTimeParam appQueryUserTodayTimeParam);
+
+    @PostMapping("/user/queryLoginRecords")
+    List<String> queryLoginRecords(@RequestBody AppUserQueryParam appUserQueryParam);
+
+    @GetMapping("/user/queryByOpenid")
+    List<YtUser> queryByOpenid(@RequestParam("openid") String openid);
+
+    @PostMapping("/wx/saveAppConfig")
+    Result<String> saveAppConfig(@RequestBody YtAppDefaultConfig defaultConfig);
+
+    @PostMapping("/wx/updateAppConfig")
+    Result<String> updateAppConfig(@RequestBody YtAppDefaultConfig defaultConfig);
+
+    @PostMapping("/wx/updateAppsConfig")
+    void updateAppsConfig(@RequestBody AppConfigUpdateParam param);
+
+    @GetMapping("/wx/getConfigs")
+    List<WxDefaultConfig> getConfigs(@RequestParam(name = "appIds") String appIds);
+
+    @PostMapping("/user/queryTodayBanned")
+    List<YtUser> queryTodayBanned(@RequestBody AppUserTodayBannedParam appUserTodayBannedParam);
+
+    @GetMapping("/ad/getAdCount")
+    Map<String, BigDecimal> getAdCount(@RequestParam(name = "appIds") String appIds);
+
+    @GetMapping("/ad/getAppTopCount")
+    AgentTopCountView getAppTopCount(@RequestParam(name = "appIds") String appIds);
+
+    @GetMapping("/ad/getAppRankingList")
+    DashboardRankingListVO queryRankingList(@RequestParam(name = "sortBy") Integer sortBy, @RequestParam(name = "limit") Integer limit);
+
+    @GetMapping("/ad/revenueStatics")
+    DashboardRevenueVO revenueStatics(@RequestParam(name = "apkIds") String apkIds);
+
+    @GetMapping("/ad/userStatics")
+    DashboardRiskVO userStatics(@RequestParam(name = "appId") String appId);
+
+    @GetMapping("/ad/getAgentProfit")
+    List<AgentAdGroupStaticsVO> getAgentProfit(@RequestParam(name = "appIds") String appIds);
+
+    @PostMapping("/user/getRevenueByTime")
+    BigDecimal getRevenueByTime(@RequestBody YtAppUserListParam param);
+
+    @GetMapping("/wx/delDefaultConfig")
+    void delAppConfig(@RequestParam("appId") String appId);
+
+    @PostMapping("/user/unLockUser")
+    void unLockUser(@RequestParam("userIds") String userIds);
+
+    /**
+     * 锁定用户
+     */
+    @GetMapping("/user/lockUser")
+    YtUser lockUser(@RequestParam(name = "userId") String userId, @RequestParam("userStatus") Integer userStatus);
+
+    /**
+     * 批量审核用户
+     */
+    @PostMapping("/user/batchAudit")
+    void batchAudit(@RequestBody AuditCheckParam auditCheckParam);
 }

+ 4 - 0
yt-novel/yt-novel-service/pom.xml

@@ -44,6 +44,10 @@
             <artifactId>mybatis-spring-boot-starter</artifactId>
             <version>2.2.0</version>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.zaxxer</groupId>
             <artifactId>HikariCP</artifactId>

+ 2 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/NovelApplication.java

@@ -6,6 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration;
+import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.web.bind.annotation.RestController;
@@ -22,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
         JdbcTemplateAutoConfiguration.class
 })
 @EnableDiscoveryClient
+@EnableCaching
 @EnableFeignClients(basePackages = {"com.ytpm.feign"})
 public class NovelApplication {
     public static void main(String[] args) {

+ 7 - 6
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/config/interceptor/HttpInterceptor.java

@@ -1,5 +1,6 @@
 package com.ytpm.novel.config.interceptor;
 
+import lombok.NonNull;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
@@ -18,11 +19,12 @@ public class HttpInterceptor implements HandlerInterceptor {
     private String applicationNameZh;
 
     @Override
-    public boolean preHandle(HttpServletRequest request,
-                             HttpServletResponse response, Object obj) throws Exception {
+    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
+                             @NonNull Object obj) {
         // 获取客户端IP地址
         String clientIp = getClientIp(request);
-        log.info("{}收到来自客户端[{}]的用户请求", applicationNameZh, clientIp);
+        String requestURI = request.getRequestURI();
+        log.info("{}收到来自客户端[{}]的用户请求:{}", applicationNameZh, clientIp, requestURI);
         return true;
     }
 
@@ -38,9 +40,8 @@ public class HttpInterceptor implements HandlerInterceptor {
      * 请求处理之后调用;在视图渲染之前,controller处理之后。
      */
     @Override
-    public void postHandle(HttpServletRequest request,
-                           HttpServletResponse response, Object obj, ModelAndView mv)
-            throws Exception {
+    public void postHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
+                           @NonNull Object obj, ModelAndView mv) {
         response.setDateHeader("Expires", 0);
         response.setHeader("Buffer", "True");
         response.setHeader("Cache-Control", "no-cache");

+ 2 - 15
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/AdController.java

@@ -1,15 +1,12 @@
 package com.ytpm.novel.controller;
 
-import cn.hutool.core.util.IdUtil;
 import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
-import com.ytpm.app.model.YtNovelAdRecord;
 import com.ytpm.app.param.DyzAdRecordParam;
 import com.ytpm.general.Result;
 import com.ytpm.middle.view.DashboardRankingListVO;
 import com.ytpm.middle.view.DashboardRevenueVO;
 import com.ytpm.middle.view.DashboardRiskVO;
-import com.ytpm.novel.dao.NovelAdRecordMapper;
 import com.ytpm.novel.model.param.NovelAdRecordParam;
 import com.ytpm.novel.service.AdService;
 import io.swagger.annotations.Api;
@@ -25,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -38,9 +34,6 @@ public class AdController {
     @Resource
     private AdService adService;
 
-    @Resource
-    private NovelAdRecordMapper novelAdRecordMapper;
-
     /**
      * 保存广告记录
      */
@@ -101,16 +94,10 @@ public class AdController {
         return adService.getAgentProfit(appIds);
     }
 
-    @ApiOperation("保存用户广告记录")
+    @ApiOperation("保存用户广告观看记录")
     @PostMapping("/novel/record")
     public Result<String> novelAdRecord(@RequestBody NovelAdRecordParam param) {
-        YtNovelAdRecord record = new YtNovelAdRecord();
-        record.setRecordId(IdUtil.fastSimpleUUID());
-        record.setAdRecordId(param.getAdRecordId());
-        record.setUserId(param.getUserId());
-        record.setDuration(param.getDuration());
-        record.setRecordTime(new Date());
-        novelAdRecordMapper.insertNovelAdRecord(record);
+        adService.saveUserRecord(param);
         return Result.resultOk("保存成功");
     }
 

+ 15 - 9
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/NovelController.java

@@ -1,8 +1,8 @@
 package com.ytpm.novel.controller;
 
 
-import com.ytpm.app.model.YtNovel;
-import com.ytpm.app.model.YtNovelCategory;
+import com.ytpm.app.model.YtNovelChapter;
+import com.ytpm.novel.model.dto.YtNovelCategoryDto;
 import com.ytpm.general.Result;
 import com.ytpm.general.ResultTable;
 import com.ytpm.novel.model.dto.YtNovelDto;
@@ -42,22 +42,28 @@ public class NovelController {
         return ResultTable.resultTableOk(novelService.selectNovelPage(param));
     }
 
-    @ApiOperation("保存小说章节阅读记录")
-    @PostMapping("/record")
-    public Result<String> saveNovelRecord(@RequestBody NovelRecordParam param) {
-        return Result.resultObjOk(novelService.saveNovelRecord(param));
+    @ApiOperation("获取小说章节列表")
+    @PostMapping("/chapter/page")
+    public ResultTable<YtNovelChapter> queryNovelCategoryList(@RequestBody NovelPageParam param) {
+        return ResultTable.resultTableOk(novelService.selectNovelChapterPage(param));
     }
 
     @ApiOperation("获取小说信息")
     @GetMapping("/info")
     public Result<YtNovelDto> queryNovelInfo(@RequestParam("novelId") String novelId,
                                              @RequestParam(value = "userId", required = false) String userId) {
-        return Result.resultObjOk(novelService.selectNovelById(novelId,userId));
+        return Result.resultObjOk(novelService.info(novelId, userId));
+    }
+
+    @ApiOperation("保存小说章节阅读记录")
+    @PostMapping("/record")
+    public Result<String> saveNovelRecord(@RequestBody NovelRecordParam param) {
+        return Result.resultObjOk(novelService.saveNovelRecord(param));
     }
 
     @ApiOperation("获取用户书架列表")
     @GetMapping("/shelf/list")
-    public Result<List<YtNovel>> queryNovelShelfList(@RequestParam("userId") String userId) {
+    public Result<List<YtNovelDto>> queryNovelShelfList(@RequestParam("userId") String userId) {
         return Result.resultObjOk(novelService.selectNovelShelf(userId));
     }
 
@@ -69,7 +75,7 @@ public class NovelController {
 
     @ApiOperation(("获取小说分类列表"))
     @GetMapping("/category/list")
-    public Result<List<YtNovelCategory>> queryCategoryList() {
+    public Result<List<YtNovelCategoryDto>> queryCategoryList() {
         return Result.resultObjOk(novelService.selectCategoryList());
     }
 

+ 8 - 1
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/UserController.java

@@ -15,6 +15,7 @@ import com.ytpm.app.model.YtUser;
 import com.ytpm.app.param.AppQueryUserTodayTimeParam;
 import com.ytpm.app.param.AppUserParam;
 import com.ytpm.app.param.AppUserQueryParam;
+import com.ytpm.app.param.AppUserRedPackParam;
 import com.ytpm.app.param.AppUserTodayBannedParam;
 import com.ytpm.app.param.YtAppUserListParam;
 import com.ytpm.app.view.HourCountView;
@@ -25,7 +26,7 @@ import com.ytpm.general.ResultTable;
 import com.ytpm.novel.dao.AdRecordMapper;
 import com.ytpm.novel.dao.AppUserMapper;
 import com.ytpm.novel.dao.LoginRecordMapper;
-import com.ytpm.novel.model.dto.UserStaticParam;
+import com.ytpm.novel.model.param.UserStaticParam;
 import com.ytpm.novel.service.UserService;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -242,4 +243,10 @@ public class UserController {
         userService.batchAudit(checkParam);
     }
 
+
+    @ApiOperation("扣减用户红包余额")
+    @PostMapping("/redPacket/deduct")
+    public Result<String> deductRedPack(@RequestBody AppUserRedPackParam param){
+        return userService.deductRedPacket(param);
+    }
 }

+ 2 - 2
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/controller/WxController.java

@@ -114,7 +114,7 @@ public class WxController {
         String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
         String curUser = HttpUtil.get(userInfoUrl);
         WxUserInfo wxUserInfo = JSON.parseObject(curUser, WxUserInfo.class);
-        log.error("获取的用户信息:{}", wxUserInfo);
+        log.info("[wx login]获取的用户信息:{}", wxUserInfo);
         return wxUserInfo;
     }
 
@@ -134,7 +134,7 @@ public class WxController {
         //拿到授权码 请求微信登录返回access_token
         String result = HttpUtil.get(wxLoginUrl);
         WxLoginResult loginResult = JSON.parseObject(result, WxLoginResult.class);
-        log.error("授权码获取的登录结果:{}", loginResult);
+        log.info("[wx login]授权码获取的登录结果:{}", loginResult);
         return loginResult;
     }
 

+ 5 - 1
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/dao/AppUserMapper.java

@@ -13,7 +13,7 @@ import com.ytpm.app.view.YtAppUserListView;
 import com.ytpm.middle.view.AppRankingListVO;
 import com.ytpm.middle.view.AppUserHourVO;
 import com.ytpm.middle.view.UserRankingListVO;
-import com.ytpm.novel.model.dto.UserStaticParam;
+import com.ytpm.novel.model.param.UserStaticParam;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -206,4 +206,8 @@ public interface AppUserMapper {
 
     void updateTotal(@Param("userId") String userId, @Param("videoCount") int videoCount, @Param("revenue") BigDecimal revenue);
 
+    /**
+     * 更新红包余额
+     */
+    void updateUserRedPacket(@Param("userId") String userId, @Param("revenue") BigDecimal redPackRevenue);
 }

+ 7 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/dao/NovelAdRecordMapper.java

@@ -5,6 +5,7 @@ import com.ytpm.app.model.YtNovelAdRecord;
 import org.apache.ibatis.annotations.Param;
 import org.mapstruct.Mapper;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -17,4 +18,10 @@ public interface NovelAdRecordMapper {
     List<YtNovelAdRecord> selectToDayNovelRecode(@Param("userId") String userId);
 
     void insertNovelAdRecord(@Param("param") YtNovelAdRecord adRecord);
+
+    /**
+     * 获取答题收益
+     * @param type 1-今日 2-历史
+     */
+    BigDecimal getAnswerRevenue(@Param("userId")String userId, @Param("type") int type);
 }

+ 19 - 5
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/dao/NovelMapper.java

@@ -2,10 +2,10 @@ package com.ytpm.novel.dao;
 
 
 import com.ytpm.app.model.YtNovel;
-import com.ytpm.app.model.YtNovelCategory;
 import com.ytpm.app.model.YtNovelChapter;
 import com.ytpm.app.model.YtNovelShelf;
 import com.ytpm.app.model.YtNovelReadRecord;
+import com.ytpm.novel.model.dto.YtNovelCategoryDto;
 import com.ytpm.novel.model.dto.YtNovelDto;
 import com.ytpm.novel.model.param.NovelPageParam;
 import org.apache.ibatis.annotations.Mapper;
@@ -23,20 +23,33 @@ public interface NovelMapper {
     /**
      * 分页查询小说信息
      */
-    List<YtNovelDto> selectNovelList(@Param("param") NovelPageParam param);
+    List<YtNovelDto> selectNovelPage(@Param("param") NovelPageParam param);
+
+    /**
+     * 分页查询小说章节
+     */
+    List<YtNovelChapter> selectNovelChapterPage(@Param("param") NovelPageParam param);
 
     /**
      * 根据小说ID查询小说信息
      */
-    YtNovelDto selectByNovelId(@Param("novelId") String novelId);
+    YtNovel selectByPrimaryKey(@Param("novelId") String novelId);
 
-    List<YtNovel> selectByNovelIds(@Param("novelIds") List<String> novelIds);
+    /**
+     * 批量查询小说信息
+     */
+    List<YtNovelDto> selectByNovelIds(@Param("novelIds") List<String> novelIds);
 
     /**
      * 根据小说ID查询小说章节集合
      */
     List<YtNovelChapter> selectNovelChapter(@Param("novelId")String novelId);
 
+    /**
+     * 查询小说章节信息
+     */
+    YtNovelChapter selectNovelChapterByPrimaryKey(@Param("chapterId")String chapterId);
+
     /**
      * 查询用户书架
      */
@@ -57,6 +70,7 @@ public interface NovelMapper {
      *  保存用户书架
      */
     void insertNovelShelf(YtNovelShelf shelf);
+
     /**
      *  更新用户书架
      */
@@ -66,6 +80,6 @@ public interface NovelMapper {
     /**
      * 查询小说分类列表
      */
-    List<YtNovelCategory> selectCategoryList();
+    List<YtNovelCategoryDto> selectCategoryList();
 
 }

+ 25 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/YtNovelCategoryDto.java

@@ -0,0 +1,25 @@
+package com.ytpm.novel.model.dto;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lih
+ * @date 2025-10-13 15:39
+ */
+@Data
+public class YtNovelCategoryDto {
+
+    @ApiModelProperty("分类ID")
+    private String categoryId;
+
+    @ApiModelProperty("分类名称")
+    private String categoryName;
+
+    @ApiModelProperty("分类介绍")
+    private String categoryDesc;
+
+    @ApiModelProperty("排序号")
+    private Integer sort;
+}

+ 29 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/YtNovelChapterDto.java

@@ -0,0 +1,29 @@
+package com.ytpm.novel.model.dto;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author lih
+ * @date 2025-10-13 16:17
+ */
+@Data
+public class YtNovelChapterDto implements Serializable {
+
+    @ApiModelProperty("章节ID")
+    private String chapterId;
+    @ApiModelProperty("小说ID")
+    private String novelId;
+    @ApiModelProperty("章节数")
+    private Integer chapter;
+    @ApiModelProperty("章节名称")
+    private String chapterName;
+    @ApiModelProperty("章节内容链接")
+    private String content;
+    @ApiModelProperty("章节内容")
+    private String contentText;
+
+}

+ 31 - 9
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/YtNovelDto.java

@@ -1,30 +1,52 @@
 package com.ytpm.novel.model.dto;
 
 
-import com.ytpm.app.model.YtNovel;
-import com.ytpm.app.model.YtNovelChapter;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * 小说详情信息
+ *
  * @author lih
  * @date 2025-09-30 14:34
  */
 @Data
-@EqualsAndHashCode(callSuper = true)
-public class YtNovelDto extends YtNovel implements Serializable {
+public class YtNovelDto implements Serializable {
 
-    @ApiModelProperty("小说章节集合")
-    private List<YtNovelChapter> chapterList;
+    @ApiModelProperty("小说ID")
+    private String novelId;
+    @ApiModelProperty("小说分类ID")
+    private String categoryId;
+    @ApiModelProperty("小说名称")
+    private String novelName;
+    @ApiModelProperty("小说作者")
+    private String novelAuthor;
+    @ApiModelProperty("小说简介")
+    private String novelIntroduction;
+
+    @ApiModelProperty("小说字数")
+    private Long novelWords;
+    @ApiModelProperty("阅读数")
+    private Long novelReads;
+    @ApiModelProperty("封面")
+    private String novelImg;
+    @ApiModelProperty("整篇小说地址")
+    private String novelUrl;
+    @ApiModelProperty("书籍id(第三方APIid)")
+    private String bookId;
+
+    @ApiModelProperty("小说上下架状态|0未上架|1上架")
+    private Integer status;
+    @ApiModelProperty("连载状态|0连载中|1完结")
+    private Integer state;
 
     @ApiModelProperty("是否已在书架|0否|1是")
     private Integer ifSelfShelf;
 
+    @ApiModelProperty("最后阅读章节ID")
+    private String lastReadChapterId;
     @ApiModelProperty("最后阅读章节")
-    private YtNovelChapter lastReadChapter;
+    private YtNovelChapterDto lastReadChapter;
 }

+ 6 - 3
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/param/NovelAdRecordParam.java

@@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 /**
  * 用户广告记录参数
@@ -17,10 +18,12 @@ public class NovelAdRecordParam implements Serializable {
     @ApiModelProperty("用户ID")
     private String userId;
 
-    @ApiModelProperty("广告记录ID")
-    private String adRecordId;
-
     @ApiModelProperty("耗时")
     private Long duration;
 
+    @ApiModelProperty("红包收益")
+    private BigDecimal revenue;
+
+    @ApiModelProperty("红包收益比例")
+    private String revenueRate;
 }

+ 16 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/param/NovelPageParam.java

@@ -2,6 +2,8 @@ package com.ytpm.novel.model.param;
 
 
 import com.ytpm.general.PageMeta;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
@@ -10,10 +12,24 @@ import lombok.EqualsAndHashCode;
  * @date 2025-09-30 15:25
  */
 @Data
+@ApiModel("小说查询入参")
 @EqualsAndHashCode(callSuper = true)
 public class NovelPageParam extends PageMeta {
+    @ApiModelProperty("小说ID")
+    private String novelId;
 
+    @ApiModelProperty("用户ID")
+    private String userId;
+
+    @ApiModelProperty("小说分类ID")
     private String categoryId;
 
+    @ApiModelProperty("小说名称入参")
     private String novelName;
+
+    @ApiModelProperty("查询关键字")
+    private String searchKeyword;
+
+    @ApiModelProperty("连载状态|0连载中|1完结")
+    private Integer state;
 }

+ 1 - 1
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/dto/UserStaticParam.java → yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/model/param/UserStaticParam.java

@@ -1,4 +1,4 @@
-package com.ytpm.novel.model.dto;
+package com.ytpm.novel.model.param;
 
 
 import com.ytpm.app.param.AppUserQueryParam;

+ 6 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/AdService.java

@@ -10,6 +10,7 @@ import com.ytpm.general.Result;
 import com.ytpm.middle.view.DashboardRankingListVO;
 import com.ytpm.middle.view.DashboardRevenueVO;
 import com.ytpm.middle.view.DashboardRiskVO;
+import com.ytpm.novel.model.param.NovelAdRecordParam;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -54,4 +55,9 @@ public interface AdService {
     String saveRecordAndChangeUser(DyzAdRecordParam param, YtNovelUser user);
 
     List<YtDyzAdRecord> queryRecordByIds(List<String> adRecordIds);
+
+    /**
+     * 保存用户广告收益记录
+     */
+    void saveUserRecord(NovelAdRecordParam param);
 }

+ 8 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/AppUserService.java

@@ -6,6 +6,8 @@ import com.ytpm.app.param.WxLoginParam;
 import com.ytpm.app.view.WxLoginResult;
 import com.ytpm.app.view.WxUserInfo;
 
+import java.math.BigDecimal;
+
 public interface AppUserService {
     /**
      * openid查询用户信息
@@ -16,4 +18,10 @@ public interface AppUserService {
      * 子事务处理用户crud
      */
     YtNovelUser crudForNewTrans(WxLoginParam param, WxUserInfo wxUserInfo, WxLoginResult loginResult);
+
+
+    /**
+     * 获取配置项 用户红包收益换算比例
+     */
+    BigDecimal getUserRevenueRate(String appId);
 }

+ 28 - 7
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/NovelService.java

@@ -2,8 +2,8 @@ package com.ytpm.novel.service;
 
 
 import com.github.pagehelper.PageInfo;
-import com.ytpm.app.model.YtNovel;
-import com.ytpm.app.model.YtNovelCategory;
+import com.ytpm.app.model.YtNovelChapter;
+import com.ytpm.novel.model.dto.YtNovelCategoryDto;
 import com.ytpm.novel.model.dto.YtNovelDto;
 import com.ytpm.novel.model.param.NovelPageParam;
 import com.ytpm.novel.model.param.NovelRecordParam;
@@ -18,19 +18,40 @@ import java.util.List;
 public interface NovelService {
 
     /**
-     * 根据分类ID、小说名称查询小说列表
+     * 分页查询小说<br>
+     * 可查询参数: 小说分类ID,小说名称
      */
     PageInfo<YtNovelDto> selectNovelPage(NovelPageParam param);
 
-    YtNovelDto selectNovelById(String novelId, String userId);
+    /**
+     * 分页查询小说章节<br>
+     * 查询参数: 小说ID
+     */
+    PageInfo<YtNovelChapter> selectNovelChapterPage(NovelPageParam param);
 
-    List<YtNovel> selectNovelShelf(String userId);
+    /**
+     * 获取小说详情
+     */
+    YtNovelDto info(String novelId, String userId);
 
-    String saveNovelRecord(NovelRecordParam param);
+    /**
+     * 查询用户书架信息
+     */
+    List<YtNovelDto> selectNovelShelf(String userId);
 
+    /**
+     * 保存更新用户书架
+     */
     String saveNovelShelf(NovelShelfParam param);
 
-    List<YtNovelCategory> selectCategoryList();
+    /**
+     * 保存用户阅读记录
+     */
+    String saveNovelRecord(NovelRecordParam param);
 
+    /**
+     * 查询小说分类记录
+     */
+    List<YtNovelCategoryDto> selectCategoryList();
 
 }

+ 7 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/UserService.java

@@ -3,8 +3,10 @@ package com.ytpm.novel.service;
 
 import com.ytpm.agent.param.AuditCheckParam;
 import com.ytpm.app.model.YtNovelUser;
+import com.ytpm.app.param.AppUserRedPackParam;
 import com.ytpm.app.param.YtAppUserListParam;
 import com.ytpm.app.view.YtAppUserListView;
+import com.ytpm.general.Result;
 
 import java.util.List;
 
@@ -40,4 +42,9 @@ public interface UserService {
      * 批量解锁用户
      */
     void unLockUser(String userIds);
+
+    /**
+     * 用户扣减红包余额
+     */
+    Result<String> deductRedPacket(AppUserRedPackParam param);
 }

+ 40 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/AdServiceImpl.java

@@ -1,5 +1,6 @@
 package com.ytpm.novel.service.impl;
 
+import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
@@ -10,12 +11,14 @@ import com.ytpm.agent.enums.UserStatusEnum;
 import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
 import com.ytpm.app.model.YtDyzAdRecord;
+import com.ytpm.app.model.YtNovelAdRecord;
 import com.ytpm.app.model.YtNovelUser;
 import com.ytpm.app.param.DyzAdRecordParam;
 import com.ytpm.feign.RiskFeign;
 import com.ytpm.general.RepMessage;
 import com.ytpm.general.Result;
 import com.ytpm.general.StatusCode;
+import com.ytpm.handle.CustomerException;
 import com.ytpm.middle.view.AppRankingListVO;
 import com.ytpm.middle.view.AppRevenueHourVO;
 import com.ytpm.middle.view.AppUserHourVO;
@@ -26,8 +29,11 @@ import com.ytpm.middle.view.DashboardRiskVO;
 import com.ytpm.middle.view.UserRankingListVO;
 import com.ytpm.novel.dao.AdRecordMapper;
 import com.ytpm.novel.dao.AppUserMapper;
+import com.ytpm.novel.dao.NovelAdRecordMapper;
+import com.ytpm.novel.model.param.NovelAdRecordParam;
 import com.ytpm.novel.service.AdService;
 import com.ytpm.novel.model.view.AgentNetworkAgg;
+import com.ytpm.novel.service.AppUserService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -36,10 +42,12 @@ import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -56,6 +64,10 @@ public class AdServiceImpl implements AdService {
     private AdRecordMapper adRecordMapper;
     @Autowired
     private AppUserMapper appUserMapper;
+    @Resource
+    private AppUserService appUserService;
+    @Resource
+    private NovelAdRecordMapper novelAdRecordMapper;
     @Autowired
     private RiskFeign riskFeign;
 
@@ -313,4 +325,32 @@ public class AdServiceImpl implements AdService {
         return adRecordMapper.selectRecordByIds(AdRecordEnum.LOGIN_BEFORE.getCode(), adRecordIds);
     }
 
+    @Override
+    public void saveUserRecord(NovelAdRecordParam param) {
+        YtNovelUser user = appUserMapper.selectPrimaryKey(param.getUserId());
+        if (Objects.isNull(user)) {
+            throw new CustomerException(RepMessage.TOKEN_EXPIRE);
+        }
+        if (!UserStatusEnum.NORMAL.getCode().equals(user.getUserStatus())) {
+            throw new CustomerException("当前用户处于风控中");
+        }
+        YtNovelAdRecord record = new YtNovelAdRecord();
+        BeanUtil.copyProperties(param, record);
+        record.setRecordId(IdUtil.fastSimpleUUID());
+        record.setRecordTime(new Date());
+        BigDecimal userRevenueRate = appUserService.getUserRevenueRate(user.getAppId());
+        BigDecimal redPackRevenue = BigDecimal.ZERO;
+        if (userRevenueRate != null) {
+            record.setRevenueRate(userRevenueRate.toPlainString());
+            if(record.getRevenue() != null && record.getRevenue().compareTo(BigDecimal.ZERO) > 0){
+                redPackRevenue = record.getRevenue().multiply(userRevenueRate).setScale(5, RoundingMode.HALF_UP);
+            }
+        }
+        novelAdRecordMapper.insertNovelAdRecord(record);
+        // 更新用户红包余额
+        if (redPackRevenue.compareTo(BigDecimal.ZERO) > 0) {
+            appUserMapper.updateUserRedPacket(user.getUserId(), redPackRevenue);
+        }
+    }
+
 }

+ 13 - 0
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/AppUserServiceImpl.java

@@ -9,6 +9,7 @@ import com.ytpm.app.model.YtDyzLoginRecord;
 import com.ytpm.app.model.YtNovelUser;
 import com.ytpm.app.model.YtUser;
 import com.ytpm.app.param.WxLoginParam;
+import com.ytpm.app.view.WxDefaultConfig;
 import com.ytpm.app.view.WxLoginResult;
 import com.ytpm.app.view.WxUserInfo;
 import com.ytpm.constant.StrConstant;
@@ -17,6 +18,7 @@ import com.ytpm.novel.dao.AppUserMapper;
 import com.ytpm.novel.dao.LoginRecordMapper;
 import com.ytpm.novel.redis.RedisService;
 import com.ytpm.novel.service.AppUserService;
+import com.ytpm.util.NumberUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
@@ -81,6 +83,17 @@ public class AppUserServiceImpl implements AppUserService {
         return old;
     }
 
+    @Override
+    public BigDecimal getUserRevenueRate(String appId) {
+        WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByAppId(appId);
+        String revenueDisplayRate = defaultConfig == null ? "" : defaultConfig.getRevenueDisplayRate();
+        BigDecimal revenueRate = null;
+        if (StrUtil.isNotEmpty(revenueDisplayRate)) {
+            revenueRate = NumberUtils.rateToBigDecimal(revenueDisplayRate);
+        }
+        return revenueRate;
+    }
+
     /**
      * 设置扩展信息
      */

+ 42 - 22
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/NovelServiceImpl.java

@@ -2,14 +2,12 @@ package com.ytpm.novel.service.impl;
 
 
 import cn.hutool.core.bean.BeanUtil;
-import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.ytpm.app.model.YtNovel;
-import com.ytpm.app.model.YtNovelCategory;
 import com.ytpm.app.model.YtNovelChapter;
 import com.ytpm.app.model.YtNovelReadRecord;
 import com.ytpm.app.model.YtNovelShelf;
@@ -18,6 +16,8 @@ import com.ytpm.handle.CustomerException;
 import com.ytpm.handle.ValidatedException;
 import com.ytpm.novel.dao.AppUserMapper;
 import com.ytpm.novel.dao.NovelMapper;
+import com.ytpm.novel.model.dto.YtNovelCategoryDto;
+import com.ytpm.novel.model.dto.YtNovelChapterDto;
 import com.ytpm.novel.model.dto.YtNovelDto;
 import com.ytpm.novel.model.param.NovelPageParam;
 import com.ytpm.novel.model.param.NovelRecordParam;
@@ -50,42 +50,62 @@ public class NovelServiceImpl implements NovelService {
     @Override
     public PageInfo<YtNovelDto> selectNovelPage(NovelPageParam param) {
         PageHelper.startPage(param.getPage(), param.getLimit());
-        List<YtNovelDto> list = novelMapper.selectNovelList(param);
+        List<YtNovelDto> list = novelMapper.selectNovelPage(param);
         return new PageInfo<>(list);
     }
 
     @Override
-    public YtNovelDto selectNovelById(String novelId, String userId) {
-        YtNovelDto dto = novelMapper.selectByNovelId(novelId);
-        List<YtNovelChapter> chapterList = novelMapper.selectNovelChapter(novelId);
-        dto.setChapterList(chapterList);
+    public PageInfo<YtNovelChapter> selectNovelChapterPage(NovelPageParam param) {
+        PageHelper.startPage(param.getPage(), param.getLimit());
+        if (StrUtil.isEmpty(param.getNovelId())) {
+            throw new CustomerException("小说ID不能为空");
+        }
+        List<YtNovelChapter> list = new ArrayList<>();
+        if (param.getNovelId() != null) {
+            list = novelMapper.selectNovelChapterPage(param);
+        }
+        return new PageInfo<>(list);
+    }
+
+    @Override
+    public YtNovelDto info(String novelId, String userId) {
+        YtNovel novel = novelMapper.selectByPrimaryKey(novelId);
+        YtNovelDto dto = new YtNovelDto();
+        if (novel == null) {
+            return dto;
+        }
+        BeanUtil.copyProperties(novel, dto);
+        // 查询最后阅读章节
         if (StrUtil.isNotEmpty(userId)) {
-            // 查询书籍是否在书架中
-            YtNovelShelf shelf = novelMapper.selectShelf(userId);
-            if (shelf != null && StrUtil.isNotEmpty(shelf.getNovelIds())) {
-                List<String> novels = JSONArray.parseArray(shelf.getNovelIds(), String.class);
-                dto.setIfSelfShelf(novels.contains(novelId) ? 1 : 0);
-            }
-            // 查询最后阅读章节
             YtNovelReadRecord lastReadRecord = novelMapper.selectLastRecord(userId, novelId);
-            if (lastReadRecord != null && CollUtil.isNotEmpty(chapterList)) {
-                YtNovelChapter chapter = chapterList.stream()
-                        .filter(item -> StrUtil.equals(item.getChapterId(), lastReadRecord.getChapterId()))
-                        .findFirst().orElse(null);
-                dto.setLastReadChapter(chapter);
+            if (lastReadRecord != null && StrUtil.isNotEmpty(lastReadRecord.getChapterId())) {
+                dto.setLastReadChapterId(lastReadRecord.getChapterId());
+                YtNovelChapter chapter = novelMapper.selectNovelChapterByPrimaryKey(lastReadRecord.getChapterId());
+                if (chapter != null) {
+                    YtNovelChapterDto chapterDto = new YtNovelChapterDto();
+                    BeanUtil.copyProperties(chapter, chapterDto);
+                    dto.setLastReadChapter(chapterDto);
+                }
             }
         }
         return dto;
     }
 
     @Override
-    public List<YtNovel> selectNovelShelf(String userId) {
-        List<YtNovel> list = new ArrayList<>();
+    public List<YtNovelDto> selectNovelShelf(String userId) {
+        List<YtNovelDto> list = new ArrayList<>();
         YtNovelShelf shelf = novelMapper.selectShelf(userId);
         if (shelf != null && StrUtil.isNotEmpty(shelf.getNovelIds())) {
             List<String> novels = JSONArray.parseArray(shelf.getNovelIds(), String.class);
             list = novelMapper.selectByNovelIds(novels);
         }
+        for (YtNovelDto dto : list) {
+            // 查询最后阅读章节
+            YtNovelReadRecord lastReadRecord = novelMapper.selectLastRecord(userId, dto.getNovelId());
+            if (lastReadRecord != null) {
+                dto.setLastReadChapterId(lastReadRecord.getChapterId());
+            }
+        }
         return list;
     }
 
@@ -139,7 +159,7 @@ public class NovelServiceImpl implements NovelService {
     }
 
     @Override
-    public List<YtNovelCategory> selectCategoryList() {
+    public List<YtNovelCategoryDto> selectCategoryList() {
         return novelMapper.selectCategoryList();
     }
 }

+ 13 - 25
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/UserServiceImpl.java

@@ -3,7 +3,6 @@ package com.ytpm.novel.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.StrUtil;
 import com.github.pagehelper.PageHelper;
 import com.ytpm.advertise.enums.AdSourceTypeEnum;
 import com.ytpm.agent.enums.UserStatusEnum;
@@ -13,9 +12,10 @@ import com.ytpm.agent.view.AgentAuditCheckVO;
 import com.ytpm.app.model.YtDyzAdRecord;
 import com.ytpm.app.model.YtDyzLoginRecord;
 import com.ytpm.app.model.YtNovelUser;
+import com.ytpm.app.param.AppUserRedPackParam;
 import com.ytpm.app.param.YtAppUserListParam;
-import com.ytpm.app.view.WxDefaultConfig;
 import com.ytpm.app.view.YtAppUserListView;
+import com.ytpm.general.Result;
 import com.ytpm.novel.dao.AdRecordMapper;
 import com.ytpm.novel.dao.AppUserMapper;
 import com.ytpm.novel.dao.LoginRecordMapper;
@@ -25,9 +25,7 @@ import com.ytpm.novel.service.UserService;
 import com.ytpm.risk.enums.BannedTypeEnum;
 import com.ytpm.risk.view.RiskConfigView;
 import com.ytpm.risk.view.RiskTemplateView;
-import com.ytpm.util.NumberUtils;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -58,9 +56,6 @@ public class UserServiceImpl implements UserService {
     @Resource
     private RedisService redisService;
 
-    @Value("${yt.revenue.scale:3}")
-    private Integer revenueScale;
-
 
     @Override
     public List<YtAppUserListView> queryAll(YtAppUserListParam param) {
@@ -114,24 +109,12 @@ public class UserServiceImpl implements UserService {
         if (user != null) {
             user.setLoginRecordList(loginRecordMapper.getLoginRecords(userId));
             user.setNovelAdRecordList(novelAdRecordMapper.selectToDayNovelRecode(userId));
-            // 分层系数
-            WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByAppId(user.getAppId());
-            String revenueDisplayRate = defaultConfig == null ? "" : defaultConfig.getRevenueDisplayRate();
-            BigDecimal todayRevenue = adRecordMapper.getToTalRevenue(userId, 1);
-            BigDecimal totalRevenue = user.getTotalIncome() == null ? adRecordMapper.getToTalRevenue(userId, 2) : user.getTotalIncome();
-            if (StrUtil.isNotEmpty(revenueDisplayRate)) {
-                BigDecimal rate = NumberUtils.rateToBigDecimal(revenueDisplayRate);
-                todayRevenue = todayRevenue.multiply(rate).setScale(revenueScale, RoundingMode.HALF_UP);
-                totalRevenue = totalRevenue.multiply(rate).setScale(revenueScale, RoundingMode.HALF_UP);
-            }
-            // 今日收益
-            user.setTodayIncome(todayRevenue);
-            // 历史收益
-            user.setTotalIncome(totalRevenue);
-            // 前三日总收益
-            if (user.getNearlyIncome() != null) {
-                user.setNearlyIncome(user.getNearlyIncome().setScale(revenueScale, RoundingMode.HALF_UP));
+            // 获取今日红包收益
+            BigDecimal todayRedPacketBalance = novelAdRecordMapper.getAnswerRevenue(userId, 1);
+            if (todayRedPacketBalance != null) {
+                todayRedPacketBalance = todayRedPacketBalance.setScale(5, RoundingMode.HALF_UP);
             }
+            user.setTodayRedPacketBalance(todayRedPacketBalance);
         }
         return user;
     }
@@ -217,7 +200,7 @@ public class UserServiceImpl implements UserService {
      * 用户锁定操作
      */
     private void checkLock(Map.Entry<String, List<YtDyzAdRecord>> entry, AuditUserParam auditParam) {
-        log.error("执行对低价值用户{}的定时风控操作", entry.getKey());
+        log.info("执行对低价值用户{}的定时风控操作", entry.getKey());
         if (auditParam.getEffectTime() == 0) { //立即锁定
             lockUser(entry.getKey(), UserStatusEnum.RISK.getCode());
             redisService.setTimeOutHoursStr("unlock_" + entry.getKey(), auditParam.getAppId(), auditParam.getBannedLimit() * 24L);
@@ -249,4 +232,9 @@ public class UserServiceImpl implements UserService {
             appUserMapper.unlockUser(userIds);
         }
     }
+
+    @Override
+    public Result<String> deductRedPacket(AppUserRedPackParam param) {
+        return Result.resultObjOk("not implement");
+    }
 }

+ 1 - 1
yt-novel/yt-novel-service/src/main/java/com/ytpm/novel/service/impl/VisitorLoginServiceImpl.java

@@ -91,7 +91,7 @@ public class VisitorLoginServiceImpl extends AbstractLoginService {
     protected void validateParams(LoginParam loginParam, HttpServletRequest request) {
         // deviceId空值处理
         if (StrUtil.isEmpty(loginParam.getDeviceId())) {
-            log.warn("[visitor login validate]deviceId is empty!");
+            log.info("[visitor login validate]deviceId is empty!");
             // 尝试从phoneJson中获取
             if (StrUtil.isNotEmpty(loginParam.getPhoneJson())) {
                 JSONObject phoneJson = JSONObject.parseObject(loginParam.getPhoneJson());

+ 15 - 5
yt-novel/yt-novel-service/src/main/resources/mapper/AppUserMapper.xml

@@ -169,6 +169,9 @@
             <if test="canAllowAutoRefresh != null">
                 can_allow_auto_refresh = #{canAllowAutoRefresh},
             </if>
+            <if test="unlockTimer != null">
+                unlock_timer = #{unlockTimer},
+            </if>
             <if test="revenueDisplayRate != null">
                 revenue_display_rate = #{revenueDisplayRate}
             </if>
@@ -460,7 +463,7 @@
             can_use_root, can_use_adb, can_use_float, can_accumulation,
             ditch_id, power_wait_time, interstitial_interval_time,
             low_value_tip, brush_tip,flow_interval_time,task_limit_tip,start_wait_time,
-            can_cache_video,can_allow_auto_refresh,revenue_display_rate
+            can_cache_video,can_allow_auto_refresh,revenue_display_rate,unlock_timer
         from yt_app_default_config
         where app_type = #{appType}
     </select>
@@ -471,7 +474,7 @@
             taku_reward_pid, taku_interstitial_pid, can_use_root, can_use_adb, can_use_float, can_accumulation,
             ditch_id, power_wait_time, interstitial_interval_time,
             low_value_tip, brush_tip,flow_interval_time,task_limit_tip,start_wait_time,
-            can_cache_video,can_allow_auto_refresh,revenue_display_rate
+            can_cache_video,can_allow_auto_refresh,revenue_display_rate,unlock_timer
         from yt_app_default_config
         where app_id = #{appId}
     </select>
@@ -482,7 +485,7 @@
             taku_reward_pid, taku_interstitial_pid, can_use_root, can_use_adb, can_use_float, can_accumulation,
             ditch_id, power_wait_time, interstitial_interval_time,
             low_value_tip, brush_tip, flow_interval_time,task_limit_tip,start_wait_time,
-            can_cache_video,can_allow_auto_refresh,revenue_display_rate
+            can_cache_video,can_allow_auto_refresh,revenue_display_rate,unlock_timer
         from yt_app_default_config
         where app_id = #{appId}
     </select>
@@ -490,7 +493,7 @@
         select
             user_id,phone,device_id, head_img, nick_name, registry_time, last_login_time, last_login_ip, login_days,
             total_video, total_income, nearly_income, red_packet_balance, red_packet_amount, points_balance, points_total,
-            withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ditch_id, app_id, platform_id, power
+            withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ditch_id, app_id, platform_id, power,unlock_timer
         from yt_dyz_user
         where wx_open_id = #{openid}
     </select>
@@ -506,7 +509,8 @@
         answer_path, power_path,taku_app_id, taku_key, taku_banner_pid, taku_native_pid, taku_reward_pid,
         taku_interstitial_pid, can_use_root, can_use_adb, can_use_float, can_accumulation,can_simulator,
         ditch_id, power_wait_time, interstitial_interval_time, low_value_tip, brush_tip,
-        flow_interval_time,task_limit_tip,start_wait_time,can_cache_video,can_allow_auto_refresh,revenue_display_rate
+        flow_interval_time,task_limit_tip,start_wait_time,can_cache_video,can_allow_auto_refresh,
+        revenue_display_rate,unlock_timer
         from yt_app_default_config
         where app_id in
         <foreach collection="appIds.split(',')" item="item" separator="," open="(" close=")">
@@ -822,4 +826,10 @@
         total_income = COALESCE(total_income, 0) + #{revenue}
         WHERE user_id = #{userId};
     </update>
+    <update id="updateUserRedPacket">
+        UPDATE yt_dyz_user
+        SET red_packet_amount = COALESCE(red_packet_amount, 0) + #{revenue},
+            red_packet_balance = COALESCE(red_packet_balance, 0) + #{revenue}
+        WHERE user_id = #{userId}
+    </update>
 </mapper>

+ 12 - 3
yt-novel/yt-novel-service/src/main/resources/mapper/NovelAdRecordMapper.xml

@@ -2,14 +2,23 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ytpm.novel.dao.NovelAdRecordMapper">
     <insert id="insertNovelAdRecord">
-        insert into yt_novel_ad_record(record_id, user_id, ad_record_id, duration, record_time)
-        values (#{param.recordId}, #{param.userId}, #{param.adRecordId}, #{param.duration}, #{param.recordTime})
+        insert into yt_novel_ad_record(record_id, user_id, duration, record_time, revenue, revenue_rate)
+        values (#{param.recordId}, #{param.userId}, #{param.duration}, #{param.recordTime}, #{param.revenue}, #{param.revenueRate})
     </insert>
 
     <select id="selectToDayNovelRecode" resultType="com.ytpm.app.model.YtNovelAdRecord">
-        select record_id, user_id, ad_record_id, duration, record_time
+        select record_id, user_id, duration, record_time, revenue, revenue_rate
         from yt_novel_ad_record
         where user_id = #{userId}
         order by record_time desc
     </select>
+    <select id="getAnswerRevenue" resultType="java.math.BigDecimal">
+        select
+        sum(revenue * revenue_rate)
+        from yt_novel_ad_record
+        where user_id = #{userId} and revenue is not null and revenue_rate is not null
+        <if test="type != null and type == 1">
+            and DATE_FORMAT(record_time, '%Y-%m-%d') = current_date()
+        </if>
+    </select>
 </mapper>

+ 133 - 28
yt-novel/yt-novel-service/src/main/resources/mapper/NovelMapper.xml

@@ -43,39 +43,132 @@
         where user_id =#{userId} and deleted =0;
     </update>
 
-
-    <select id="selectNovelList" resultType="com.ytpm.novel.model.dto.YtNovelDto">
-        select n.novel_id, novel_name, novel_author, novel_introduction, novel_words, novel_reads, novel_img, novel_url,
-        book_id, status, state, deleted, create_by, create_time, update_by, update_time, revision
+    <select id="selectByPrimaryKey" resultType="com.ytpm.novel.model.dto.YtNovelDto">
+        select novel_id,
+               category_id,
+               novel_name,
+               novel_author,
+               novel_introduction,
+               novel_words,
+               novel_reads,
+               novel_img,
+               novel_url,
+               book_id,
+               status,
+               state,
+               create_by,
+               create_time,
+               update_by,
+               update_time,
+               revision
         from yt_novel n
+        where n.deleted = 0 and n.novel_id=#{novelId}
+    </select>
+    <select id="selectNovelPage" resultType="com.ytpm.novel.model.dto.YtNovelDto">
+        select n.novel_id,
+        n.category_id,
+        n.novel_name,
+        n.novel_author,
+        n.novel_introduction,
+        n.novel_words,
+        n.novel_reads,
+        n.novel_img,
+        n.novel_url,
+        n.book_id,
+        n.status,
+        n.state,
+        n.create_by,
+        n.create_time,
+        n.update_by,
+        n.update_time,
+        n.revision
+        from yt_novel n
+        left join yt_novel_category nc on nc.category_id = n.category_id
+        <if test="param.userId != null and param.userId != ''">
+        left join (
+            select record_id, user_id, novel_id, read_time
+            from yt_novel_read_record
+            where user_id = #{param.userId} and deleted = 0
+            order by read_time desc
+            limit 1
+        ) nrr on n.novel_id = nrr.novel_id
+        </if>
         where n.deleted = 0
         <if test="param.novelName != null and param.novelName != ''">
             and n.novel_name like CONCAT('%', #{param.novelName}, '%')
         </if>
+        <if test="param.categoryId != null and param.categoryId != ''">
+            and n.category_id = #{param.categoryId}
+        </if>
+        <if test="param.searchKeyword != null and param.searchKeyword != ''">
+            and (
+                n.novel_name like CONCAT('%', #{param.searchKeyword}, '%')
+                or n.novel_author like CONCAT('%', #{param.searchKeyword}, '%')
+                or nc.category_name like CONCAT('%', #{param.searchKeyword}, '%')
+            )
+        </if>
+        <if test="param.state != null">
+            and n.state = #{param.state}
+        </if>
+        <if test="param.userId != null and param.userId != ''">
+            ORDER BY nrr.read_time DESC
+        </if>
     </select>
-    <select id="selectByNovelId" resultType="com.ytpm.novel.model.dto.YtNovelDto">
-        select n.novel_id, novel_name, novel_author, novel_introduction, novel_words, novel_reads, novel_img, novel_url,
-               book_id, status, state, deleted, create_by, create_time, update_by, update_time, revision
+    <select id="selectByNovelIds" resultType="com.ytpm.novel.model.dto.YtNovelDto">
+        select novel_id,
+        category_id,
+        novel_name,
+        novel_author,
+        novel_introduction,
+        novel_words,
+        novel_reads,
+        novel_img,
+        novel_url,
+        book_id,
+        status,
+        state,
+        deleted,
+        create_by,
+        create_time,
+        update_by,
+        update_time,
+        revision
         from yt_novel n
-        where n.deleted = 0 and n.novel_id=#{novelId}
+        where n.deleted = 0
+        <foreach collection="novelIds" item="id" open="and n.novel_id in (" separator="," close=")">#{id}</foreach>
     </select>
     <select id="selectNovelChapter" resultType="com.ytpm.app.model.YtNovelChapter">
         select nc.chapter_id,
-               novel_id,
-               chapter,
-               chapter_name,
-               content,
-               content_text,
-               deleted,
-               revision,
-               create_by,
-               create_time,
-               update_by,
-               update_time
+               nc.novel_id,
+               nc.chapter,
+               nc.chapter_name,
+               nc.content,
+               nc.content_text,
+               nc.create_by,
+               nc.create_time,
+               nc.update_by,
+               nc.update_time
         from yt_novel_chapter nc
         where nc.deleted=0 and nc.novel_id=#{novelId}
         order by chapter
     </select>
+    <select id="selectNovelChapterByPrimaryKey" resultType="com.ytpm.app.model.YtNovelChapter">
+        select nc.chapter_id,
+               nc.novel_id,
+               nc.chapter,
+               nc.chapter_name,
+               nc.content,
+               nc.content_text,
+               nc.create_by,
+               nc.create_time,
+               nc.update_by,
+               nc.update_time
+        from yt_novel_chapter nc
+        where nc.deleted=0 and nc.chapter_id=#{chapterId}
+        order by chapter
+    </select>
+
+
     <select id="selectShelf" resultType="com.ytpm.app.model.YtNovelShelf">
         select yns.shelf_id,
                user_id,
@@ -107,19 +200,31 @@
         order by read_time desc
         limit 1
     </select>
-    <select id="selectByNovelIds" resultType="com.ytpm.app.model.YtNovel">
-        select n.novel_id, novel_name, novel_author, novel_introduction, novel_words, novel_reads, novel_img, novel_url,
-               book_id, status, state, deleted, create_by, create_time, update_by, update_time, revision
-        from yt_novel n
-        where n.deleted = 0
-        <foreach collection="novelIds" item="id" open="and n.novel_id in (" separator="," close=")">#{id}</foreach>
-
+    <select id="selectNovelChapterPage" resultType="com.ytpm.app.model.YtNovelChapter">
+        select chapter_id,
+               novel_id,
+               chapter,
+               chapter_name,
+               content,
+               content_text,
+               revision,
+               create_by,
+               create_time,
+               update_by,
+               update_time
+        from yt_novel_chapter
+        where novel_id = #{param.novelId} and deleted = 0
+        order by chapter
     </select>
-    <select id="selectCategoryList" resultType="com.ytpm.app.model.YtNovelCategory">
-        select category_id, category_name, category_desc, sort, create_by, create_time, update_by, update_time
+    <select id="selectCategoryList" resultType="com.ytpm.novel.model.dto.YtNovelCategoryDto">
+        select category_id,
+               category_name,
+               category_desc,
+               sort
         from yt_novel_category ync
         where ync.deleted=0
         order by ync.sort
     </select>
 
+
 </mapper>

+ 8 - 9
yt-question/yt-question-feign/src/main/java/com/ytpm/question/base/BaseFeign.java

@@ -7,7 +7,6 @@ import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
 import com.ytpm.app.model.YtAppDefaultConfig;
 import com.ytpm.app.model.YtDyzAdRecord;
-import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.model.YtUser;
 import com.ytpm.app.param.AppConfigUpdateParam;
 import com.ytpm.app.param.AppQueryUserTodayTimeParam;
@@ -45,19 +44,19 @@ public interface BaseFeign {
     int getDitchCount(@RequestParam("deviceId") String deviceId, @RequestParam("hours") Integer hours);
 
     @GetMapping("/user/getMonthRegistryUser")
-    List<YtDyzUser> getMonthRegistryUser(@RequestParam("appIds") String appIds, @RequestParam("type") Integer type);
+    List<YtUser> getMonthRegistryUser(@RequestParam("appIds") String appIds, @RequestParam("type") Integer type);
 
     @PostMapping("/user/queryAll")
     ResultTable<YtAppUserListView> queryAll(@RequestBody YtAppUserListParam param);
 
     @GetMapping("/user/getUserInfo")
-    Result<YtDyzUser> getUserInfo(@RequestParam("userId") String userId);
+    Result<YtUser> getUserInfo(@RequestParam("userId") String userId);
 
     @PostMapping("/user/getUserList")
-    ResultTable<YtDyzUser> getUserList(@RequestBody AppUserParam param);
+    ResultTable<YtUser> getUserList(@RequestBody AppUserParam param);
 
     @PostMapping("/user/getUserAll")
-    ResultTable<YtDyzUser> getUserAll(@RequestBody AppUserParam param);
+    ResultTable<YtUser> getUserAll(@RequestBody AppUserParam param);
 
     @PostMapping("/user/updateUserInfo")
     Result<?> updateUserInfo(@RequestBody YtUser dyzUser);
@@ -75,7 +74,7 @@ public interface BaseFeign {
                                           @RequestParam(name = "startTime", required = false) String startTime);
 
     @PostMapping("/user/queryUserByTime")
-    List<YtDyzUser> queryUserByTime(@RequestBody AppUserQueryParam appUserQueryParam);
+    List<YtUser> queryUserByTime(@RequestBody AppUserQueryParam appUserQueryParam);
 
     @PostMapping("/user/queryUserByTodayTime")
     int[] queryUserByTodayTime(@RequestBody AppQueryUserTodayTimeParam appQueryUserTodayTimeParam);
@@ -84,7 +83,7 @@ public interface BaseFeign {
     List<String> queryLoginRecords(@RequestBody AppUserQueryParam appUserQueryParam);
 
     @GetMapping("/user/queryByOpenid")
-    List<YtDyzUser> queryByOpenid(@RequestParam("openid") String openid);
+    List<YtUser> queryByOpenid(@RequestParam("openid") String openid);
 
     @PostMapping("/wx/saveAppConfig")
     Result<String> saveAppConfig(@RequestBody YtAppDefaultConfig defaultConfig);
@@ -99,7 +98,7 @@ public interface BaseFeign {
     List<WxDefaultConfig> getConfigs(@RequestParam(name = "appIds") String appIds);
 
     @PostMapping("/user/queryTodayBanned")
-    List<YtDyzUser> queryTodayBanned(@RequestBody AppUserTodayBannedParam appUserTodayBannedParam);
+    List<YtUser> queryTodayBanned(@RequestBody AppUserTodayBannedParam appUserTodayBannedParam);
 
     @GetMapping("/ad/getAdCount")
     Map<String, BigDecimal> getAdCount(@RequestParam(name = "appIds") String appIds);
@@ -132,7 +131,7 @@ public interface BaseFeign {
      * 锁定用户
      */
     @GetMapping("/user/lockUser")
-    YtDyzUser lockUser(@RequestParam(name = "userId") String userId, @RequestParam("userStatus") Integer userStatus);
+    YtUser lockUser(@RequestParam(name = "userId") String userId, @RequestParam("userStatus") Integer userStatus);
 
     /**
      * 批量审核用户

+ 7 - 1
yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/UserController.java

@@ -54,6 +54,7 @@ import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayOutputStream;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -182,6 +183,12 @@ public class UserController {
                 ifPowerLimit = "766".equals(result.getMessage())
                         || result.getCode() == StatusCode.ACCESS_RISK_ERROR && StrUtil.isNotEmpty(result.getMessage());
             }
+            // 获取今日红包收益
+            BigDecimal todayRedPacketBalance = questionMapper.getAnswerRevenue(userId, 1);
+            if (todayRedPacketBalance != null) {
+                todayRedPacketBalance = todayRedPacketBalance.setScale(5, RoundingMode.HALF_UP);
+            }
+            user.setTodayRedPacketBalance(todayRedPacketBalance);
             user.setIfPowerLimit(ifPowerLimit);
         }
         return Result.resultObjOk(user);
@@ -437,6 +444,5 @@ public class UserController {
                 }
             }
         }
-
     }
 }

+ 4 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/dao/AppUserMapper.java

@@ -214,4 +214,8 @@ public interface AppUserMapper {
 
     void updateTotal(@Param("userId") String userId, @Param("videoCount") int videoCount, @Param("revenue") BigDecimal revenue);
 
+    /**
+     * 更新红包余额
+     */
+    void updateUserRedPacket(@Param("userId") String userId, @Param("revenue") BigDecimal redPackRevenue);
 }

+ 7 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/dao/QuestionMapper.java

@@ -5,6 +5,7 @@ import com.ytpm.app.view.QuestionListView;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 @Mapper
@@ -31,6 +32,12 @@ public interface QuestionMapper {
      */
     Integer getAnswerCount(@Param("userId")String userId, @Param("type") int type);
 
+    /**
+     * 获取答题收益
+     * @param type 1-今日 2-历史
+     */
+    BigDecimal getAnswerRevenue(@Param("userId")String userId, @Param("type") int type);
+
     /**
      * 查询答题历史记录
      */

+ 7 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/service/AppUserService.java

@@ -5,6 +5,8 @@ import com.ytpm.app.param.WxLoginParam;
 import com.ytpm.app.view.WxLoginResult;
 import com.ytpm.app.view.WxUserInfo;
 
+import java.math.BigDecimal;
+
 public interface AppUserService {
     /**
      * openid查询用户信息
@@ -15,4 +17,9 @@ public interface AppUserService {
      * 子事务处理用户crud
      */
     YtDyzUser crudForNewTrans(WxLoginParam param, WxUserInfo wxUserInfo, WxLoginResult loginResult);
+
+    /**
+     * 获取配置项 用户红包收益换算比例
+     */
+    BigDecimal getUserRevenueRate(String appId);
 }

+ 13 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/service/impl/AppUserServiceImpl.java

@@ -8,6 +8,7 @@ import com.ytpm.agent.enums.UserStatusEnum;
 import com.ytpm.app.model.YtDyzLoginRecord;
 import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.param.WxLoginParam;
+import com.ytpm.app.view.WxDefaultConfig;
 import com.ytpm.app.view.WxLoginResult;
 import com.ytpm.app.view.WxUserInfo;
 import com.ytpm.constant.StrConstant;
@@ -17,6 +18,7 @@ import com.ytpm.question.dao.LoginRecordMapper;
 import com.ytpm.question.dao.QuestionMapper;
 import com.ytpm.question.redis.RedisService;
 import com.ytpm.question.service.AppUserService;
+import com.ytpm.util.NumberUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
@@ -84,6 +86,17 @@ public class AppUserServiceImpl implements AppUserService {
         return old;
     }
 
+    @Override
+    public BigDecimal getUserRevenueRate(String appId) {
+        WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByAppId(appId);
+        String revenueDisplayRate = defaultConfig == null ? "" : defaultConfig.getRevenueDisplayRate();
+        BigDecimal revenueRate = null;
+        if (StrUtil.isNotEmpty(revenueDisplayRate)) {
+            revenueRate = NumberUtils.rateToBigDecimal(revenueDisplayRate);
+        }
+        return revenueRate;
+    }
+
     /**
      * 设置扩展信息
      */

+ 19 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/service/impl/QuestionServiceImpl.java

@@ -15,11 +15,14 @@ import com.ytpm.general.ResultTable;
 import com.ytpm.general.StatusCode;
 import com.ytpm.question.dao.AppUserMapper;
 import com.ytpm.question.dao.QuestionMapper;
+import com.ytpm.question.service.AppUserService;
 import com.ytpm.question.service.QuestionService;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.Date;
 import java.util.Objects;
 
@@ -30,6 +33,8 @@ public class QuestionServiceImpl implements QuestionService {
     private QuestionMapper questionMapper;
     @Resource
     private AppUserMapper appUserMapper;
+    @Resource
+    private AppUserService appUserService;
 
     /**
      * 获取题库
@@ -52,11 +57,21 @@ public class QuestionServiceImpl implements QuestionService {
         if (!UserStatusEnum.NORMAL.getCode().equals(user.getUserStatus())) {
             return new Result<>(StatusCode.ACCESS_ERR, "当前用户处于风控中");
         }
+        // 计算本次红包收益
         YtDyzAnswerRecord record = new YtDyzAnswerRecord();
         BeanUtil.copyProperties(param, record);
         record.setRecordId(IdUtil.fastSimpleUUID());
         record.setAnswerTime(new Date());
+        BigDecimal redPackRevenue = BigDecimal.ZERO;
+        BigDecimal userRevenueRate = appUserService.getUserRevenueRate(user.getAppId());
+        if (userRevenueRate != null) {
+            record.setRevenueRate(userRevenueRate.toPlainString());
+            if(record.getRevenue() != null && record.getRevenue().compareTo(BigDecimal.ZERO) > 0){
+                redPackRevenue = record.getRevenue().multiply(userRevenueRate).setScale(5, RoundingMode.HALF_UP);
+            }
+        }
         questionMapper.saveAnswerRecord(record);
+        // 扣减体力 记录体积消耗记录
         appUserMapper.subOnePower(param.getUserId());
         YtDyzPowerRecord powerRecord = new YtDyzPowerRecord();
         powerRecord.setUserId(param.getUserId());
@@ -65,6 +80,10 @@ public class QuestionServiceImpl implements QuestionService {
         powerRecord.setType(1);
         powerRecord.setRemark("减少体力");
         appUserMapper.addPowerRecord(powerRecord);
+        // 更新用户红包余额
+        if (redPackRevenue.compareTo(BigDecimal.ZERO) > 0) {
+            appUserMapper.updateUserRedPacket(user.getUserId(), redPackRevenue);
+        }
         return Result.resultOk(RepMessage.SAVE_SUCCESS);
     }
 }

+ 6 - 0
yt-question/yt-question-service/src/main/resources/mapper/AppUserMapper.xml

@@ -797,4 +797,10 @@
         total_income = COALESCE(total_income, 0) + #{revenue}
         WHERE user_id = #{userId};
     </update>
+    <update id="updateUserRedPacket">
+        UPDATE yt_dyz_user
+        SET red_packet_amount =  COALESCE(red_packet_amount, 0) + #{revenue},
+            red_packet_balance =  COALESCE(red_packet_balance, 0) + #{revenue}
+        WHERE user_id = #{userId}
+    </update>
 </mapper>

+ 15 - 3
yt-question/yt-question-service/src/main/resources/mapper/QuestionMapper.xml

@@ -15,8 +15,8 @@
         </collection>
     </resultMap>
     <insert id="saveAnswerRecord">
-        insert into yt_dyz_answer_record (record_id, question_id, item_id, duration, answer_time, user_id)
-        values (#{recordId}, #{questionId}, #{itemId}, #{duration}, #{answerTime}, #{userId});
+        insert into yt_dyz_answer_record (record_id, question_id, item_id, duration, answer_time, user_id, revenue, revenue_rate)
+        values (#{recordId},#{questionId},#{itemId},#{duration},#{answerTime},#{userId}, #{revenue}, #{revenueRate});
     </insert>
     <select id="questionList" resultMap="questionListMap">
         SELECT ydq.question_id,
@@ -48,15 +48,27 @@
             and DATE_FORMAT(answer_time, '%Y-%m-%d') = current_date()
         </if>
     </select>
+    <select id="getAnswerRevenue" resultType="java.math.BigDecimal">
+        select
+        sum(revenue * revenue_rate)
+        from yt_dyz_answer_record
+        where user_id = #{userId} and revenue is not null and revenue_rate is not null
+        <if test="type != null and type == 1">
+            and DATE_FORMAT(answer_time, '%Y-%m-%d') = current_date()
+        </if>
+    </select>
     <select id="getAnswerRecords" resultType="com.ytpm.app.model.YtDyzAnswerRecord">
         select record_id,
                question_id,
                item_id,
                duration,
                answer_time,
-               user_id
+               user_id,
+               revenue,
+               revenue_rate
         from yt_dyz_answer_record
         where user_id = #{userId}
         order by answer_time desc
     </select>
+
 </mapper>

+ 5 - 5
yt-risk/risk-manage/src/main/java/com/ytpm/service/impl/RiskServiceImpl.java

@@ -426,8 +426,7 @@ public class RiskServiceImpl implements RiskService {
         } else {
             o = feignInvoker.invoke(userApp.getServiceName(),"queryByOpenid",dyzUser.getWxOpenId());
         }
-        List<YtDyzUser> dyzUsers = JSONArray.parseArray(JSON.toJSONString(o), YtDyzUser.class);
-
+        List<YtUser> ytUsers = JSONArray.parseArray(JSON.toJSONString(o), YtUser.class);
         List<RiskConfigView> configList = view.getConfigList();
         Map<String, String> configMap = configList.stream().collect(
                 Collectors.toMap(RiskConfigView::getFieldName, RiskConfigView::getConfigVal));
@@ -435,9 +434,10 @@ public class RiskServiceImpl implements RiskService {
         int uidCount = Integer.parseInt(configMap.get("uidCount"));
         int days = Integer.parseInt(configMap.get("days"));
         //过滤该用户注册时间在三天内的渠道数
-        long ditchCount = dyzUsers.stream().filter(
-                s->(days>DateUtil.between(new Date(), s.getRegistryTime(),DateUnit.DAY))
-        ).count();
+        Date currentDate = new Date();
+        long ditchCount = ytUsers.stream()
+                .filter(user -> (days > DateUtil.between(currentDate, user.getRegistryTime(), DateUnit.DAY)))
+                .count();
         //三天内注册的渠道数小于预设的渠道数通过校验,否则风控锁定用户
         if(ditchCount<uidCount)return;
         riskLockUser(dyzUser,"322","系统判定重复刷单用户限制",getTipsMsg());