diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/UserErrorLogController.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/UserErrorLogController.java new file mode 100644 index 00000000..7e009518 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/UserErrorLogController.java @@ -0,0 +1,96 @@ +package com.ruoyi.cai.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.cai.domain.UserErrorLog; +import com.ruoyi.cai.dto.admin.vo.UserErrorLogAdminVo; +import com.ruoyi.cai.service.UserErrorLogService; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.enums.BusinessType; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; + +/** + * 用户异常记录 + * + * @author 77 + * @date 2024-01-22 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/cai/userErrorLog") +public class UserErrorLogController extends BaseController { + + private final UserErrorLogService userErrorLogService; + + /** + * 查询用户异常记录列表 + */ + @SaCheckPermission("cai:userErrorLog:list") + @GetMapping("/list") + public TableDataInfo list(UserErrorLogAdminVo bo, PageQuery pageQuery) { + Page page = userErrorLogService.pageAdmin(pageQuery, bo); + return TableDataInfo.build(page); + } + + /** + * 获取用户异常记录详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("cai:userErrorLog:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(userErrorLogService.getById(id)); + } + + /** + * 新增用户异常记录 + */ + @SaCheckPermission("cai:userErrorLog:add") + @Log(title = "用户异常记录", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody UserErrorLog bo) { + return toAjax(userErrorLogService.save(bo)); + } + + /** + * 修改用户异常记录 + */ + @SaCheckPermission("cai:userErrorLog:edit") + @Log(title = "用户异常记录", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody UserErrorLog bo) { + return toAjax(userErrorLogService.updateById(bo)); + } + + /** + * 删除用户异常记录 + * + * @param ids 主键串 + */ + @SaCheckPermission("cai:userErrorLog:remove") + @Log(title = "用户异常记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(userErrorLogService.removeBatchByIds(Arrays.asList(ids))); + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/app/OtherController.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/app/OtherController.java index 6bf949a6..ca75bca1 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/app/OtherController.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/controller/app/OtherController.java @@ -1,7 +1,9 @@ package com.ruoyi.cai.controller.app; import com.ruoyi.cai.dto.app.query.UserReportReq; +import com.ruoyi.cai.dto.app.query.push.PushErrorReq; import com.ruoyi.cai.service.ReportService; +import com.ruoyi.cai.service.UserErrorLogService; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.enums.BusinessType; @@ -21,6 +23,8 @@ public class OtherController { @Autowired private ReportService reportService; + @Autowired + private UserErrorLogService userErrorLogService; @PostMapping("/report") @Operation(summary = "举报") @@ -31,4 +35,13 @@ public class OtherController { reportService.report(reportRes); return R.ok(); } + + @PostMapping("/pushError") + @Operation(summary = "上报异常行为(截屏,录屏)") + @Log(title = "上报异常行为(截屏,录屏)", businessType = BusinessType.OTHER, isSaveDb = false) + public R pushError(@RequestBody PushErrorReq req){ + req.setUserId(LoginHelper.getUserId()); + userErrorLogService.pushError(req); + return R.ok(); + } } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserErrorLog.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserErrorLog.java new file mode 100644 index 00000000..61a453b1 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserErrorLog.java @@ -0,0 +1,45 @@ +package com.ruoyi.cai.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; +import java.math.BigDecimal; + +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 用户异常记录对象 cai_user_error_log + * + * @author 77 + * @date 2024-01-22 + */ +@Data +@TableName("cai_user_error_log") +public class UserErrorLog implements Serializable { + + private static final long serialVersionUID=1L; + + /** + * + */ + @TableId(value = "id",type = IdType.AUTO) + private Long id; + /** + * 类型 1-截屏 2-录屏 + */ + private Integer type; + /** + * 用户ID + */ + private Long userId; + /** + * 异常行为发生的地方, video=直播,other=其他 + */ + private String homeIndex; + + private LocalDateTime createTime; + +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserRiskLog.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserRiskLog.java index babdfcd7..c5fb4f4d 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserRiskLog.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/domain/UserRiskLog.java @@ -16,6 +16,7 @@ import java.time.LocalDateTime; */ @Data @TableName("cai_user_risk_log") +@Deprecated public class UserRiskLog implements Serializable { private static final long serialVersionUID=1L; diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/dto/admin/vo/UserErrorLogAdminVo.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/dto/admin/vo/UserErrorLogAdminVo.java new file mode 100644 index 00000000..b275723d --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/dto/admin/vo/UserErrorLogAdminVo.java @@ -0,0 +1,35 @@ +package com.ruoyi.cai.dto.admin.vo; + +import com.ruoyi.cai.domain.UserErrorLog; +import com.ruoyi.common.annotation.Sensitive; +import com.ruoyi.common.enums.SensitiveStrategy; +import lombok.Data; + +@Data +public class UserErrorLogAdminVo extends UserErrorLog { + /** + * 用户号/ID号 + */ + private String usercode; + /** + * 昵称 + */ + private String nickname; + + /** + * 手机号 + */ + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String mobile; + + /** + * 头像 + */ + private String avatar; + /** + * 性别 + */ + private Integer gender; + private Integer age; + private Integer isAnchor; +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/dto/app/query/push/PushErrorReq.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/dto/app/query/push/PushErrorReq.java new file mode 100644 index 00000000..ae2aeb4c --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/dto/app/query/push/PushErrorReq.java @@ -0,0 +1,15 @@ +package com.ruoyi.cai.dto.app.query.push; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "上报异常模式入参") +public class PushErrorReq { + @Schema(description = "用户ID",hidden = true) + private Long userId; + @Schema(description = "1-截屏 2-录屏") + private Integer type; + @Schema(description = "异常行为发生的地方, video=直播,other=其他") + private String homeIndex = "other"; +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/enums/user/UserErrorLogHomeIndexEnum.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/enums/user/UserErrorLogHomeIndexEnum.java new file mode 100644 index 00000000..b116f342 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/enums/user/UserErrorLogHomeIndexEnum.java @@ -0,0 +1,17 @@ +package com.ruoyi.cai.enums.user; + +import lombok.Getter; + +@Getter +public enum UserErrorLogHomeIndexEnum { + VIDEO("video","直播"), + OTHER("other","其他"), + ; + private final String code; + private final String name; + + UserErrorLogHomeIndexEnum(String code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/enums/user/UserErrorLogType.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/enums/user/UserErrorLogType.java new file mode 100644 index 00000000..8dde62e2 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/enums/user/UserErrorLogType.java @@ -0,0 +1,28 @@ +package com.ruoyi.cai.enums.user; + +import lombok.Getter; + +@Getter +public enum UserErrorLogType { + SCREEN_SHOT(1,"截屏"), + SCREEN_RECORDING(2,"录屏"), + ; + + private final Integer code; + private final String name; + + UserErrorLogType(Integer code, String name) { + this.code = code; + this.name = name; + } + + public static UserErrorLogType getByCode(Integer type) { + UserErrorLogType[] values = values(); + for (UserErrorLogType value : values) { + if(value.getCode().equals(type)){ + return value; + } + } + return null; + } +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/LowHeightRiskMapper.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/LowHeightRiskMapper.java index efb528aa..81fd661b 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/LowHeightRiskMapper.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/LowHeightRiskMapper.java @@ -15,4 +15,8 @@ import org.apache.ibatis.annotations.Param; public interface LowHeightRiskMapper extends BaseMapper { Page pageAdmin(@Param("build") Page build, @Param("bo") LowHeightRiskAdminVo bo); + + void incsScreenShot(@Param("id") Long id); + + void incsScreenRecording(@Param("id") Long id); } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/UserErrorLogMapper.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/UserErrorLogMapper.java new file mode 100644 index 00000000..10f18061 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/mapper/UserErrorLogMapper.java @@ -0,0 +1,18 @@ +package com.ruoyi.cai.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.cai.domain.UserErrorLog; +import com.ruoyi.cai.dto.admin.vo.UserErrorLogAdminVo; +import org.apache.ibatis.annotations.Param; + +/** + * 用户异常记录Mapper接口 + * + * @author 77 + * @date 2024-01-22 + */ +public interface UserErrorLogMapper extends BaseMapper { + + Page pageAdmin(@Param("build") Page build, @Param("bo") UserErrorLogAdminVo bo); +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/LowHeightRiskService.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/LowHeightRiskService.java index 3cc31451..0c9e8b73 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/LowHeightRiskService.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/LowHeightRiskService.java @@ -3,6 +3,7 @@ package com.ruoyi.cai.service; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.cai.domain.LowHeightRisk; +import com.ruoyi.cai.domain.UserErrorLog; import com.ruoyi.cai.dto.admin.vo.LowHeightRiskAdminVo; import com.ruoyi.common.core.domain.PageQuery; @@ -15,4 +16,6 @@ import com.ruoyi.common.core.domain.PageQuery; public interface LowHeightRiskService extends IService { Page pageAdmin(PageQuery pageQuery, LowHeightRiskAdminVo bo); + + void incsNum(UserErrorLog log); } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/UserErrorLogService.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/UserErrorLogService.java new file mode 100644 index 00000000..eb497591 --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/UserErrorLogService.java @@ -0,0 +1,21 @@ +package com.ruoyi.cai.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; +import com.ruoyi.cai.domain.UserErrorLog; +import com.ruoyi.cai.dto.admin.vo.UserErrorLogAdminVo; +import com.ruoyi.cai.dto.app.query.push.PushErrorReq; +import com.ruoyi.common.core.domain.PageQuery; + +/** + * 用户异常记录Service接口 + * + * @author 77 + * @date 2024-01-22 + */ +public interface UserErrorLogService extends IService { + + void pushError(PushErrorReq req); + + Page pageAdmin(PageQuery pageQuery, UserErrorLogAdminVo bo); +} diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/LowHeightRiskServiceImpl.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/LowHeightRiskServiceImpl.java index 2a505614..857e15cf 100644 --- a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/LowHeightRiskServiceImpl.java +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/LowHeightRiskServiceImpl.java @@ -1,14 +1,19 @@ package com.ruoyi.cai.service.impl; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.cai.domain.LowHeightRisk; +import com.ruoyi.cai.domain.UserErrorLog; import com.ruoyi.cai.dto.admin.vo.LowHeightRiskAdminVo; +import com.ruoyi.cai.enums.user.UserErrorLogType; import com.ruoyi.cai.mapper.LowHeightRiskMapper; import com.ruoyi.cai.service.LowHeightRiskService; import com.ruoyi.common.core.domain.PageQuery; import org.springframework.stereotype.Service; +import java.util.concurrent.locks.ReentrantLock; + /** * 高风险用户记录Service业务层处理 * @@ -22,4 +27,33 @@ public class LowHeightRiskServiceImpl extends ServiceImpl pageAdmin(PageQuery pageQuery, LowHeightRiskAdminVo bo) { return baseMapper.pageAdmin(pageQuery.build(),bo); } + + @Override + public void incsNum(UserErrorLog log){ + if(log == null || log.getUserId() == null){ + return; + } + LowHeightRisk one = this.getOne(Wrappers.lambdaQuery(LowHeightRisk.class) + .eq(LowHeightRisk::getUserId, log.getUserId())); + if(one == null){ + ReentrantLock lock = new ReentrantLock(); + try { + lock.lock(); + one = this.getOne(Wrappers.lambdaQuery(LowHeightRisk.class) + .eq(LowHeightRisk::getUserId, log.getUserId())); + if(one == null){ + one = new LowHeightRisk(); + one.setUserId(log.getUserId()); + } + this.save(one); + }finally { + lock.unlock(); + } + } + if(UserErrorLogType.SCREEN_SHOT.getCode().equals(log.getType())){ + baseMapper.incsScreenShot(one.getId()); + }else if(UserErrorLogType.SCREEN_RECORDING.getCode().equals(log.getType())){ + baseMapper.incsScreenRecording(one.getId()); + } + } } diff --git a/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/UserErrorLogServiceImpl.java b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/UserErrorLogServiceImpl.java new file mode 100644 index 00000000..6ec926ab --- /dev/null +++ b/ruoyi-cai/src/main/java/com/ruoyi/cai/service/impl/UserErrorLogServiceImpl.java @@ -0,0 +1,77 @@ +package com.ruoyi.cai.service.impl; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ruoyi.cai.domain.UserErrorLog; +import com.ruoyi.cai.dto.admin.UserForbidDTO; +import com.ruoyi.cai.dto.admin.vo.UserErrorLogAdminVo; +import com.ruoyi.cai.dto.app.query.push.PushErrorReq; +import com.ruoyi.cai.enums.ForbidTimeEnum; +import com.ruoyi.cai.enums.ForbidTypeEnum; +import com.ruoyi.cai.enums.user.UserErrorLogHomeIndexEnum; +import com.ruoyi.cai.enums.user.UserErrorLogType; +import com.ruoyi.cai.manager.UserForbidManager; +import com.ruoyi.cai.mapper.UserErrorLogMapper; +import com.ruoyi.cai.service.LowHeightRiskService; +import com.ruoyi.cai.service.UserErrorLogService; +import com.ruoyi.common.core.domain.PageQuery; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 用户异常记录Service业务层处理 + * + * @author 77 + * @date 2024-01-22 + */ +@Service +@Slf4j +public class UserErrorLogServiceImpl extends ServiceImpl implements UserErrorLogService { + + @Autowired + private LowHeightRiskService lowHeightRiskService; + @Autowired + private UserForbidManager userForbidManager; + + @Override + @Transactional(rollbackFor = Exception.class) + public void pushError(PushErrorReq req) { + UserErrorLogType logType = UserErrorLogType.getByCode(req.getType()); + if(logType == null){ + log.error("记录高危风险失败,参数异常! req={}", JSON.toJSONString(req)); + return; + } + if(req.getHomeIndex() == null){ + req.setHomeIndex(UserErrorLogHomeIndexEnum.OTHER.getCode()); + } + UserErrorLog log = new UserErrorLog(); + log.setType(req.getType()); + log.setUserId(req.getUserId()); + log.setHomeIndex(req.getHomeIndex()); + this.save(log); + lowHeightRiskService.incsNum(log); + // 记录风险 + if(UserErrorLogHomeIndexEnum.VIDEO.getCode().equals(log.getHomeIndex())){ // 直播的直接封号 + String remark = String.format("于%s 直播期间%s封10年", + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), + logType.getName()); + UserForbidDTO dto = new UserForbidDTO(); + dto.setForbidTime(ForbidTimeEnum.YEAR_10.getCode()); + dto.setForbidType(ForbidTypeEnum.USER.getCode()); + dto.setMember(req.getUserId()+""); + dto.setRemark(remark); + userForbidManager.forbid(dto); + } + } + + @Override + public Page pageAdmin(PageQuery pageQuery, UserErrorLogAdminVo bo) { + return baseMapper.pageAdmin(pageQuery.build(),bo); + } +} diff --git a/ruoyi-cai/src/main/resources/mapper/cai/LowHeightRiskMapper.xml b/ruoyi-cai/src/main/resources/mapper/cai/LowHeightRiskMapper.xml index 05417c95..b58a7d0b 100644 --- a/ruoyi-cai/src/main/resources/mapper/cai/LowHeightRiskMapper.xml +++ b/ruoyi-cai/src/main/resources/mapper/cai/LowHeightRiskMapper.xml @@ -12,6 +12,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + update cai_low_height_risk + set screenshot_num = screenshot_num + 1 + where id = #{id} + + + update cai_low_height_risk + set screen_recording_num = screen_recording_num + 1 + where id = #{id} + + select t1.*,t2.usercode,t2.nickname,t2.mobile,t2.avatar,t2.gender,t2.is_anchor,t2.age + from cai_user_error_log t1 + left join cai_user t2 on t1.user_id = t2.id + + + and t2.mobile = #{bo.mobile} + + + and t2.usercode = #{bo.usercode} + + + and t1.type = #{bo.type} + + + and t1.home_index = #{bo.homeIndex} + + + order by t1.create_time desc + + + + diff --git a/ruoyi-cai/src/main/resources/mapper/system/CaiUserErrorLogMapper.xml b/ruoyi-cai/src/main/resources/mapper/system/CaiUserErrorLogMapper.xml new file mode 100644 index 00000000..1c583c18 --- /dev/null +++ b/ruoyi-cai/src/main/resources/mapper/system/CaiUserErrorLogMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + +