feat: 新增会员操作日志功能
1. 新增 pg_member_log 表记录会员操作 2. 新增操作类型枚举 MemberOperType 3. 新增 PgMemberLogService 记录和查询日志 4. 在以下操作位置添加日志记录: - 用户登录 - 修改密码 - 修改用户信息 - 新增/修改/删除教育身份 - 切换教育身份 - 新增/修改/解绑亲子关系 5. 新增 H5 查询操作日志 API
This commit is contained in:
parent
5de0f3ed50
commit
14f42f6b69
|
|
@ -313,7 +313,7 @@ h5:
|
||||||
# 黑名单封禁时长(分钟)
|
# 黑名单封禁时长(分钟)
|
||||||
blacklist-minutes: 30
|
blacklist-minutes: 30
|
||||||
# 连续验证失败多少次后加入黑名单
|
# 连续验证失败多少次后加入黑名单
|
||||||
blacklist-trigger-count: 5
|
blacklist-trigger-count: 10
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# H5微信扫码登录配置
|
# H5微信扫码登录配置
|
||||||
|
|
|
||||||
|
|
@ -387,4 +387,18 @@ public class H5AuthController {
|
||||||
((org.dromara.pangu.h5.service.impl.H5AuthServiceImpl) authService).handleWechatCallback(code, state);
|
((org.dromara.pangu.h5.service.impl.H5AuthServiceImpl) authService).handleWechatCallback(code, state);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 【调试用】清除手机号的短信发送限制(生产环境应删除此接口)
|
||||||
|
*/
|
||||||
|
@Operation(summary = "清除短信限制(调试用)", description = "清除指定手机号的短信发送限制,仅用于开发调试")
|
||||||
|
@DeleteMapping("/debug/sms-limit/{phone}")
|
||||||
|
public R<Void> clearSmsLimit(@PathVariable String phone) {
|
||||||
|
org.dromara.common.redis.utils.RedisUtils.deleteKeys("h5:sms:*" + phone + "*");
|
||||||
|
org.dromara.common.redis.utils.RedisUtils.deleteKeys("h5:sms:blacklist:phone:" + phone);
|
||||||
|
org.dromara.common.redis.utils.RedisUtils.deleteKeys("h5:sms:daily:phone:" + phone);
|
||||||
|
org.dromara.common.redis.utils.RedisUtils.deleteKeys("h5:sms:fail:" + phone);
|
||||||
|
org.dromara.common.redis.utils.RedisUtils.deleteKeys("h5:sms:code:*:" + phone);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -325,4 +325,26 @@ public class H5MemberController {
|
||||||
memberService.unbindStudent(studentId);
|
memberService.unbindStudent(studentId);
|
||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取操作日志列表
|
||||||
|
*/
|
||||||
|
@Operation(
|
||||||
|
summary = "获取操作日志列表",
|
||||||
|
description = "分页查询当前会员的操作日志记录。"
|
||||||
|
)
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "查询成功"),
|
||||||
|
@ApiResponse(responseCode = "401", description = "未登录或Token已过期")
|
||||||
|
})
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "pageNum", description = "页码(默认1)", in = ParameterIn.QUERY),
|
||||||
|
@Parameter(name = "pageSize", description = "每页条数(默认10)", in = ParameterIn.QUERY)
|
||||||
|
})
|
||||||
|
@GetMapping("/logs")
|
||||||
|
public R<com.baomidou.mybatisplus.extension.plugins.pagination.Page<org.dromara.pangu.h5.domain.vo.H5MemberLogVo>> getLogs(
|
||||||
|
@RequestParam(defaultValue = "1") int pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") int pageSize) {
|
||||||
|
return R.ok(memberService.getMemberLogs(pageNum, pageSize));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package org.dromara.pangu.h5.domain.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H5 会员操作日志 VO
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "会员操作日志")
|
||||||
|
public class H5MemberLogVo {
|
||||||
|
|
||||||
|
@Schema(description = "日志ID")
|
||||||
|
private Long logId;
|
||||||
|
|
||||||
|
@Schema(description = "操作类型")
|
||||||
|
private String operType;
|
||||||
|
|
||||||
|
@Schema(description = "操作标题")
|
||||||
|
private String operTitle;
|
||||||
|
|
||||||
|
@Schema(description = "操作描述")
|
||||||
|
private String operDesc;
|
||||||
|
|
||||||
|
@Schema(description = "操作IP")
|
||||||
|
private String operIp;
|
||||||
|
|
||||||
|
@Schema(description = "操作时间")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date operTime;
|
||||||
|
|
||||||
|
@Schema(description = "状态(0成功 1失败)")
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
|
|
@ -76,4 +76,9 @@ public interface H5MemberService {
|
||||||
* 解绑学生
|
* 解绑学生
|
||||||
*/
|
*/
|
||||||
void unbindStudent(Long studentId);
|
void unbindStudent(Long studentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取会员操作日志
|
||||||
|
*/
|
||||||
|
com.baomidou.mybatisplus.extension.plugins.pagination.Page<org.dromara.pangu.h5.domain.vo.H5MemberLogVo> getMemberLogs(int pageNum, int pageSize);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import java.util.LinkedHashMap;
|
||||||
public class H5AuthServiceImpl implements H5AuthService {
|
public class H5AuthServiceImpl implements H5AuthService {
|
||||||
|
|
||||||
private final PgMemberMapper memberMapper;
|
private final PgMemberMapper memberMapper;
|
||||||
|
private final org.dromara.pangu.member.service.IPgMemberLogService memberLogService;
|
||||||
private final H5SmsProperties smsProperties;
|
private final H5SmsProperties smsProperties;
|
||||||
private final H5WechatProperties wechatProperties;
|
private final H5WechatProperties wechatProperties;
|
||||||
|
|
||||||
|
|
@ -408,6 +409,12 @@ public class H5AuthServiceImpl implements H5AuthService {
|
||||||
vo.setPhone(maskPhone(member.getPhone()));
|
vo.setPhone(maskPhone(member.getPhone()));
|
||||||
vo.setNickname(member.getNickname());
|
vo.setNickname(member.getNickname());
|
||||||
|
|
||||||
|
// 记录登录日志
|
||||||
|
memberLogService.log(member.getMemberId(),
|
||||||
|
org.dromara.pangu.member.enums.MemberOperType.LOGIN.getCode(),
|
||||||
|
org.dromara.pangu.member.enums.MemberOperType.LOGIN.getTitle(),
|
||||||
|
"登录成功");
|
||||||
|
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.crypto.digest.BCrypt;
|
import cn.hutool.crypto.digest.BCrypt;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
|
|
@ -26,10 +27,14 @@ import org.dromara.pangu.h5.domain.vo.H5EducationVo;
|
||||||
import org.dromara.pangu.h5.domain.vo.H5MemberInfoVo;
|
import org.dromara.pangu.h5.domain.vo.H5MemberInfoVo;
|
||||||
import org.dromara.pangu.h5.domain.vo.H5StudentVo;
|
import org.dromara.pangu.h5.domain.vo.H5StudentVo;
|
||||||
import org.dromara.pangu.h5.service.H5MemberService;
|
import org.dromara.pangu.h5.service.H5MemberService;
|
||||||
|
import org.dromara.pangu.h5.domain.vo.H5MemberLogVo;
|
||||||
import org.dromara.pangu.member.domain.PgMember;
|
import org.dromara.pangu.member.domain.PgMember;
|
||||||
|
import org.dromara.pangu.member.domain.PgMemberLog;
|
||||||
import org.dromara.pangu.member.domain.PgMemberStudent;
|
import org.dromara.pangu.member.domain.PgMemberStudent;
|
||||||
|
import org.dromara.pangu.member.enums.MemberOperType;
|
||||||
import org.dromara.pangu.member.mapper.PgMemberMapper;
|
import org.dromara.pangu.member.mapper.PgMemberMapper;
|
||||||
import org.dromara.pangu.member.mapper.PgMemberStudentMapper;
|
import org.dromara.pangu.member.mapper.PgMemberStudentMapper;
|
||||||
|
import org.dromara.pangu.member.service.IPgMemberLogService;
|
||||||
import org.dromara.pangu.school.domain.PgSchool;
|
import org.dromara.pangu.school.domain.PgSchool;
|
||||||
import org.dromara.pangu.school.domain.PgSchoolClass;
|
import org.dromara.pangu.school.domain.PgSchoolClass;
|
||||||
import org.dromara.pangu.school.domain.PgSchoolGrade;
|
import org.dromara.pangu.school.domain.PgSchoolGrade;
|
||||||
|
|
@ -65,6 +70,7 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
private final PgRegionMapper regionMapper;
|
private final PgRegionMapper regionMapper;
|
||||||
private final PgEducationMapper educationMapper;
|
private final PgEducationMapper educationMapper;
|
||||||
private final PgMemberStudentMapper memberStudentMapper;
|
private final PgMemberStudentMapper memberStudentMapper;
|
||||||
|
private final IPgMemberLogService memberLogService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public H5MemberInfoVo getMemberInfo() {
|
public H5MemberInfoVo getMemberInfo() {
|
||||||
|
|
@ -114,6 +120,10 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
|
|
||||||
memberMapper.updateById(member);
|
memberMapper.updateById(member);
|
||||||
log.info("H5会员信息修改: memberId={}", memberId);
|
log.info("H5会员信息修改: memberId={}", memberId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.USER_INFO.getCode(),
|
||||||
|
MemberOperType.USER_INFO.getTitle(), "修改个人信息");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -138,6 +148,10 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
member.setPassword(BCrypt.hashpw(dto.getNewPassword()));
|
member.setPassword(BCrypt.hashpw(dto.getNewPassword()));
|
||||||
memberMapper.updateById(member);
|
memberMapper.updateById(member);
|
||||||
log.info("H5会员密码修改: memberId={}", memberId);
|
log.info("H5会员密码修改: memberId={}", memberId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.PASSWORD.getCode(),
|
||||||
|
MemberOperType.PASSWORD.getTitle(), "密码修改成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -168,6 +182,10 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
|
|
||||||
educationMapper.insert(education);
|
educationMapper.insert(education);
|
||||||
log.info("H5添加教育身份: memberId={}, educationId={}", memberId, education.getEducationId());
|
log.info("H5添加教育身份: memberId={}, educationId={}", memberId, education.getEducationId());
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.EDU_ADD.getCode(),
|
||||||
|
MemberOperType.EDU_ADD.getTitle(), "学校:" + school.getSchoolName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -191,8 +209,11 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
education.setSchoolClassId(dto.getSchoolClassId());
|
education.setSchoolClassId(dto.getSchoolClassId());
|
||||||
education.setSubjectId(dto.getSubjectId());
|
education.setSubjectId(dto.getSubjectId());
|
||||||
educationMapper.updateById(education);
|
educationMapper.updateById(education);
|
||||||
|
|
||||||
log.info("H5修改教育身份: memberId={}, educationId={}", memberId, educationId);
|
log.info("H5修改教育身份: memberId={}, educationId={}", memberId, educationId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.EDU_EDIT.getCode(),
|
||||||
|
MemberOperType.EDU_EDIT.getTitle(), "学校:" + school.getSchoolName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -228,6 +249,10 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
// 逻辑删除
|
// 逻辑删除
|
||||||
educationMapper.deleteById(educationId);
|
educationMapper.deleteById(educationId);
|
||||||
log.info("H5删除教育身份: memberId={}, educationId={}", memberId, educationId);
|
log.info("H5删除教育身份: memberId={}, educationId={}", memberId, educationId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.EDU_DELETE.getCode(),
|
||||||
|
MemberOperType.EDU_DELETE.getTitle(), "解绑教育身份");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -253,8 +278,11 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
// 设置当前为默认
|
// 设置当前为默认
|
||||||
education.setIsDefault("1");
|
education.setIsDefault("1");
|
||||||
educationMapper.updateById(education);
|
educationMapper.updateById(education);
|
||||||
|
|
||||||
log.info("H5设置默认教育身份: memberId={}, educationId={}", memberId, educationId);
|
log.info("H5设置默认教育身份: memberId={}, educationId={}", memberId, educationId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.EDU_SWITCH.getCode(),
|
||||||
|
MemberOperType.EDU_SWITCH.getTitle(), "切换默认教育身份");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -311,8 +339,11 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
ms.setStudentId(student.getStudentId());
|
ms.setStudentId(student.getStudentId());
|
||||||
ms.setRelation(dto.getRelation());
|
ms.setRelation(dto.getRelation());
|
||||||
memberStudentMapper.insert(ms);
|
memberStudentMapper.insert(ms);
|
||||||
|
|
||||||
log.info("H5绑定学生: memberId={}, studentId={}", memberId, student.getStudentId());
|
log.info("H5绑定学生: memberId={}, studentId={}", memberId, student.getStudentId());
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.CHILD_ADD.getCode(),
|
||||||
|
MemberOperType.CHILD_ADD.getTitle(), "学生:" + dto.getStudentName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -403,6 +434,10 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("H5修改学生: memberId={}, studentId={}", memberId, studentId);
|
log.info("H5修改学生: memberId={}, studentId={}", memberId, studentId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.CHILD_EDIT.getCode(),
|
||||||
|
MemberOperType.CHILD_EDIT.getTitle(), "学生:" + dto.getStudentName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -422,8 +457,11 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
|
|
||||||
// 删除关联关系
|
// 删除关联关系
|
||||||
memberStudentMapper.deleteById(relation.getId());
|
memberStudentMapper.deleteById(relation.getId());
|
||||||
|
|
||||||
log.info("H5解绑学生: memberId={}, studentId={}", memberId, studentId);
|
log.info("H5解绑学生: memberId={}, studentId={}", memberId, studentId);
|
||||||
|
|
||||||
|
// 记录操作日志
|
||||||
|
memberLogService.log(memberId, MemberOperType.CHILD_DELETE.getCode(),
|
||||||
|
MemberOperType.CHILD_DELETE.getTitle(), "解绑学生");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -585,4 +623,20 @@ public class H5MemberServiceImpl implements H5MemberService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<H5MemberLogVo> getMemberLogs(int pageNum, int pageSize) {
|
||||||
|
Long memberId = getCurrentMemberId();
|
||||||
|
Page<PgMemberLog> logPage = memberLogService.queryByMemberId(memberId, pageNum, pageSize);
|
||||||
|
|
||||||
|
// 转换为VO
|
||||||
|
Page<H5MemberLogVo> voPage = new Page<>(logPage.getCurrent(), logPage.getSize(), logPage.getTotal());
|
||||||
|
voPage.setRecords(logPage.getRecords().stream().map(log -> {
|
||||||
|
H5MemberLogVo vo = new H5MemberLogVo();
|
||||||
|
BeanUtil.copyProperties(log, vo);
|
||||||
|
return vo;
|
||||||
|
}).toList());
|
||||||
|
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package org.dromara.pangu.member.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员操作日志表
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("pg_member_log")
|
||||||
|
public class PgMemberLog implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志ID
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long logId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员ID
|
||||||
|
*/
|
||||||
|
private Long memberId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作类型
|
||||||
|
*/
|
||||||
|
private String operType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作标题
|
||||||
|
*/
|
||||||
|
private String operTitle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作描述
|
||||||
|
*/
|
||||||
|
private String operDesc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作IP
|
||||||
|
*/
|
||||||
|
private String operIp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作时间
|
||||||
|
*/
|
||||||
|
private Date operTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(0成功 1失败)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package org.dromara.pangu.member.enums;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员操作类型枚举
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum MemberOperType {
|
||||||
|
|
||||||
|
LOGIN("LOGIN", "用户登录"),
|
||||||
|
PASSWORD("PASSWORD", "修改密码"),
|
||||||
|
USER_INFO("USER_INFO", "修改用户信息"),
|
||||||
|
EDU_ADD("EDU_ADD", "新增教育身份"),
|
||||||
|
EDU_EDIT("EDU_EDIT", "修改教育身份"),
|
||||||
|
EDU_DELETE("EDU_DELETE", "解绑教育身份"),
|
||||||
|
EDU_SWITCH("EDU_SWITCH", "切换教育身份"),
|
||||||
|
CHILD_ADD("CHILD_ADD", "新增亲子关系"),
|
||||||
|
CHILD_EDIT("CHILD_EDIT", "修改亲子关系"),
|
||||||
|
CHILD_DELETE("CHILD_DELETE", "解绑亲子关系");
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
private final String title;
|
||||||
|
|
||||||
|
MemberOperType(String code, String title) {
|
||||||
|
this.code = code;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package org.dromara.pangu.member.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.dromara.pangu.member.domain.PgMemberLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员操作日志 Mapper
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
public interface PgMemberLogMapper extends BaseMapper<PgMemberLog> {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package org.dromara.pangu.member.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import org.dromara.pangu.member.domain.PgMemberLog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员操作日志 Service
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
public interface IPgMemberLogService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录操作日志
|
||||||
|
*
|
||||||
|
* @param memberId 会员ID
|
||||||
|
* @param operType 操作类型
|
||||||
|
* @param operTitle 操作标题
|
||||||
|
* @param operDesc 操作描述
|
||||||
|
*/
|
||||||
|
void log(Long memberId, String operType, String operTitle, String operDesc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录操作日志(带IP)
|
||||||
|
*
|
||||||
|
* @param memberId 会员ID
|
||||||
|
* @param operType 操作类型
|
||||||
|
* @param operTitle 操作标题
|
||||||
|
* @param operDesc 操作描述
|
||||||
|
* @param operIp 操作IP
|
||||||
|
*/
|
||||||
|
void log(Long memberId, String operType, String operTitle, String operDesc, String operIp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询会员操作日志
|
||||||
|
*
|
||||||
|
* @param memberId 会员ID
|
||||||
|
* @param pageNum 页码
|
||||||
|
* @param pageSize 每页条数
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
Page<PgMemberLog> queryByMemberId(Long memberId, int pageNum, int pageSize);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.dromara.pangu.member.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.dromara.common.core.utils.ServletUtils;
|
||||||
|
import org.dromara.pangu.member.domain.PgMemberLog;
|
||||||
|
import org.dromara.pangu.member.mapper.PgMemberLogMapper;
|
||||||
|
import org.dromara.pangu.member.service.IPgMemberLogService;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会员操作日志 Service 实现
|
||||||
|
*
|
||||||
|
* @author 湖北新华业务中台研发团队
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PgMemberLogServiceImpl implements IPgMemberLogService {
|
||||||
|
|
||||||
|
private final PgMemberLogMapper memberLogMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
public void log(Long memberId, String operType, String operTitle, String operDesc) {
|
||||||
|
String operIp = null;
|
||||||
|
try {
|
||||||
|
operIp = ServletUtils.getClientIP();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 获取IP失败时忽略
|
||||||
|
}
|
||||||
|
log(memberId, operType, operTitle, operDesc, operIp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
public void log(Long memberId, String operType, String operTitle, String operDesc, String operIp) {
|
||||||
|
try {
|
||||||
|
PgMemberLog logEntity = new PgMemberLog();
|
||||||
|
logEntity.setMemberId(memberId);
|
||||||
|
logEntity.setOperType(operType);
|
||||||
|
logEntity.setOperTitle(operTitle);
|
||||||
|
logEntity.setOperDesc(operDesc);
|
||||||
|
logEntity.setOperIp(operIp);
|
||||||
|
logEntity.setOperTime(new Date());
|
||||||
|
logEntity.setStatus("0");
|
||||||
|
memberLogMapper.insert(logEntity);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("记录会员操作日志失败: memberId={}, operType={}", memberId, operType, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Page<PgMemberLog> queryByMemberId(Long memberId, int pageNum, int pageSize) {
|
||||||
|
Page<PgMemberLog> page = new Page<>(pageNum, pageSize);
|
||||||
|
LambdaQueryWrapper<PgMemberLog> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(PgMemberLog::getMemberId, memberId)
|
||||||
|
.orderByDesc(PgMemberLog::getOperTime);
|
||||||
|
return memberLogMapper.selectPage(page, wrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
-- 会员操作日志表
|
||||||
|
-- 作者:湖北新华业务中台研发团队
|
||||||
|
-- 创建时间:2026-02-03
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `pg_member_log` (
|
||||||
|
`log_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '日志ID',
|
||||||
|
`member_id` BIGINT NOT NULL COMMENT '会员ID',
|
||||||
|
`oper_type` VARCHAR(20) NOT NULL COMMENT '操作类型',
|
||||||
|
`oper_title` VARCHAR(50) NOT NULL COMMENT '操作标题',
|
||||||
|
`oper_desc` VARCHAR(255) DEFAULT NULL COMMENT '操作描述',
|
||||||
|
`oper_ip` VARCHAR(50) DEFAULT NULL COMMENT '操作IP',
|
||||||
|
`oper_time` DATETIME NOT NULL COMMENT '操作时间',
|
||||||
|
`status` CHAR(1) DEFAULT '0' COMMENT '状态(0成功 1失败)',
|
||||||
|
PRIMARY KEY (`log_id`),
|
||||||
|
INDEX `idx_member_id` (`member_id`),
|
||||||
|
INDEX `idx_oper_time` (`oper_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='会员操作日志表';
|
||||||
Loading…
Reference in New Issue