diff --git a/maku-boot-system/src/main/java/net/maku/system/controller/SysLogOperateController.java b/maku-boot-system/src/main/java/net/maku/system/controller/SysLogOperateController.java
new file mode 100644
index 0000000..39beba1
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/controller/SysLogOperateController.java
@@ -0,0 +1,39 @@
+package net.maku.system.controller;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import net.maku.framework.common.utils.PageResult;
+import net.maku.framework.common.utils.Result;
+import net.maku.system.query.SysLogOperateQuery;
+import net.maku.system.service.SysLogOperateService;
+import net.maku.system.vo.SysLogOperateVO;
+import org.springdoc.core.annotations.ParameterObject;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@RestController
+@RequestMapping("sys/log/operate")
+@Tag(name = "操作日志")
+@AllArgsConstructor
+public class SysLogOperateController {
+ private final SysLogOperateService sysLogOperateService;
+
+ @GetMapping("page")
+ @Operation(summary = "分页")
+ @PreAuthorize("hasAuthority('sys:operate:all')")
+ public Result> page(@ParameterObject @Valid SysLogOperateQuery query) {
+ PageResult page = sysLogOperateService.page(query);
+
+ return Result.ok(page);
+ }
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/convert/SysLogOperateConvert.java b/maku-boot-system/src/main/java/net/maku/system/convert/SysLogOperateConvert.java
new file mode 100644
index 0000000..6312b2e
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/convert/SysLogOperateConvert.java
@@ -0,0 +1,26 @@
+package net.maku.system.convert;
+
+import net.maku.system.entity.SysLogOperateEntity;
+import net.maku.system.vo.SysLogOperateVO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@Mapper
+public interface SysLogOperateConvert {
+ SysLogOperateConvert INSTANCE = Mappers.getMapper(SysLogOperateConvert.class);
+
+ SysLogOperateEntity convert(SysLogOperateVO vo);
+
+ SysLogOperateVO convert(SysLogOperateEntity entity);
+
+ List convertList(List list);
+
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/dao/SysLogOperateDao.java b/maku-boot-system/src/main/java/net/maku/system/dao/SysLogOperateDao.java
new file mode 100644
index 0000000..7fe0d27
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/dao/SysLogOperateDao.java
@@ -0,0 +1,16 @@
+package net.maku.system.dao;
+
+import net.maku.framework.mybatis.dao.BaseDao;
+import net.maku.system.entity.SysLogOperateEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@Mapper
+public interface SysLogOperateDao extends BaseDao {
+
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/entity/SysLogOperateEntity.java b/maku-boot-system/src/main/java/net/maku/system/entity/SysLogOperateEntity.java
new file mode 100644
index 0000000..9b78b1d
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/entity/SysLogOperateEntity.java
@@ -0,0 +1,103 @@
+package net.maku.system.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+
+@Data
+@TableName("sys_log_operate")
+public class SysLogOperateEntity {
+ /**
+ * id
+ */
+ @TableId
+ private Long id;
+
+ /**
+ * 用户ID
+ */
+ private Long userId;
+
+ /**
+ * 操作人
+ */
+ private String realName;
+
+ /**
+ * 模块名
+ */
+ private String module;
+
+ /**
+ * 操作名
+ */
+ private String name;
+
+ /**
+ * 请求URI
+ */
+ private String reqUri;
+
+ /**
+ * 请求方法
+ */
+ private String reqMethod;
+
+ /**
+ * 请求参数
+ */
+ private String reqParams;
+
+ /**
+ * 操作IP
+ */
+ private String ip;
+
+ /**
+ * 登录地点
+ */
+ private String address;
+
+ /**
+ * User Agent
+ */
+ private String userAgent;
+
+ /**
+ * 操作类型
+ */
+ private Integer operateType;
+
+ /**
+ * 执行时长
+ */
+ private Integer duration;
+
+ /**
+ * 操作状态
+ */
+ private Integer status;
+
+ /**
+ * 返回消息
+ */
+ private String resultMsg;
+
+ /**
+ * 创建时间
+ */
+ @TableField(fill = FieldFill.INSERT)
+ private Date createTime;
+
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/query/SysLogOperateQuery.java b/maku-boot-system/src/main/java/net/maku/system/query/SysLogOperateQuery.java
new file mode 100644
index 0000000..defdb50
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/query/SysLogOperateQuery.java
@@ -0,0 +1,30 @@
+package net.maku.system.query;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import net.maku.framework.common.query.Query;
+
+/**
+ * 操作日志查询
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Schema(description = "操作日志查询")
+public class SysLogOperateQuery extends Query {
+ @Schema(description = "用户")
+ private String realName;
+
+ @Schema(description = "模块名")
+ private String module;
+
+ @Schema(description = "请求URI")
+ private String reqUri;
+
+ @Schema(description = "操作状态")
+ private Integer status;
+
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/service/SysLogOperateService.java b/maku-boot-system/src/main/java/net/maku/system/service/SysLogOperateService.java
new file mode 100644
index 0000000..5755813
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/service/SysLogOperateService.java
@@ -0,0 +1,18 @@
+package net.maku.system.service;
+
+import net.maku.framework.common.utils.PageResult;
+import net.maku.framework.mybatis.service.BaseService;
+import net.maku.system.entity.SysLogOperateEntity;
+import net.maku.system.query.SysLogOperateQuery;
+import net.maku.system.vo.SysLogOperateVO;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+public interface SysLogOperateService extends BaseService {
+
+ PageResult page(SysLogOperateQuery query);
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/service/impl/SysLogOperateServiceImpl.java b/maku-boot-system/src/main/java/net/maku/system/service/impl/SysLogOperateServiceImpl.java
new file mode 100644
index 0000000..be9b0e3
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/service/impl/SysLogOperateServiceImpl.java
@@ -0,0 +1,83 @@
+package net.maku.system.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import jakarta.annotation.PostConstruct;
+import lombok.AllArgsConstructor;
+import net.maku.framework.common.cache.RedisCache;
+import net.maku.framework.common.cache.RedisKeys;
+import net.maku.framework.common.utils.ExceptionUtils;
+import net.maku.framework.common.utils.PageResult;
+import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
+import net.maku.framework.operatelog.dto.OperateLogDTO;
+import net.maku.system.convert.SysLogOperateConvert;
+import net.maku.system.dao.SysLogOperateDao;
+import net.maku.system.entity.SysLogOperateEntity;
+import net.maku.system.query.SysLogOperateQuery;
+import net.maku.system.service.SysLogOperateService;
+import net.maku.system.vo.SysLogOperateVO;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@Service
+@AllArgsConstructor
+public class SysLogOperateServiceImpl extends BaseServiceImpl implements SysLogOperateService {
+ private final RedisCache redisCache;
+
+ @Override
+ public PageResult page(SysLogOperateQuery query) {
+ IPage page = baseMapper.selectPage(getPage(query), getWrapper(query));
+
+ return new PageResult<>(SysLogOperateConvert.INSTANCE.convertList(page.getRecords()), page.getTotal());
+ }
+
+ private LambdaQueryWrapper getWrapper(SysLogOperateQuery query) {
+ LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
+ wrapper.eq(query.getStatus() != null, SysLogOperateEntity::getStatus, query.getStatus());
+ wrapper.like(StrUtil.isNotBlank(query.getRealName()), SysLogOperateEntity::getRealName, query.getRealName());
+ wrapper.like(StrUtil.isNotBlank(query.getModule()), SysLogOperateEntity::getModule, query.getModule());
+ wrapper.like(StrUtil.isNotBlank(query.getReqUri()), SysLogOperateEntity::getReqUri, query.getReqUri());
+ wrapper.orderByDesc(SysLogOperateEntity::getId);
+ return wrapper;
+ }
+
+ /**
+ * 启动项目时,从Redis队列获取操作日志并保存
+ */
+ @PostConstruct
+ public void saveLog() {
+ ScheduledExecutorService scheduledService = ThreadUtil.createScheduledExecutor(1);
+
+ // 每隔10秒钟,执行一次
+ scheduledService.scheduleWithFixedDelay(() -> {
+ try {
+ String key = RedisKeys.getLogKey();
+ // 每次插入10条
+ int count = 10;
+ for (int i = 0; i < count; i++) {
+ OperateLogDTO log = (OperateLogDTO) redisCache.rightPop(key);
+ if (log == null) {
+ return;
+ }
+
+ SysLogOperateEntity entity = BeanUtil.copyProperties(log, SysLogOperateEntity.class);
+ baseMapper.insert(entity);
+ }
+ } catch (Exception e) {
+ log.error("SysLogOperateServiceImpl.saveLog Error:" + ExceptionUtils.getExceptionMessage(e));
+ }
+ }, 1, 10, TimeUnit.SECONDS);
+ }
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/java/net/maku/system/vo/SysLogOperateVO.java b/maku-boot-system/src/main/java/net/maku/system/vo/SysLogOperateVO.java
new file mode 100644
index 0000000..c261f30
--- /dev/null
+++ b/maku-boot-system/src/main/java/net/maku/system/vo/SysLogOperateVO.java
@@ -0,0 +1,71 @@
+package net.maku.system.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import net.maku.framework.common.utils.DateUtils;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 操作日志
+ *
+ * @author 阿沐 babamu@126.com
+ * MAKU
+ */
+@Data
+@Schema(description = "操作日志")
+public class SysLogOperateVO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Schema(description = "id")
+ private Long id;
+
+ @Schema(description = "用户ID")
+ private Long userId;
+
+ @Schema(description = "操作人")
+ private String realName;
+
+ @Schema(description = "模块名")
+ private String module;
+
+ @Schema(description = "操作名")
+ private String name;
+
+ @Schema(description = "请求URI")
+ private String reqUri;
+
+ @Schema(description = "请求方法")
+ private String reqMethod;
+
+ @Schema(description = "请求参数")
+ private String reqParams;
+
+ @Schema(description = "操作IP")
+ private String ip;
+
+ @Schema(description = "登录地点")
+ private String address;
+
+ @Schema(description = "User Agent")
+ private String userAgent;
+
+ @Schema(description = "操作类型")
+ private Integer operateType;
+
+ @Schema(description = "执行时长")
+ private Integer duration;
+
+ @Schema(description = "操作状态")
+ private Integer status;
+
+ @Schema(description = "返回消息")
+ private String resultMsg;
+
+ @Schema(description = "创建时间")
+ @JsonFormat(pattern = DateUtils.DATE_TIME_PATTERN)
+ private Date createTime;
+
+}
\ No newline at end of file
diff --git a/maku-boot-system/src/main/resources/mapper/SysLogOperateDao.xml b/maku-boot-system/src/main/resources/mapper/SysLogOperateDao.xml
new file mode 100644
index 0000000..d0fd093
--- /dev/null
+++ b/maku-boot-system/src/main/resources/mapper/SysLogOperateDao.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file