marxjaw 2 місяців тому
батько
коміт
79738e332f

+ 180 - 0
yt-adage/adage-service/src/main/java/com/ytpm/adage/controller/VisitorController.java

@@ -0,0 +1,180 @@
+package com.ytpm.adage.controller;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import com.ytpm.adage.dao.AppUserMapper;
+import com.ytpm.adage.dao.LoginRecordMapper;
+import com.ytpm.adage.dao.QuestionMapper;
+import com.ytpm.adage.redis.RedisService;
+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.WxUserInfo;
+import com.ytpm.constant.StrConstant;
+import com.ytpm.feign.RiskFeign;
+import com.ytpm.general.Result;
+import com.ytpm.general.StatusCode;
+import com.ytpm.handle.CustomerException;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * @author Marx
+ * @date 2025/9/2 15:02
+ */
+@Api(tags = "游客管理")
+@RefreshScope
+@RestController
+@RequestMapping("/visitor")
+public class VisitorController {
+
+    @Autowired
+    private AppUserMapper appUserMapper;
+    @Autowired
+    private LoginRecordMapper loginRecordMapper;
+    @Autowired
+    private QuestionMapper questionMapper;
+    @Autowired
+    private RiskFeign riskFeign;
+    @Autowired
+    private RedisService redisService;
+    @Value("${risk.config.banned.tips}")
+    private String tips;
+
+    @PostMapping("/login")
+    @ApiOperation("游客登录")
+    @Transactional(rollbackFor = Exception.class)
+    public Result<YtDyzUser> visitorLogin(@RequestBody WxLoginParam param, HttpServletRequest request) {
+        param.setLoginIp(getClientIp(request));
+        YtDyzUser old = appUserMapper.getByDeviceAndDitch(param.getDeviceId(),param.getDitchId());
+        //当前设备在该渠道未曾注册
+        if(Objects.isNull(old)){
+            old = new YtDyzUser();
+            registerUser(param, old);
+        }else{
+            //当前设备已注册该渠道
+            if(!old.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())){
+                return new Result<>(StatusCode.ACCESS_ERR,getTipsMsg());
+            }
+            deadWithUserCrud(old,param);
+        }
+        //设置最后一次答题问题ID、今日答题数、历史答题数
+        setExtInfo(old);
+        // 添加用户登录记录
+        addLoginRecord(param,old.getUserId());
+        //校验游客风控
+        Result<?> result = riskFeign.checkLoginRisk(old);
+        if(result.getCode()!=200){
+            return new Result<>(StatusCode.ACCESS_ERR,result.getMessage());
+        }
+        return Result.resultObjOk(old);
+    }
+
+    /**
+     * 注册用户
+     */
+    private YtDyzUser registerUser(WxLoginParam param, YtDyzUser old) {
+        old.setUserId(redisService.getAppUserId());
+        old.setPhone(param.getPhone());
+        old.setDeviceId(param.getDeviceId());
+        old.setNickName("visitor_"+RandomUtil.randomString(10));
+        old.setLastLoginTime(new Date());
+        old.setRegistryTime(new Date());
+        old.setLastLoginIp(param.getLoginIp());
+        old.setLoginDays(1);
+        old.setPower(0);
+        old.setTotalVideo(0);
+        old.setTotalIncome(BigDecimal.ZERO);
+        old.setRedPacketAmount(BigDecimal.ZERO);
+        old.setRedPacketBalance(BigDecimal.ZERO);
+        old.setPointsBalance(BigDecimal.ZERO);
+        old.setPointsTotal(BigDecimal.ZERO);
+        old.setWithdrawTotal(BigDecimal.ZERO);
+        old.setDitchId(param.getDitchId());
+        old.setSignDays(0);
+        old.setAppId(param.getAppId());
+        old.setUserStatus(UserStatusEnum.NORMAL.getCode());
+        appUserMapper.addOne(old);
+        return old;
+    }
+
+    private String getClientIp(HttpServletRequest request) {
+        String xfHeader = request.getHeader("X-Forwarded-For");
+        if (xfHeader == null) {
+            return request.getRemoteAddr();
+        }
+        return xfHeader.split(",")[0]; // 可能会有多个IP,这里取第一个逗号前的IP
+    }
+
+    /**
+     * 获取随机提示
+     */
+    private String getTipsMsg(){
+        String[] split = tips.split(",");
+        return split[RandomUtil.randomInt(split.length)];
+    }
+
+    /**
+     * 设置扩展信息
+     */
+    private void setExtInfo(YtDyzUser old) {
+        old.setLastQuestionId(questionMapper.getLastQuestionId(old.getUserId()));
+        old.setTodayAnswerCount(questionMapper.getAnswerCount(old.getUserId(),1));
+        old.setHistoryAnswerCount(questionMapper.getAnswerCount(old.getUserId(),2));
+        old.setAnswerRecordList(questionMapper.getAnswerRecords(old.getUserId()));
+        old.setLoginRecordList(loginRecordMapper.getLoginRecords(old.getUserId()));
+    }
+    /**
+     * 处理用户数据
+     */
+    private void deadWithUserCrud(YtDyzUser old, WxLoginParam param) {
+        //处于风控状态的用户不允许登录
+        if(!old.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())){
+            throw new CustomerException(getTipsMsg());
+        }
+        YtDyzUser newUser = new YtDyzUser();
+        newUser.setUserId(old.getUserId());
+        newUser.setLastLoginTime(new Date());
+        newUser.setLastLoginIp(param.getLoginIp());
+        newUser.setPhone(param.getPhone());
+        newUser.setDeviceId(param.getDeviceId());
+        //如果当前登录是本日第一次登录则登录天数+1
+        int loginCount = loginRecordMapper.getTodayLoginCount(old.getUserId());
+        if(loginCount < 1){
+            newUser.setLoginDays(old.getLoginDays()+1);
+        }
+        appUserMapper.updateUser(newUser);
+    }
+
+    /**
+     * 增加用户登录记录
+     */
+    private void addLoginRecord(WxLoginParam param,String userId) {
+        YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
+        loginRecord.setRecordId(IdUtil.fastSimpleUUID());
+        loginRecord.setUserId(userId);
+        loginRecord.setLoginTime(new Date());
+        loginRecord.setDeviceBrand(param.getBrand());
+        loginRecord.setDeviceModel(param.getModel());
+        loginRecord.setLoginIp(param.getLoginIp());
+        loginRecord.setOperator(param.getIpOperator());
+        loginRecord.setIpAddr(param.getIpLocation());
+        loginRecord.setPhoneJson(param.getPhoneJson());
+        loginRecordMapper.insertOne(loginRecord);
+    }
+}

+ 10 - 0
yt-adage/adage-service/src/main/java/com/ytpm/adage/dao/AppUserMapper.java

@@ -183,4 +183,14 @@ public interface AppUserMapper {
     List<AgentAuditCheckVO> queryTodayUserAd(AuditUserParam auditParam);
 
     List<YtDyzUser> getMonthRegistryUser(@Param("appIds") String appIds, @Param("type") Integer type);
+
+    /**
+     * 根据设备ID 和 渠道ID 查询用户信息
+     */
+    YtDyzUser getByDeviceAndDitch(@Param("deviceId") String deviceId,@Param("ditchId")Long ditchId);
+
+    /**
+     * 查询设备指定天数内注册的渠道数
+     */
+    int countDitch(@Param("deviceId")String deviceId,@Param("days")int days);
 }

+ 2 - 0
yt-adage/adage-service/src/main/java/com/ytpm/adage/dao/LoginRecordMapper.java

@@ -22,4 +22,6 @@ public interface LoginRecordMapper {
     List<YtDyzLoginRecord> getLoginRecordByIds(@Param("userIds")String userIds);
 
     List<String> queryLoginCount(AppUserQueryParam appUserQueryParam);
+
+    int getTodayLoginCount(@Param("userId") String userId);
 }

+ 14 - 0
yt-adage/adage-service/src/main/resources/mapper/AppUserMapper.xml

@@ -635,6 +635,20 @@
             and DATE_FORMAT(last_login_time, '%Y-%m') = DATE_FORMAT(now(),'%Y-%m')
         </if>
     </select>
+    <select id="getByDeviceAndDitch" resultType="com.ytpm.app.model.YtDyzUser">
+        select
+            user_id, head_img, nick_name, registry_time, last_login_time, last_login_ip, login_days, total_video, total_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, phone, device_id, phone_json
+        from yt_dyz_user
+        where device_id = #{deviceId} and ditch_id = #{ditchId}
+    </select>
+    <select id="countDitch" resultType="java.lang.Integer">
+        select
+            count( distinct ditch_id)
+        from yt_dyz_user
+        where device_id = #{deviceId}
+        and registry_time > DATE_SUB(CURRENT_DATE(), INTERVAL #{days} DAY)
+        and registry_time <![CDATA[<=]]> CURRENT_DATE()
+    </select>
     <update id="unlockUser">
         update yt_dyz_user
         set user_status = 1

+ 6 - 0
yt-adage/adage-service/src/main/resources/mapper/LoginRecordMapper.xml

@@ -70,6 +70,12 @@
             #{item}
         </foreach>
     </select>
+    <select id="getTodayLoginCount" resultType="java.lang.Integer">
+        select
+            count(*)
+        from yt_dyz_login_record
+        where user_id = #{userId} and DATE(login_time) = current_date()
+    </select>
 
 
 </mapper>

+ 2 - 0
yt-agent/agent-service/src/main/resources/bootstrap.yml

@@ -48,6 +48,8 @@ spring:
 ---
 spring:
   profiles: prod
+  main:
+    allow-bean-definition-overriding: true
   application:
     name: agent-service
   cloud:

+ 2 - 0
yt-risk/risk-feign/src/main/java/com/ytpm/feign/RiskFeign.java

@@ -17,4 +17,6 @@ public interface RiskFeign {
     Result<?> checkAdRisk(@RequestBody YtDyzUser ytDyzUser);
     @GetMapping("/public/addDeblockingRecord")
     void addBlockingRecord(@RequestParam("userId")String userId);
+    @PostMapping("/public/checkLoginRisk")
+    Result<?> checkLoginRisk(@RequestBody YtDyzUser ytDyzUser);
 }

+ 14 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/controller/PublicApiController.java

@@ -48,6 +48,14 @@ public class PublicApiController {
     public Result<RiskTemplateView> getRiskByCode(@RequestParam("code")String code){
         return riskService.getRiskByCode(code);
     }
+    /**
+     * 根据应用获取风控配置
+     */
+    @ApiOperation("根据应用ID获取风控配置")
+    @GetMapping("/getRiskTemplate")
+    public List<RiskTemplateView> getRiskTemplate(@RequestParam("appId")String appId){
+        return riskService.getRiskTemplate(appId);
+    }
 
     /**
      * 校验广告的默认风控配置
@@ -72,4 +80,10 @@ public class PublicApiController {
     public void addDeblockingRecord(@RequestParam(name = "userId")String userId){
         riskService.addDeblockingRecord(userId);
     }
+
+    @ApiOperation("校验登录风控配置")
+    @PostMapping("/checkLoginRisk")
+    public Result<?> checkLoginRisk(@RequestBody YtDyzUser dyzUser){
+        return riskService.checkLoginRisk(dyzUser);
+    }
 }

+ 5 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/dao/RiskConfigMapper.java

@@ -86,4 +86,9 @@ public interface RiskConfigMapper {
      * @param effectNode 业务节点
      */
     List<RiskTemplateView> getCustomTempConfig(@Param("appId") String appId,@Param("effectNode")Integer effectNode);
+
+    /**
+     * 根据应用获取风控配置
+     */
+    List<RiskTemplateView> getTemplateByAppId(@Param("appId") String appId);
 }

+ 7 - 0
yt-risk/risk-manage/src/main/java/com/ytpm/service/RiskService.java

@@ -114,4 +114,11 @@ public interface RiskService {
      * 增加解禁记录
      */
     void addDeblockingRecord(String userId);
+
+    /**
+     * 根据应用获取风控配置
+     */
+    List<RiskTemplateView> getRiskTemplate(String appId);
+
+    Result<?> checkLoginRisk(YtDyzUser dyzUser);
 }

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

@@ -89,7 +89,7 @@ import java.util.stream.Collectors;
 @Slf4j(topic = "风控服务")
 @Service
 @RefreshScope
-public class RiskServiceImpl extends ReflectUtil implements RiskService {
+public class RiskServiceImpl implements RiskService {
 
     @Autowired
     private FeignClientInvoker feignInvoker;
@@ -840,4 +840,21 @@ public class RiskServiceImpl extends ReflectUtil implements RiskService {
         deblocking.setDeblockingReason("到期解封");
         riskManageMapper.addDeblockingRecord(deblocking);
     }
+
+    /**
+     * 根据应用查询风控配置模版
+     */
+    @Override
+    public List<RiskTemplateView> getRiskTemplate(String appId) {
+        return configMapper.getTemplateByAppId(appId);
+    }
+
+    /**
+     * 校验登录风控规则
+     */
+    @Override
+    public Result<?> checkLoginRisk(YtDyzUser dyzUser) {
+
+        return null;
+    }
 }

+ 21 - 0
yt-risk/risk-manage/src/main/resources/mapper/RiskConfigMapper.xml

@@ -291,4 +291,25 @@
             and rt.app_id = #{appId}
             and rt.effect_node = #{effectNode}
     </select>
+    <select id="getTemplateByAppId" resultMap="RiskTemplateViewMap">
+        SELECT
+            rt.template_id,
+            rt.template_code,
+            rt.template_name,
+            rt.template_content,
+            rt.effect_node,
+            rt.enabled,
+            rc.config_id,
+            rc.field_name,
+            rc.field_desc,
+            rc.config_type,
+            rc.config_val,
+            rc.multy
+        FROM
+            yt_risk_template rt
+                LEFT JOIN yt_risk_template_config rtc ON rt.template_id = rtc.template_id
+                LEFT JOIN yt_risk_config rc ON rtc.config_id = rc.config_id
+        WHERE
+            rt.app_id = #{appId}
+    </select>
 </mapper>