소스 검색

风控体系代码提交

zjy 1 개월 전
부모
커밋
252933ae00
16개의 변경된 파일697개의 추가작업 그리고 4개의 파일을 삭제
  1. 50 0
      alien-entity/src/main/java/shop/alien/entity/second/LifeUserLog.java
  2. 54 0
      alien-entity/src/main/java/shop/alien/entity/second/SecondUserCredit.java
  3. 56 0
      alien-entity/src/main/java/shop/alien/entity/second/SecondUserCreditRecord.java
  4. 12 0
      alien-entity/src/main/java/shop/alien/mapper/second/SecondUserCreditMapper.java
  5. 12 0
      alien-entity/src/main/java/shop/alien/mapper/second/SecondUserCreditRecordMapper.java
  6. 4 3
      alien-gateway/src/main/java/shop/alien/gateway/controller/LifeUserController.java
  7. 11 0
      alien-gateway/src/main/java/shop/alien/gateway/feign/SecondServiceFeign.java
  8. 27 0
      alien-gateway/src/main/java/shop/alien/gateway/mapper/LifeUserLogMapper.java
  9. 51 1
      alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserService.java
  10. 81 0
      alien-second/src/main/java/shop/alien/second/controller/SecondUserPointsController.java
  11. 60 0
      alien-second/src/main/java/shop/alien/second/controller/SecondUserPointsRecordController.java
  12. 39 0
      alien-second/src/main/java/shop/alien/second/platform/PlatformSecondUserFreezeController.java
  13. 24 0
      alien-second/src/main/java/shop/alien/second/service/SecondUserCreditRecordService.java
  14. 33 0
      alien-second/src/main/java/shop/alien/second/service/SecondUserCreditService.java
  15. 59 0
      alien-second/src/main/java/shop/alien/second/service/impl/SecondUserCreditRecordServiceImpl.java
  16. 124 0
      alien-second/src/main/java/shop/alien/second/service/impl/SecondUserCreditServiceImpl.java

+ 50 - 0
alien-entity/src/main/java/shop/alien/entity/second/LifeUserLog.java

@@ -0,0 +1,50 @@
+package shop.alien.entity.second;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户
+ */
+@Data
+@JsonInclude
+@TableName("life_user_log")
+public class LifeUserLog implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("user_id")
+    private Integer userId;
+
+    @TableField("user_name")
+    private String userName;
+
+    @TableField("mac_ip")
+    private String macIp;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}

+ 54 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondUserCredit.java

@@ -0,0 +1,54 @@
+package shop.alien.entity.second;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户
+ */
+@Data
+@JsonInclude
+@TableName("second_user_credit")
+public class SecondUserCredit implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("user_id")
+    private Integer userId;
+
+    @TableField("user_points")
+    private Integer userPoints;
+
+    @TableField("delete_flag")
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "冻结时间")
+    @TableField("freeze_time")
+    private Date freezeTime;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}

+ 56 - 0
alien-entity/src/main/java/shop/alien/entity/second/SecondUserCreditRecord.java

@@ -0,0 +1,56 @@
+package shop.alien.entity.second;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 用户
+ */
+@Data
+@JsonInclude
+@TableName("second_user_credit_record")
+public class SecondUserCreditRecord implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("user_id")
+    private Integer userId;
+
+    @TableField("points")
+    private Integer points;
+
+    @TableField("points_type")
+    private Integer pointsType;
+
+    @TableField("user_points")
+    private Integer userPoints;
+
+    @TableField("delete_flag")
+    private Integer deleteFlag;
+
+    @ApiModelProperty(value = "创建时间")
+    @TableField(value = "created_time", fill = FieldFill.INSERT)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createdTime;
+
+    @ApiModelProperty(value = "创建人ID")
+    @TableField("created_user_id")
+    private Integer createdUserId;
+
+    @ApiModelProperty(value = "修改时间")
+    @TableField(value = "updated_time", fill = FieldFill.UPDATE)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updatedTime;
+
+    @ApiModelProperty(value = "修改人ID")
+    @TableField("updated_user_id")
+    private Integer updatedUserId;
+}

+ 12 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondUserCreditMapper.java

@@ -0,0 +1,12 @@
+package shop.alien.mapper.second;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.second.SecondUserCredit;
+
+
+/**
+ * 二手商品映射器
+ */
+public interface SecondUserCreditMapper extends BaseMapper<SecondUserCredit> {
+
+}

+ 12 - 0
alien-entity/src/main/java/shop/alien/mapper/second/SecondUserCreditRecordMapper.java

@@ -0,0 +1,12 @@
+package shop.alien.mapper.second;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import shop.alien.entity.second.SecondUserCreditRecord;
+
+
+/**
+ * 二手商品映射器
+ */
+public interface SecondUserCreditRecordMapper extends BaseMapper<SecondUserCreditRecord> {
+
+}

+ 4 - 3
alien-gateway/src/main/java/shop/alien/gateway/controller/LifeUserController.java

@@ -25,9 +25,10 @@ public class LifeUserController {
     @ApiOperationSupport(order = 1)
     @ApiImplicitParams({@ApiImplicitParam(name = "phoneNum", value = "手机号", dataType = "String", paramType = "query", required = true)})
     @GetMapping("/userLogin")
-    public R<LifeUserVo> userLogin(@RequestParam("phoneNum") String phoneNum) {
-        log.info("LifeUserController.userLogin?phoneNum={}", phoneNum);
-        LifeUserVo userVo = service.userLogin(phoneNum);
+    public R<LifeUserVo> userLogin(@RequestParam("phoneNum") String phoneNum,
+                                    @RequestParam(value = "macIp",required = false) String macIp) {
+        log.info("LifeUserController.userLogin?phoneNum={},macIp={}", phoneNum, macIp);
+        LifeUserVo userVo = service.userLogin(phoneNum, macIp);
         if (null == userVo) {
             return R.fail("登录失败");
         }

+ 11 - 0
alien-gateway/src/main/java/shop/alien/gateway/feign/SecondServiceFeign.java

@@ -22,4 +22,15 @@ public interface SecondServiceFeign {
                                @RequestParam("ruleName") String ruleName,
                                @RequestParam("businessId") String businessId,
                                @RequestParam("detailInfo") String detailInfo);
+
+    /**
+     * 用户积分数据
+     *
+     * @param userId     用户ID
+     * @param initialPoints   用户积分
+     */
+    @PostMapping("/userPoints/create")
+    void createPointsRecord(@RequestParam("userId") Integer userId,
+                            @RequestParam("initialPoints") Integer initialPoints,
+                            @RequestParam("pointsType") Integer pointsType);
 }

+ 27 - 0
alien-gateway/src/main/java/shop/alien/gateway/mapper/LifeUserLogMapper.java

@@ -0,0 +1,27 @@
+package shop.alien.gateway.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import shop.alien.entity.second.LifeUserLog;
+
+import java.util.List;
+
+@Mapper
+public interface LifeUserLogMapper extends BaseMapper<LifeUserLog> {
+
+    /**
+     * 查询时间段内同一个macip地址的登录记录
+     *
+     * @param starDate 开始日期
+     * @param endDate 结束日期
+     * @return 同一个macip地址的登录记录
+     */
+    @Select("SELECT user_id, user_name, mac_ip FROM life_user_log " +
+            " WHERE created_time BETWEEN DATE_FORMAT(#{starDate}, '%Y-%m-%d %H:%i:%s') " +
+            " AND DATE_FORMAT(#{endDate}, '%Y-%m-%d %H:%i:%s') AND mac_ip = #{macIp} " +
+            " GROUP BY user_id, user_name, mac_ip ")
+    List<LifeUserLog> getLifeUserLogByDate(@Param("starDate") String starDate, @Param("endDate") String endDate, @Param("macIp") String macIp);
+
+}

+ 51 - 1
alien-gateway/src/main/java/shop/alien/gateway/service/LifeUserService.java

@@ -7,15 +7,22 @@ import lombok.RequiredArgsConstructor;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import shop.alien.entity.second.LifeUserLog;
 import shop.alien.entity.store.LifeUser;
 import shop.alien.entity.store.vo.LifeUserVo;
 import shop.alien.gateway.config.BaseRedisService;
+import shop.alien.gateway.feign.SecondServiceFeign;
+import shop.alien.gateway.mapper.LifeUserLogMapper;
 import shop.alien.gateway.mapper.LifeUserMapper;
 import shop.alien.util.common.JwtUtil;
 
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 用户
@@ -26,12 +33,19 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
 
     private final LifeUserMapper lifeUserMapper;
 
+    private final LifeUserLogMapper lifeUserLogMapper;
+
     private final BaseRedisService baseRedisService;
 
+    private final SecondServiceFeign secondServiceFeign;
+
+    @Value("${risk-control.account-abnormal.reg-count24h:4}")
+    private Integer regCount24h;
+
     @Value("${jwt.expiration-time}")
     private String effectiveTime;
 
-    public LifeUserVo userLogin(String phoneNum) {
+    public LifeUserVo userLogin(String phoneNum, String macIp) {
         int effectiveTimeInt = Integer.parseInt(effectiveTime.substring(0, effectiveTime.length() - 1));
         String effectiveTimeUnit = effectiveTime.substring(effectiveTime.length() - 1);
         long effectiveTimeIntLong = 0L;
@@ -74,6 +88,8 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
                 userVo.setToken(JwtUtil.createJWT("user_" + phoneNum, lifeUser.getUserName(), JSONObject.toJSONString(tokenMap), effectiveTimeIntLong));
 //                userVo.setToken(JWTUtils.createToken(tokenMap));
                 baseRedisService.setString("user_" + phoneNum, userVo.getToken());
+                // 二手平台登录log,同一个macip登录多账号记录
+                addLifeUserLogInfo(user2, macIp);
                 return userVo;
             } else {
                 return null;
@@ -90,6 +106,8 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
             String token = JwtUtil.createJWT("user_" + phoneNum, user.getUserName(), JSONObject.toJSONString(tokenMap), effectiveTimeIntLong);
             userVo.setToken(token);
             baseRedisService.setString("user_" + phoneNum, token);
+            // 二手平台登录log,同一个macip登录多账号记录
+            addLifeUserLogInfo(user, macIp);
             return userVo;
         }
     }
@@ -100,4 +118,36 @@ public class LifeUserService extends ServiceImpl<LifeUserMapper, LifeUser> {
         return this.getOne(lambdaQueryWrapper);
     }
 
+
+    /**
+     * 用户登录log存放(加入mac地址)
+     */
+    public void addLifeUserLogInfo(LifeUser user, String macIp) {
+        try {
+            LifeUserLog lifeUserLog = new LifeUserLog();
+            lifeUserLog.setUserId(user.getId());
+            lifeUserLog.setUserName(user.getUserName());
+            lifeUserLog.setMacIp(macIp);
+            lifeUserLog.setCreatedTime(new Date());
+            lifeUserLogMapper.insert(lifeUserLog);
+
+            String startDate = LocalDateTime.now().minusHours(24L).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            String endDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            List<LifeUserLog> lsit = lifeUserLogMapper.getLifeUserLogByDate(startDate, endDate, macIp);
+
+            secondServiceFeign.recordRiskControlData(1, 2, "账号异常","1", "测试");
+
+            if (lsit.size() > regCount24h) {
+                String detailInfo = lsit.stream()
+                        .map(row -> row.getUserId().toString())
+                        .collect(Collectors.joining(","));
+                secondServiceFeign.recordRiskControlData(null, 2, "账号异常", "1", detailInfo);
+            }
+
+            secondServiceFeign.createPointsRecord(user.getId(), 300, 1);
+        } catch (Exception e) {
+            log.error("用户登录log存放异常:{}");
+        }
+
+    }
 }

+ 81 - 0
alien-second/src/main/java/shop/alien/second/controller/SecondUserPointsController.java

@@ -0,0 +1,81 @@
+package shop.alien.second.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.second.SecondUserCredit;
+import shop.alien.second.service.SecondUserCreditService;
+
+/**
+ * 二手平台用户积分控制器
+ */
+@Slf4j
+@Api(tags = {"二期-用户积分"})
+@CrossOrigin
+@RestController
+@RequestMapping("/userPoints")
+@RequiredArgsConstructor
+public class SecondUserPointsController {
+    
+    private final SecondUserCreditService secondUserCreditService;
+    
+    @ApiOperation("获取用户积分")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "path", required = true)
+    })
+    @GetMapping("/{userId}")
+    public R<SecondUserCredit> getUserPoints(@PathVariable Integer userId) {
+        log.info("获取用户积分,userId={}", userId);
+        try {
+            SecondUserCredit userPoints = secondUserCreditService.getByUserId(userId);
+            return R.data(userPoints);
+        } catch (Exception e) {
+            log.error("获取用户积分失败,userId={}", userId, e);
+            return R.fail("获取用户积分失败");
+        }
+    }
+    
+    @ApiOperation("更新用户积分")
+    @ApiOperationSupport(order = 2)
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "path", required = true),
+        @ApiImplicitParam(name = "points", value = "积分变动值", dataType = "Integer", paramType = "query", required = true)
+    })
+    @PostMapping("/{userId}/points")
+    public R<Boolean> updateUserPoints(@PathVariable Integer userId, @RequestParam Integer points) {
+        log.info("更新用户积分,userId={}, points={}", userId, points);
+        try {
+            boolean result = secondUserCreditService.updatePoints(userId, points);
+            if (result) {
+                return R.success("积分更新成功");
+            } else {
+                return R.fail("积分更新失败");
+            }
+        } catch (Exception e) {
+            log.error("更新用户积分失败,userId={}, points={}", userId, points, e);
+            return R.fail("积分更新失败");
+        }
+    }
+    
+    @ApiOperation("新建用户积分记录")
+    @ApiOperationSupport(order = 3)
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "path", required = true),
+        @ApiImplicitParam(name = "initialPoints", value = "初始积分值", dataType = "Integer", paramType = "query"),
+            @ApiImplicitParam(name = "pointsType", value = "初始积分类型", dataType = "Integer", paramType = "query")
+    })
+    @PostMapping("/create")
+    public void createPointsRecord(@RequestParam("userId")  Integer userId,
+                                   @RequestParam("initialPoints")  Integer initialPoints,
+                                   @RequestParam("pointsType")  Integer pointsType) {
+        log.info("新建用户积分记录,userId={}, initialPoints={}", userId, initialPoints);
+        try {
+            secondUserCreditService.createPointsRecord(userId, initialPoints, pointsType);
+        } catch (Exception e) {
+            log.error("新建用户积分记录失败,userId={}, initialPoints={}", userId, initialPoints, e);
+        }
+    }
+}

+ 60 - 0
alien-second/src/main/java/shop/alien/second/controller/SecondUserPointsRecordController.java

@@ -0,0 +1,60 @@
+package shop.alien.second.controller;
+
+import io.swagger.annotations.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.second.SecondUserCreditRecord;
+import shop.alien.second.service.SecondUserCreditRecordService;
+
+import java.util.List;
+
+/**
+ * 二手平台用户积分记录控制器
+ */
+@Slf4j
+@Api(tags = {"二期-用户积分记录"})
+@CrossOrigin
+@RestController
+@RequestMapping("/userPointsRecord")
+@RequiredArgsConstructor
+public class SecondUserPointsRecordController {
+    
+    private final SecondUserCreditRecordService secondUserPointsRecordService;
+    
+    @ApiOperation("获取用户积分记录列表")
+    @ApiOperationSupport(order = 1)
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "用户ID", dataType = "Integer", paramType = "path", required = true)
+    })
+    @GetMapping("/user/{userId}")
+    public R<List<SecondUserCreditRecord>> getUserPointsRecords(@PathVariable Integer userId) {
+        log.info("获取用户积分记录列表,userId={}", userId);
+        try {
+            List<SecondUserCreditRecord> records = secondUserPointsRecordService.getRecordsByUserId(userId);
+            return R.data(records);
+        } catch (Exception e) {
+            log.error("获取用户积分记录列表失败,userId={}", userId, e);
+            return R.fail("获取用户积分记录列表失败");
+        }
+    }
+    
+    @ApiOperation("创建积分记录")
+    @ApiOperationSupport(order = 2)
+    @PostMapping("/create")
+    public R<Boolean> createPointsRecord(@RequestBody SecondUserCreditRecord record) {
+        log.info("创建积分记录,userId={}, points={}", record.getUserId(), record.getPoints());
+        try {
+            boolean result = secondUserPointsRecordService.createRecord(record);
+            if (result) {
+                return R.success("积分记录创建成功");
+            } else {
+                return R.fail("积分记录创建失败");
+            }
+        } catch (Exception e) {
+            log.error("创建积分记录失败,record={}", record, e);
+            return R.fail("积分记录创建失败");
+        }
+    }
+}

+ 39 - 0
alien-second/src/main/java/shop/alien/second/platform/PlatformSecondUserFreezeController.java

@@ -0,0 +1,39 @@
+package shop.alien.second.platform;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiOperationSupport;
+import io.swagger.annotations.ApiSort;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import shop.alien.entity.result.R;
+import shop.alien.entity.second.vo.SecondTradeRecordVo;
+import shop.alien.second.service.PlatformSecondTradeService;
+
+import java.util.List;
+
+@Slf4j
+@Api(tags = {"平台-账号冻结"})
+@ApiSort(1)
+@CrossOrigin
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/userFreeze")
+public class PlatformSecondUserFreezeController {
+
+    private final PlatformSecondTradeService secondTradeRecordService;
+
+    @ApiOperation("交易列表(分页)")
+    @ApiOperationSupport(order = 1)
+    @PostMapping("/getTradeRecordPage")
+    public R<IPage<SecondTradeRecordVo>> getTradeRecordPage(@RequestBody SecondTradeRecordVo vo) throws Exception {
+        log.info("PlatformSecondTradeController.getTradeRecordPage?vo={}", vo.toString());
+        return R.data(secondTradeRecordService.getTradeRecordPage(vo));
+    }
+
+
+
+}

+ 24 - 0
alien-second/src/main/java/shop/alien/second/service/SecondUserCreditRecordService.java

@@ -0,0 +1,24 @@
+package shop.alien.second.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.second.SecondUserCreditRecord;
+
+/**
+ * 二手平台用户积分记录服务接口
+ */
+public interface SecondUserCreditRecordService extends IService<SecondUserCreditRecord> {
+    
+    /**
+     * 根据用户ID获取积分记录列表
+     * @param userId 用户ID
+     * @return 积分记录列表
+     */
+    java.util.List<SecondUserCreditRecord> getRecordsByUserId(Integer userId);
+    
+    /**
+     * 创建积分记录
+     * @param record 积分记录信息
+     * @return 是否创建成功
+     */
+    boolean createRecord(SecondUserCreditRecord record);
+}

+ 33 - 0
alien-second/src/main/java/shop/alien/second/service/SecondUserCreditService.java

@@ -0,0 +1,33 @@
+package shop.alien.second.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import shop.alien.entity.second.SecondUserCredit;
+
+/**
+ * 二手平台用户积分服务接口
+ */
+public interface SecondUserCreditService extends IService<SecondUserCredit> {
+    
+    /**
+     * 根据用户ID获取用户积分信息
+     * @param userId 用户ID
+     * @return 用户积分信息
+     */
+    SecondUserCredit getByUserId(Integer userId);
+    
+    /**
+     * 更新用户积分
+     * @param userId 用户ID
+     * @param points 积分变动值(可为负数)
+     * @return 是否更新成功
+     */
+    boolean updatePoints(Integer userId, Integer points);
+    
+    /**
+     * 新建用户积分记录
+     * @param userId 用户ID
+     * @param initialPoints 初始积分值
+     * @return 是否创建成功
+     */
+    boolean createPointsRecord(Integer userId, Integer initialPoints, Integer pointsType);
+}

+ 59 - 0
alien-second/src/main/java/shop/alien/second/service/impl/SecondUserCreditRecordServiceImpl.java

@@ -0,0 +1,59 @@
+package shop.alien.second.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.second.SecondUserCreditRecord;
+import shop.alien.mapper.second.SecondUserCreditRecordMapper;
+import shop.alien.second.service.SecondUserCreditRecordService;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 二手平台用户积分记录服务实现类
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SecondUserCreditRecordServiceImpl extends ServiceImpl<SecondUserCreditRecordMapper, SecondUserCreditRecord> implements SecondUserCreditRecordService {
+    
+    private final SecondUserCreditRecordMapper secondUserCreditRecordMapper;
+    
+    /**
+     * 根据用户ID获取积分记录列表
+     * @param userId 用户ID
+     * @return 积分记录列表
+     */
+    @Override
+    public List<SecondUserCreditRecord> getRecordsByUserId(Integer userId) {
+        log.info("查询用户积分记录,userId={}", userId);
+        LambdaQueryWrapper<SecondUserCreditRecord> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SecondUserCreditRecord::getUserId, userId)
+                .eq(SecondUserCreditRecord::getDeleteFlag, 0)
+                .orderByDesc(SecondUserCreditRecord::getCreatedTime);
+        return secondUserCreditRecordMapper.selectList(queryWrapper);
+    }
+    
+    /**
+     * 创建积分记录
+     * @param record 积分记录信息
+     * @return 是否创建成功
+     */
+    @Override
+    public boolean createRecord(SecondUserCreditRecord record) {
+        try {
+            log.info("创建积分记录,userId={}, points={}", record.getUserId(), record.getPoints());
+            record.setDeleteFlag(0);
+            record.setCreatedTime(new Date());
+            record.setUpdatedTime(new Date());
+            int result = secondUserCreditRecordMapper.insert(record);
+            return result > 0;
+        } catch (Exception e) {
+            log.error("创建积分记录失败,userId={}, points={}", record.getUserId(), record.getPoints(), e);
+            return false;
+        }
+    }
+}

+ 124 - 0
alien-second/src/main/java/shop/alien/second/service/impl/SecondUserCreditServiceImpl.java

@@ -0,0 +1,124 @@
+package shop.alien.second.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import shop.alien.entity.second.SecondUserCredit;
+import shop.alien.entity.second.SecondUserCreditRecord;
+import shop.alien.mapper.second.SecondUserCreditMapper;
+import shop.alien.second.service.SecondUserCreditService;
+
+import java.util.Date;
+
+/**
+ * 二手平台用户积分服务实现类
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SecondUserCreditServiceImpl extends ServiceImpl<SecondUserCreditMapper, SecondUserCredit> implements SecondUserCreditService {
+    
+    private final SecondUserCreditMapper secondUserCreditMapper;
+
+    private final SecondUserCreditRecordServiceImpl serviceImpl;
+
+    /**
+     * 根据用户ID获取用户积分信息
+     * @param userId 用户ID
+     * @return 用户积分信息
+     */
+    @Override
+    public SecondUserCredit getByUserId(Integer userId) {
+        LambdaQueryWrapper<SecondUserCredit> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SecondUserCredit::getUserId, userId)
+                .eq(SecondUserCredit::getDeleteFlag, 0);
+        return secondUserCreditMapper.selectOne(queryWrapper);
+    }
+    
+    /**
+     * 更新用户积分
+     * @param userId 用户ID
+     * @param points 积分变动值(可为负数)
+     * @return 是否更新成功
+     */
+    @Override
+    public boolean updatePoints(Integer userId, Integer points) {
+        try {
+            // 查询用户积分记录
+            SecondUserCredit userPoints = getByUserId(userId);
+            
+            if (userPoints == null) {
+                // 如果用户没有积分记录,则创建新记录
+                userPoints = new SecondUserCredit();
+                userPoints.setUserId(userId);
+                userPoints.setUserPoints(points > 0 ? points : 0);
+                userPoints.setDeleteFlag(0);
+                userPoints.setCreatedTime(new Date());
+                userPoints.setUpdatedTime(new Date());
+                secondUserCreditMapper.insert(userPoints);
+            } else {
+                // 更新积分
+                int newPoints = userPoints.getUserPoints() + points;
+                userPoints.setUserPoints(newPoints > 0 ? newPoints : 0);
+                userPoints.setUpdatedTime(new Date());
+                secondUserCreditMapper.updateById(userPoints);
+            }
+            return true;
+        } catch (Exception e) {
+            log.error("更新用户积分失败,userId={}, points={}", userId, points, e);
+            return false;
+        }
+    }
+    
+    /**
+     * 新建用户积分记录
+     * @param userId 用户ID
+     * @param initialPoints 初始积分值
+     * @return 是否创建成功
+     */
+    @Override
+    public boolean createPointsRecord(Integer userId, Integer initialPoints, Integer pointsType) {
+        try {
+            // 检查是否已存在记录
+            SecondUserCredit existingPoints = getByUserId(userId);
+            if (existingPoints != null) {
+                log.warn("用户积分记录已存在,userId={}", userId);
+                return false;
+            }
+            return addPointsRecord(userId, initialPoints, pointsType);
+        } catch (Exception e) {
+            log.error("创建用户积分记录失败,userId={}, initialPoints={}", userId, initialPoints, e);
+            return false;
+        }
+    }
+
+    public boolean addPointsRecord(Integer userId, Integer points, Integer pointsType) {
+        try {
+            // 创建新的积分记录
+            SecondUserCredit userPoints = new SecondUserCredit();
+            userPoints.setUserId(userId);
+            userPoints.setUserPoints(points != null ? points : 0);
+            userPoints.setDeleteFlag(0);
+            userPoints.setCreatedTime(new Date());
+            userPoints.setUpdatedTime(new Date());
+
+            int result = secondUserCreditMapper.insert(userPoints);
+
+            // 创建积分记录
+            SecondUserCreditRecord record = new SecondUserCreditRecord();
+            record.setUserId(userId);
+            record.setPoints(points);
+            record.setPointsType(pointsType);
+            serviceImpl.createRecord(record);
+
+            return result > 0;
+        } catch (Exception e) {
+            log.error("删除用户积分记录失败,userId={}", userId, e);
+            return false;
+        }
+    }
+
+
+}