Commit 1768d27e1154c1d5486f0c6e4cd3107ddbeda4ac

Authored by YunaiV
1 parent 2fccaa2b

完善新操作日志的页面修改

Showing 34 changed files with 649 additions and 664 deletions
... ... @@ -22,7 +22,7 @@
22 22 <maven.compiler.target>${java.version}</maven.compiler.target>
23 23 <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
24 24 <!-- 统一依赖管理 -->
25   - <spring.boot.version>2.4.1</spring.boot.version>
  25 + <spring.boot.version>2.4.2</spring.boot.version>
26 26  
27 27 <!-- <ruoyi.version>3.3.0</ruoyi.version>-->
28 28 <!-- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>-->
... ...
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
... ... @@ -23,28 +23,12 @@ import com.ruoyi.system.service.ISysOperLogService;
23 23 *
24 24 * @author ruoyi
25 25 */
26   -@RestController
27   -@RequestMapping("/monitor/operlog")
  26 +
28 27 public class SysOperlogController extends BaseController {
29 28  
30 29 @Autowired
31 30 private ISysOperLogService operLogService;
32 31  
33   - @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
34   - @GetMapping("/list")
35   - public TableDataInfo list(SysOperLog operLog) {
36   - startPage();
37   - List<SysOperLog> list = operLogService.selectOperLogList(operLog);
38   - return getDataTable(list);
39   - }
40   -
41   - @Log(title = "操作日志", businessType = BusinessType.EXPORT)
42   - @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
43   - @GetMapping("/export")
44   - public AjaxResult export(SysOperLog operLog) {
45   - List<SysOperLog> list = operLogService.selectOperLogList(operLog);
46   - ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
47   - return util.exportExcel(list, "操作日志");
48   - }
  32 +
49 33  
50 34 }
... ...
ruoyi-common/pom.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project xmlns="http://maven.apache.org/POM/4.0.0"
3   - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4   - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5   - <parent>
6   - <artifactId>ruoyi</artifactId>
7   - <groupId>com.ruoyi</groupId>
8   - <version>3.3.0</version>
9   - </parent>
10   - <modelVersion>4.0.0</modelVersion>
11   -
12   - <artifactId>ruoyi-common</artifactId>
13   -
14   - <description>
15   - common通用工具
16   - </description>
17   -
18   - <dependencies>
19   -
20   - <!-- yml解析器 -->
21   - <dependency>
22   - <groupId>org.yaml</groupId>
23   - <artifactId>snakeyaml</artifactId>
24   - </dependency>
25   -
26   - <!-- 解析客户端操作系统、浏览器等 -->
27   - <dependency>
28   - <groupId>eu.bitwalker</groupId>
29   - <artifactId>UserAgentUtils</artifactId>
30   - </dependency>
31   -
32   -
33   - </dependencies>
34   -
35   -</project>
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java deleted
1   -package com.ruoyi.common.annotation;
2   -
3   -import java.lang.annotation.Documented;
4   -import java.lang.annotation.ElementType;
5   -import java.lang.annotation.Retention;
6   -import java.lang.annotation.RetentionPolicy;
7   -import java.lang.annotation.Target;
8   -import com.ruoyi.common.enums.BusinessType;
9   -import com.ruoyi.common.enums.OperatorType;
10   -
11   -/**
12   - * 自定义操作日志记录注解
13   - *
14   - * @author ruoyi
15   - *
16   - */
17   -@Target({ ElementType.PARAMETER, ElementType.METHOD })
18   -@Retention(RetentionPolicy.RUNTIME)
19   -@Documented
20   -public @interface Log
21   -{
22   - /**
23   - * 模块
24   - */
25   - public String title() default "";
26   -
27   - /**
28   - * 功能
29   - */
30   - public BusinessType businessType() default BusinessType.OTHER;
31   -
32   - /**
33   - * 操作人类别
34   - */
35   - public OperatorType operatorType() default OperatorType.MANAGE;
36   -
37   - /**
38   - * 是否保存请求的参数
39   - */
40   - public boolean isSaveRequestData() default true;
41   -}
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java deleted
1   -package com.ruoyi.framework.aspectj;
2   -
3   -import java.lang.reflect.Method;
4   -import java.util.Collection;
5   -import java.util.Iterator;
6   -import java.util.Map;
7   -import javax.servlet.http.HttpServletRequest;
8   -import javax.servlet.http.HttpServletResponse;
9   -
10   -import org.aspectj.lang.JoinPoint;
11   -import org.aspectj.lang.Signature;
12   -import org.aspectj.lang.annotation.AfterReturning;
13   -import org.aspectj.lang.annotation.AfterThrowing;
14   -import org.aspectj.lang.annotation.Aspect;
15   -import org.aspectj.lang.annotation.Pointcut;
16   -import org.aspectj.lang.reflect.MethodSignature;
17   -import org.slf4j.Logger;
18   -import org.slf4j.LoggerFactory;
19   -import org.springframework.stereotype.Component;
20   -import org.springframework.web.multipart.MultipartFile;
21   -import org.springframework.web.servlet.HandlerMapping;
22   -import com.alibaba.fastjson.JSON;
23   -import com.ruoyi.common.annotation.Log;
24   -import com.ruoyi.common.core.domain.model.LoginUser;
25   -import com.ruoyi.common.enums.BusinessStatus;
26   -import com.ruoyi.common.enums.HttpMethod;
27   -import com.ruoyi.common.utils.ServletUtils;
28   -import com.ruoyi.common.utils.StringUtils;
29   -import com.ruoyi.common.utils.ip.IpUtils;
30   -import com.ruoyi.common.utils.spring.SpringUtils;
31   -import com.ruoyi.framework.manager.AsyncManager;
32   -import com.ruoyi.framework.manager.factory.AsyncFactory;
33   -import com.ruoyi.framework.web.service.TokenService;
34   -import com.ruoyi.system.domain.SysOperLog;
35   -
36   -/**
37   - * 操作日志记录处理
38   - *
39   - * @author ruoyi
40   - */
41   -@Aspect
42   -@Component
43   -public class LogAspect {
44   - private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
45   -
46   - // 配置织入点
47   - @Pointcut("@annotation(com.ruoyi.common.annotation.Log)")
48   - public void logPointCut() {
49   - }
50   -
51   - /**
52   - * 处理完请求后执行
53   - *
54   - * @param joinPoint 切点
55   - */
56   - @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
57   - public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
58   - handleLog(joinPoint, null, jsonResult);
59   - }
60   -
61   - /**
62   - * 拦截异常操作
63   - *
64   - * @param joinPoint 切点
65   - * @param e 异常
66   - */
67   - @AfterThrowing(value = "logPointCut()", throwing = "e")
68   - public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
69   - handleLog(joinPoint, e, null);
70   - }
71   -
72   - protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
73   - try {
74   - // 获得注解
75   - Log controllerLog = getAnnotationLog(joinPoint);
76   - if (controllerLog == null) {
77   - return;
78   - }
79   -
80   - // 获取当前的用户
81   - LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
82   -
83   - // *========数据库日志=========*//
84   - SysOperLog operLog = new SysOperLog();
85   - operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
86   - // 请求的地址
87   - String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
88   - operLog.setOperIp(ip);
89   - // 返回参数
90   - operLog.setJsonResult(JSON.toJSONString(jsonResult));
91   -
92   - operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
93   - if (loginUser != null) {
94   - operLog.setOperName(loginUser.getUsername());
95   - }
96   -
97   - if (e != null) {
98   - operLog.setStatus(BusinessStatus.FAIL.ordinal());
99   - operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
100   - }
101   - // 设置方法名称
102   - String className = joinPoint.getTarget().getClass().getName();
103   - String methodName = joinPoint.getSignature().getName();
104   - operLog.setMethod(className + "." + methodName + "()");
105   - // 设置请求方式
106   - operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
107   - // 处理设置注解上的参数
108   - getControllerMethodDescription(joinPoint, controllerLog, operLog);
109   - // 保存数据库
110   - AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
111   - } catch (Exception exp) {
112   - // 记录本地异常日志
113   - log.error("==前置通知异常==");
114   - log.error("异常信息:{}", exp.getMessage());
115   - exp.printStackTrace();
116   - }
117   - }
118   -
119   - /**
120   - * 参数拼装
121   - */
122   - private String argsArrayToString(Object[] paramsArray) {
123   - String params = "";
124   - if (paramsArray != null && paramsArray.length > 0) {
125   - for (int i = 0; i < paramsArray.length; i++) {
126   - if (!isFilterObject(paramsArray[i])) {
127   - Object jsonObj = JSON.toJSON(paramsArray[i]);
128   - params += jsonObj.toString() + " ";
129   - }
130   - }
131   - }
132   - return params.trim();
133   - }
134   -
135   - /**
136   - * 判断是否需要过滤的对象。
137   - *
138   - * @param o 对象信息。
139   - * @return 如果是需要过滤的对象,则返回true;否则返回false。
140   - */
141   - @SuppressWarnings("rawtypes")
142   - public boolean isFilterObject(final Object o) {
143   - Class<?> clazz = o.getClass();
144   - if (clazz.isArray()) {
145   - return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
146   - } else if (Collection.class.isAssignableFrom(clazz)) {
147   - Collection collection = (Collection) o;
148   - for (Iterator iter = collection.iterator(); iter.hasNext(); ) {
149   - return iter.next() instanceof MultipartFile;
150   - }
151   - } else if (Map.class.isAssignableFrom(clazz)) {
152   - Map map = (Map) o;
153   - for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
154   - Map.Entry entry = (Map.Entry) iter.next();
155   - return entry.getValue() instanceof MultipartFile;
156   - }
157   - }
158   - return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
159   - }
160   -}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java deleted
1   -package com.ruoyi.framework.config;
2   -
3   -import java.util.TimeZone;
4   -
5   -import org.mybatis.spring.annotation.MapperScan;
6   -import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
7   -import org.springframework.context.annotation.Bean;
8   -import org.springframework.context.annotation.Configuration;
9   -import org.springframework.context.annotation.EnableAspectJAutoProxy;
10   -
11   -/**
12   - * 程序注解配置
13   - *
14   - * @author ruoyi
15   - */
16   -@Configuration
17   -// 表示通过aop框架暴露该代理对象,AopContext能够访问
18   -@EnableAspectJAutoProxy(exposeProxy = true)
19   -// 指定要扫描的Mapper类的包的路径
20   -@MapperScan("com.ruoyi.**.mapper")
21   -public class ApplicationConfig {
22   - /**
23   - * 时区配置
24   - */
25   - @Bean
26   - public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
27   - return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
28   - }
29   -}
ruoyi-ui/src/api/monitor/operlog.js renamed to ruoyi-ui/src/api/system/operatelog.js
1   -import request from '@/utils/request'
2   -
3   -// 查询操作日志列表
4   -export function list(query) {
5   - return request({
6   - url: '/monitor/operlog/list',
7   - method: 'get',
8   - params: query
9   - })
10   -}
11   -
12   -// 删除操作日志
13   -export function delOperlog(operId) {
14   - return request({
15   - url: '/monitor/operlog/' + operId,
16   - method: 'delete'
17   - })
18   -}
19   -
20   -// 清空操作日志
21   -export function cleanOperlog() {
22   - return request({
23   - url: '/monitor/operlog/clean',
24   - method: 'delete'
25   - })
26   -}
27   -
28   -// 导出操作日志
29   -export function exportOperlog(query) {
30   - return request({
31   - url: '/monitor/operlog/export',
32   - method: 'get',
33   - params: query
34   - })
35   -}
36 1 \ No newline at end of file
  2 +import request from '@/utils/request'
  3 +
  4 +// 查询操作日志列表
  5 +export function listOperateLog(query) {
  6 + return request({
  7 + url: '/system/operate-log/page',
  8 + method: 'get',
  9 + params: query
  10 + })
  11 +}
  12 +
  13 +// 导出操作日志
  14 +export function exportOperateLog(query) {
  15 + return request({
  16 + url: '/system/operate-log/export',
  17 + method: 'get',
  18 + params: query
  19 + })
  20 +}
... ...
ruoyi-ui/src/main.js
... ... @@ -23,6 +23,7 @@ import RightToolbar from &quot;@/components/RightToolbar&quot;
23 23 // 代码高亮插件
24 24 import hljs from 'highlight.js'
25 25 import 'highlight.js/styles/github-gist.css'
  26 +import {DICT_TYPE, getDictDataLabel, getDictDatas} from "@/utils/dict";
26 27  
27 28 // 全局方法挂载
28 29 Vue.prototype.getDicts = getDicts
... ... @@ -32,6 +33,9 @@ Vue.prototype.resetForm = resetForm
32 33 Vue.prototype.addDateRange = addDateRange
33 34 Vue.prototype.selectDictLabel = selectDictLabel
34 35 Vue.prototype.selectDictLabels = selectDictLabels
  36 +Vue.prototype.getDictDatas = getDictDatas
  37 +Vue.prototype.getDictDataLabel = getDictDataLabel
  38 +Vue.prototype.DICT_TYPE = DICT_TYPE
35 39 Vue.prototype.download = download
36 40 Vue.prototype.downloadExcel = downloadExcel
37 41 Vue.prototype.handleTree = handleTree
... ...
ruoyi-ui/src/utils/dict.js
... ... @@ -12,6 +12,7 @@ export const DICT_TYPE = {
12 12 SYS_DATA_SCOPE: 'sys_data_scope',
13 13 SYS_USER_SEX: 'sys_user_sex',
14 14 SYS_NOTICE_TYPE: 'sys_notice_type',
  15 + SYS_OPERATE_TYPE: 'sys_operate_type'
15 16 }
16 17  
17 18 /**
... ...
ruoyi-ui/src/views/monitor/operlog/index.vue renamed to ruoyi-ui/src/views/system/operatelog/index.vue
1   -<template>
2   - <div class="app-container">
3   - <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4   - <el-form-item label="系统模块" prop="title">
5   - <el-input
6   - v-model="queryParams.title"
7   - placeholder="请输入系统模块"
8   - clearable
9   - style="width: 240px;"
10   - size="small"
11   - @keyup.enter.native="handleQuery"
12   - />
13   - </el-form-item>
14   - <el-form-item label="操作人员" prop="operName">
15   - <el-input
16   - v-model="queryParams.operName"
17   - placeholder="请输入操作人员"
18   - clearable
19   - style="width: 240px;"
20   - size="small"
21   - @keyup.enter.native="handleQuery"
22   - />
23   - </el-form-item>
24   - <el-form-item label="类型" prop="businessType">
25   - <el-select
26   - v-model="queryParams.businessType"
27   - placeholder="操作类型"
28   - clearable
29   - size="small"
30   - style="width: 240px"
31   - >
32   - <el-option
33   - v-for="dict in typeOptions"
34   - :key="dict.dictValue"
35   - :label="dict.dictLabel"
36   - :value="dict.dictValue"
37   - />
38   - </el-select>
39   - </el-form-item>
40   - <el-form-item label="状态" prop="status">
41   - <el-select
42   - v-model="queryParams.status"
43   - placeholder="操作状态"
44   - clearable
45   - size="small"
46   - style="width: 240px"
47   - >
48   - <el-option
49   - v-for="dict in statusOptions"
50   - :key="dict.dictValue"
51   - :label="dict.dictLabel"
52   - :value="dict.dictValue"
53   - />
54   - </el-select>
55   - </el-form-item>
56   - <el-form-item label="操作时间">
57   - <el-date-picker
58   - v-model="dateRange"
59   - size="small"
60   - style="width: 240px"
61   - value-format="yyyy-MM-dd"
62   - type="daterange"
63   - range-separator="-"
64   - start-placeholder="开始日期"
65   - end-placeholder="结束日期"
66   - ></el-date-picker>
67   - </el-form-item>
68   - <el-form-item>
69   - <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
70   - <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
71   - </el-form-item>
72   - </el-form>
73   -
74   - <el-row :gutter="10" class="mb8">
75   - <el-col :span="1.5">
76   - <el-button
77   - type="danger"
78   - icon="el-icon-delete"
79   - size="mini"
80   - :disabled="multiple"
81   - @click="handleDelete"
82   - v-hasPermi="['monitor:operlog:remove']"
83   - >删除</el-button>
84   - </el-col>
85   - <el-col :span="1.5">
86   - <el-button
87   - type="danger"
88   - icon="el-icon-delete"
89   - size="mini"
90   - @click="handleClean"
91   - v-hasPermi="['monitor:operlog:remove']"
92   - >清空</el-button>
93   - </el-col>
94   - <el-col :span="1.5">
95   - <el-button
96   - type="warning"
97   - icon="el-icon-download"
98   - size="mini"
99   - @click="handleExport"
100   - v-hasPermi="['system:config:export']"
101   - >导出</el-button>
102   - </el-col>
103   - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
104   - </el-row>
105   -
106   - <el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
107   - <el-table-column type="selection" width="55" align="center" />
108   - <el-table-column label="日志编号" align="center" prop="operId" />
109   - <el-table-column label="系统模块" align="center" prop="title" />
110   - <el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" />
111   - <el-table-column label="请求方式" align="center" prop="requestMethod" />
112   - <el-table-column label="操作人员" align="center" prop="operName" />
113   - <el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
114   - <el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
115   - <el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" />
116   - <el-table-column label="操作日期" align="center" prop="operTime" width="180">
117   - <template slot-scope="scope">
118   - <span>{{ parseTime(scope.row.operTime) }}</span>
119   - </template>
120   - </el-table-column>
121   - <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
122   - <template slot-scope="scope">
123   - <el-button
124   - size="mini"
125   - type="text"
126   - icon="el-icon-view"
127   - @click="handleView(scope.row,scope.index)"
128   - v-hasPermi="['monitor:operlog:query']"
129   - >详细</el-button>
130   - </template>
131   - </el-table-column>
132   - </el-table>
133   -
134   - <pagination
135   - v-show="total>0"
136   - :total="total"
137   - :page.sync="queryParams.pageNum"
138   - :limit.sync="queryParams.pageSize"
139   - @pagination="getList"
140   - />
141   -
142   - <!-- 操作日志详细 -->
143   - <el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
144   - <el-form ref="form" :model="form" label-width="100px" size="mini">
145   - <el-row>
146   - <el-col :span="12">
147   - <el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
148   - <el-form-item
149   - label="登录信息:"
150   - >{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
151   - </el-col>
152   - <el-col :span="12">
153   - <el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
154   - <el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
155   - </el-col>
156   - <el-col :span="24">
157   - <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
158   - </el-col>
159   - <el-col :span="24">
160   - <el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
161   - </el-col>
162   - <el-col :span="24">
163   - <el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
164   - </el-col>
165   - <el-col :span="12">
166   - <el-form-item label="操作状态:">
167   - <div v-if="form.status === 0">正常</div>
168   - <div v-else-if="form.status === 1">失败</div>
169   - </el-form-item>
170   - </el-col>
171   - <el-col :span="12">
172   - <el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
173   - </el-col>
174   - <el-col :span="24">
175   - <el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
176   - </el-col>
177   - </el-row>
178   - </el-form>
179   - <div slot="footer" class="dialog-footer">
180   - <el-button @click="open = false">关 闭</el-button>
181   - </div>
182   - </el-dialog>
183   - </div>
184   -</template>
185   -
186   -<script>
187   -import { list, delOperlog, cleanOperlog, exportOperlog } from "@/api/monitor/operlog";
188   -
189   -export default {
190   - name: "Operlog",
191   - data() {
192   - return {
193   - // 遮罩层
194   - loading: true,
195   - // 选中数组
196   - ids: [],
197   - // 非多个禁用
198   - multiple: true,
199   - // 显示搜索条件
200   - showSearch: true,
201   - // 总条数
202   - total: 0,
203   - // 表格数据
204   - list: [],
205   - // 是否显示弹出层
206   - open: false,
207   - // 类型数据字典
208   - typeOptions: [],
209   - // 类型数据字典
210   - statusOptions: [],
211   - // 日期范围
212   - dateRange: [],
213   - // 表单参数
214   - form: {},
215   - // 查询参数
216   - queryParams: {
217   - pageNum: 1,
218   - pageSize: 10,
219   - title: undefined,
220   - operName: undefined,
221   - businessType: undefined,
222   - status: undefined
223   - }
224   - };
225   - },
226   - created() {
227   - this.getList();
228   - this.getDicts("sys_oper_type").then(response => {
229   - this.typeOptions = response.data;
230   - });
231   - this.getDicts("sys_common_status").then(response => {
232   - this.statusOptions = response.data;
233   - });
234   - },
235   - methods: {
236   - /** 查询登录日志 */
237   - getList() {
238   - this.loading = true;
239   - list(this.addDateRange(this.queryParams, this.dateRange)).then( response => {
240   - this.list = response.rows;
241   - this.total = response.total;
242   - this.loading = false;
243   - }
244   - );
245   - },
246   - // 操作日志状态字典翻译
247   - statusFormat(row, column) {
248   - return this.selectDictLabel(this.statusOptions, row.status);
249   - },
250   - // 操作日志类型字典翻译
251   - typeFormat(row, column) {
252   - return this.selectDictLabel(this.typeOptions, row.businessType);
253   - },
254   - /** 搜索按钮操作 */
255   - handleQuery() {
256   - this.queryParams.pageNum = 1;
257   - this.getList();
258   - },
259   - /** 重置按钮操作 */
260   - resetQuery() {
261   - this.dateRange = [];
262   - this.resetForm("queryForm");
263   - this.handleQuery();
264   - },
265   - // 多选框选中数据
266   - handleSelectionChange(selection) {
267   - this.ids = selection.map(item => item.operId)
268   - this.multiple = !selection.length
269   - },
270   - /** 详细按钮操作 */
271   - handleView(row) {
272   - this.open = true;
273   - this.form = row;
274   - },
275   - /** 删除按钮操作 */
276   - handleDelete(row) {
277   - const operIds = row.operId || this.ids;
278   - this.$confirm('是否确认删除日志编号为"' + operIds + '"的数据项?', "警告", {
279   - confirmButtonText: "确定",
280   - cancelButtonText: "取消",
281   - type: "warning"
282   - }).then(function() {
283   - return delOperlog(operIds);
284   - }).then(() => {
285   - this.getList();
286   - this.msgSuccess("删除成功");
287   - })
288   - },
289   - /** 清空按钮操作 */
290   - handleClean() {
291   - this.$confirm('是否确认清空所有操作日志数据项?', "警告", {
292   - confirmButtonText: "确定",
293   - cancelButtonText: "取消",
294   - type: "warning"
295   - }).then(function() {
296   - return cleanOperlog();
297   - }).then(() => {
298   - this.getList();
299   - this.msgSuccess("清空成功");
300   - })
301   - },
302   - /** 导出按钮操作 */
303   - handleExport() {
304   - const queryParams = this.queryParams;
305   - this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
306   - confirmButtonText: "确定",
307   - cancelButtonText: "取消",
308   - type: "warning"
309   - }).then(function() {
310   - return exportOperlog(queryParams);
311   - }).then(response => {
312   - this.download(response.msg);
313   - })
314   - }
315   - }
316   -};
317   -</script>
318   -
  1 +<template>
  2 + <div class="app-container">
  3 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
  4 + <el-form-item label="系统模块" prop="title">
  5 + <el-input
  6 + v-model="queryParams.title"
  7 + placeholder="请输入系统模块"
  8 + clearable
  9 + style="width: 240px;"
  10 + size="small"
  11 + @keyup.enter.native="handleQuery"
  12 + />
  13 + </el-form-item>
  14 + <el-form-item label="操作人员" prop="operName">
  15 + <el-input
  16 + v-model="queryParams.operName"
  17 + placeholder="请输入操作人员"
  18 + clearable
  19 + style="width: 240px;"
  20 + size="small"
  21 + @keyup.enter.native="handleQuery"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="类型" prop="type">
  25 + <el-select
  26 + v-model="queryParams.type"
  27 + placeholder="操作类型"
  28 + clearable
  29 + size="small"
  30 + style="width: 240px"
  31 + >
  32 + <el-option
  33 + v-for="dict in this.getDictDatas(DICT_TYPE.SYS_OPERATE_TYPE)"
  34 + :key="parseInt(dict.value)"
  35 + :label="dict.label"
  36 + :value="parseInt(dict.value)"
  37 + />
  38 + </el-select>
  39 + </el-form-item>
  40 + <el-form-item label="状态" prop="status">
  41 + <el-select
  42 + v-model="queryParams.success"
  43 + placeholder="操作状态"
  44 + clearable
  45 + size="small"
  46 + style="width: 240px"
  47 + >
  48 + <el-option
  49 + :key="true"
  50 + label="成功"
  51 + :value="true"
  52 + />
  53 + <el-option
  54 + :key="false"
  55 + label="失败"
  56 + :value="false"
  57 + />
  58 + </el-select>
  59 + </el-form-item>
  60 + <el-form-item label="操作时间">
  61 + <el-date-picker
  62 + v-model="dateRange"
  63 + size="small"
  64 + style="width: 240px"
  65 + value-format="yyyy-MM-dd"
  66 + type="daterange"
  67 + range-separator="-"
  68 + start-placeholder="开始日期"
  69 + end-placeholder="结束日期"
  70 + ></el-date-picker>
  71 + </el-form-item>
  72 + <el-form-item>
  73 + <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  74 + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
  75 + </el-form-item>
  76 + </el-form>
  77 +
  78 + <el-row :gutter="10" class="mb8">
  79 + <el-col :span="1.5">
  80 + <el-button
  81 + type="warning"
  82 + icon="el-icon-download"
  83 + size="mini"
  84 + @click="handleExport"
  85 + v-hasPermi="['system:config:export']"
  86 + >导出</el-button>
  87 + </el-col>
  88 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  89 + </el-row>
  90 +
  91 + <el-table v-loading="loading" :data="list">
  92 + <el-table-column label="日志编号" align="center" prop="id" />
  93 + <el-table-column label="操作模块" align="center" prop="module" />
  94 + <el-table-column label="操作名" align="center" prop="name" width="180" />
  95 + <el-table-column label="操作类型" align="center" prop="type">
  96 + <template slot-scope="scope">
  97 + <span>{{ getDictDataLabel(DICT_TYPE.SYS_OPERATE_TYPE, scope.row.type) }}</span>
  98 + </template>
  99 + </el-table-column>
  100 + <el-table-column label="操作人" align="center" prop="userNickname" />
  101 + <el-table-column label="操作结果" align="center" prop="status">
  102 + <template slot-scope="scope">
  103 + <span>{{ scope.row.resultCode === 0 ? '成功' : '失败' }}</span>
  104 + </template>
  105 + </el-table-column>
  106 + <el-table-column label="操作日期" align="center" prop="startTime" width="180">
  107 + <template slot-scope="scope">
  108 + <span>{{ parseTime(scope.row.startTime) }}</span>
  109 + </template>
  110 + </el-table-column>
  111 + <el-table-column label="执行时长" align="center" prop="startTime">
  112 + <template slot-scope="scope">
  113 + <span>{{ scope.row.duration }} ms</span>
  114 + </template>
  115 + </el-table-column>
  116 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  117 + <template slot-scope="scope">
  118 + <el-button
  119 + size="mini"
  120 + type="text"
  121 + icon="el-icon-view"
  122 + @click="handleView(scope.row,scope.index)"
  123 + v-hasPermi="['system:operate-log:query']"
  124 + >详细</el-button>
  125 + </template>
  126 + </el-table-column>
  127 + </el-table>
  128 +
  129 + <pagination
  130 + v-show="total>0"
  131 + :total="total"
  132 + :page.sync="queryParams.pageNo"
  133 + :limit.sync="queryParams.pageSize"
  134 + @pagination="getList"
  135 + />
  136 +
  137 + <!-- 操作日志详细 -->
  138 + <el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
  139 + <el-form ref="form" :model="form" label-width="100px" size="mini">
  140 + <el-row>
  141 + <el-col :span="12">
  142 + <el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
  143 + <el-form-item
  144 + label="登录信息:"
  145 + >{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
  146 + </el-col>
  147 + <el-col :span="12">
  148 + <el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
  149 + <el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
  150 + </el-col>
  151 + <el-col :span="24">
  152 + <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
  153 + </el-col>
  154 + <el-col :span="24">
  155 + <el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
  156 + </el-col>
  157 + <el-col :span="24">
  158 + <el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
  159 + </el-col>
  160 + <el-col :span="12">
  161 + <el-form-item label="操作状态:">
  162 + <div v-if="form.status === 0">正常</div>
  163 + <div v-else-if="form.status === 1">失败</div>
  164 + </el-form-item>
  165 + </el-col>
  166 + <el-col :span="12">
  167 + <el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
  168 + </el-col>
  169 + <el-col :span="24">
  170 + <el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
  171 + </el-col>
  172 + </el-row>
  173 + </el-form>
  174 + <div slot="footer" class="dialog-footer">
  175 + <el-button @click="open = false">关 闭</el-button>
  176 + </div>
  177 + </el-dialog>
  178 + </div>
  179 +</template>
  180 +
  181 +<script>
  182 +import { listOperateLog, exportOperateLog } from "@/api/system/operatelog";
  183 +
  184 +export default {
  185 + name: "Operlog",
  186 + data() {
  187 + return {
  188 + // 遮罩层
  189 + loading: true,
  190 + // 显示搜索条件
  191 + showSearch: true,
  192 + // 总条数
  193 + total: 0,
  194 + // 表格数据
  195 + list: [],
  196 + // 是否显示弹出层
  197 + open: false,
  198 + // 类型数据字典
  199 + typeOptions: [],
  200 + // 类型数据字典
  201 + statusOptions: [],
  202 + // 日期范围
  203 + dateRange: [],
  204 + // 表单参数
  205 + form: {},
  206 + // 查询参数
  207 + queryParams: {
  208 + pageNo: 1,
  209 + pageSize: 10,
  210 + title: undefined,
  211 + operName: undefined,
  212 + businessType: undefined,
  213 + status: undefined
  214 + },
  215 +
  216 + };
  217 + },
  218 + created() {
  219 + this.getList();
  220 + },
  221 + methods: {
  222 + /** 查询登录日志 */
  223 + getList() {
  224 + this.loading = true;
  225 + listOperateLog(this.addDateRange(this.queryParams, [
  226 + this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
  227 + this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
  228 + ])).then( response => {
  229 + this.list = response.data.list;
  230 + this.total = response.data.total;
  231 + this.loading = false;
  232 + }
  233 + );
  234 + },
  235 + // 操作日志状态字典翻译
  236 + statusFormat(row, column) {
  237 + return this.selectDictLabel(this.statusOptions, row.status);
  238 + },
  239 + // 操作日志类型字典翻译
  240 + typeFormat(row, column) {
  241 + return this.selectDictLabel(this.typeOptions, row.businessType);
  242 + },
  243 + /** 搜索按钮操作 */
  244 + handleQuery() {
  245 + this.queryParams.pageNo = 1;
  246 + this.getList();
  247 + },
  248 + /** 重置按钮操作 */
  249 + resetQuery() {
  250 + this.dateRange = [];
  251 + this.resetForm("queryForm");
  252 + this.handleQuery();
  253 + },
  254 + /** 详细按钮操作 */
  255 + handleView(row) {
  256 + this.open = true;
  257 + this.form = row;
  258 + },
  259 + /** 导出按钮操作 */
  260 + handleExport() {
  261 + const queryParams = this.queryParams;
  262 + this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
  263 + confirmButtonText: "确定",
  264 + cancelButtonText: "取消",
  265 + type: "warning"
  266 + }).then(function() {
  267 + return exportOperateLog(queryParams);
  268 + }).then(response => {
  269 + this.download(response.msg);
  270 + })
  271 + }
  272 + }
  273 +};
  274 +</script>
  275 +
... ...
sql/ruoyi-vue-pro-data.sql 0 → 100644
  1 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (1, 1, '男', '1', 'sys_user_sex', 0, '性别男', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 05:48:53', b'0');
  2 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (2, 2, '女', '2', 'sys_user_sex', 0, '性别女', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 05:48:55', b'0');
  3 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (8, 1, '正常', '0', 'sys_job_status', 0, '正常状态', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  4 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (9, 2, '暂停', '1', 'sys_job_status', 0, '停用状态', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  5 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (10, 1, '默认', 'DEFAULT', 'sys_job_group', 0, '默认分组', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  6 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (11, 2, '系统', 'SYSTEM', 'sys_job_group', 0, '系统分组', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  7 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (12, 1, '是', 'Y', 'sys_yes_no', 0, '系统默认是', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  8 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (13, 2, '否', 'N', 'sys_yes_no', 0, '系统默认否', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  9 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (14, 1, '通知', '1', 'sys_notice_type', 0, '通知', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  10 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (15, 2, '公告', '2', 'sys_notice_type', 0, '公告', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 00:02:28', b'0');
  11 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (16, 0, '其它', '0', 'sys_operate_type', 0, '其它操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:51:12', b'0');
  12 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (17, 1, '查询', '1', 'sys_operate_type', 0, '查询操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:51:10', b'0');
  13 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (18, 2, '新增', '2', 'sys_operate_type', 0, '新增操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:51:17', b'0');
  14 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (19, 3, '修改', '3', 'sys_operate_type', 0, '修改操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:51:20', b'0');
  15 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (20, 4, '删除', '4', 'sys_operate_type', 0, '删除操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:51:24', b'0');
  16 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (22, 5, '导出', '5', 'sys_operate_type', 0, '导出操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:49:20', b'0');
  17 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (23, 6, '导入', '6', 'sys_operate_type', 0, '导入操作', 'admin', '2021-01-05 17:03:48', '', '2021-01-16 13:49:24', b'0');
  18 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (27, 1, '开启', '0', 'sys_common_status', 0, '开启状态', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 02:57:12', b'0');
  19 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (28, 2, '关闭', '1', 'sys_common_status', 0, '关闭状态', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 05:48:32', b'0');
  20 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (29, 1, '目录', '1', 'sys_menu_type', 0, '目录', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 13:33:30', b'0');
  21 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (30, 2, '菜单', '2', 'sys_menu_type', 0, '菜单', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 13:33:35', b'0');
  22 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (31, 3, '按钮', '3', 'sys_menu_type', 0, '按钮', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 13:33:38', b'0');
  23 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (32, 1, '内置', '1', 'sys_role_type', 0, '内置角色', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 13:34:22', b'0');
  24 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (33, 2, '自定义', '2', 'sys_role_type', 0, '自定义角色', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 13:34:26', b'0');
  25 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (34, 1, '全部数据权限', '1', 'sys_data_scope', 0, '全部数据权限', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 19:38:02', b'0');
  26 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (35, 2, '指定部门数据权限', '2', 'sys_data_scope', 0, '指定部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 19:38:20', b'0');
  27 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (36, 3, '本部门数据权限', '3', 'sys_data_scope', 0, '本部门数据权限', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 19:38:29', b'0');
  28 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (37, 4, '本部门及以下数据权限', '4', 'sys_data_scope', 0, '本部门及以下数据权限', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 19:38:32', b'0');
  29 +INSERT INTO `ruoyi-vue-pro`.`sys_dict_data`(`id`, `sort`, `label`, `value`, `dict_type`, `status`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `deleted`) VALUES (38, 5, '仅本人数据权限', '5', 'sys_data_scope', 0, '仅本人数据权限', 'admin', '2021-01-05 17:03:48', '', '2021-01-06 19:38:38', b'0');
... ...
src/main/java/cn/iocoder/dashboard/common/pojo/PageResult.java
... ... @@ -31,4 +31,8 @@ public final class PageResult&lt;T&gt; implements Serializable {
31 31 this.total = total;
32 32 }
33 33  
  34 + public static <T> PageResult<T> empty() {
  35 + return new PageResult<>(0L);
  36 + }
  37 +
34 38 }
... ...
src/main/java/cn/iocoder/dashboard/framework/async/config/AsyncConfiguration.java
... ... @@ -4,6 +4,6 @@ import org.springframework.context.annotation.Configuration;
4 4 import org.springframework.scheduling.annotation.EnableAsync;
5 5  
6 6 @Configuration
7   -@EnableAsync(proxyTargetClass = true)
  7 +@EnableAsync
8 8 public class AsyncConfiguration {
9 9 }
... ...
src/main/java/cn/iocoder/dashboard/framework/logger/operatelog/core/annotations/OperateLog.java
1 1 package cn.iocoder.dashboard.framework.logger.operatelog.core.annotations;
2 2  
3   -import cn.iocoder.dashboard.modules.system.enums.logger.SysOperateLogTypeEnum;
  3 +import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
4 4 import io.swagger.annotations.Api;
5 5 import io.swagger.annotations.ApiOperation;
6 6  
... ... @@ -32,7 +32,7 @@ public @interface OperateLog {
32 32 *
33 33 * 实际并不是数组,因为枚举不能设置 null 作为默认值
34 34 */
35   - SysOperateLogTypeEnum[] type() default {};
  35 + OperateLogTypeEnum[] type() default {};
36 36  
37 37 // ========== 开关字段 ==========
38 38  
... ...
src/main/java/cn/iocoder/dashboard/framework/logger/operatelog/core/aop/OperateLogAspect.java
... ... @@ -6,11 +6,11 @@ import cn.hutool.core.util.StrUtil;
6 6 import cn.hutool.extra.servlet.ServletUtil;
7 7 import cn.iocoder.dashboard.common.pojo.CommonResult;
8 8 import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  9 +import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
9 10 import cn.iocoder.dashboard.framework.logger.operatelog.core.service.OperateLogFrameworkService;
10 11 import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils;
11 12 import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
12 13 import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogCreateReqVO;
13   -import cn.iocoder.dashboard.modules.system.enums.logger.SysOperateLogTypeEnum;
14 14 import cn.iocoder.dashboard.util.servlet.ServletUtils;
15 15 import com.alibaba.fastjson.JSON;
16 16 import com.google.common.collect.Maps;
... ... @@ -180,7 +180,7 @@ public class OperateLogAspect {
180 180 }
181 181 if (operateLogVO.getType() == null) {
182 182 RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint));
183   - SysOperateLogTypeEnum operateLogType = convertOperateLogType(requestMethod);
  183 + OperateLogTypeEnum operateLogType = convertOperateLogType(requestMethod);
184 184 operateLogVO.setType(operateLogType != null ? operateLogType.getType() : null);
185 185 }
186 186 // content 和 exts 属性
... ... @@ -275,21 +275,21 @@ public class OperateLogAspect {
275 275 return requestMethods[0];
276 276 }
277 277  
278   - private static SysOperateLogTypeEnum convertOperateLogType(RequestMethod requestMethod) {
  278 + private static OperateLogTypeEnum convertOperateLogType(RequestMethod requestMethod) {
279 279 if (requestMethod == null) {
280 280 return null;
281 281 }
282 282 switch (requestMethod) {
283 283 case GET:
284   - return SysOperateLogTypeEnum.GET;
  284 + return OperateLogTypeEnum.GET;
285 285 case POST:
286   - return SysOperateLogTypeEnum.CREATE;
  286 + return OperateLogTypeEnum.CREATE;
287 287 case PUT:
288   - return SysOperateLogTypeEnum.UPDATE;
  288 + return OperateLogTypeEnum.UPDATE;
289 289 case DELETE:
290   - return SysOperateLogTypeEnum.DELETE;
  290 + return OperateLogTypeEnum.DELETE;
291 291 default:
292   - return SysOperateLogTypeEnum.OTHER;
  292 + return OperateLogTypeEnum.OTHER;
293 293 }
294 294 }
295 295  
... ...
src/main/java/cn/iocoder/dashboard/modules/system/enums/logger/SysOperateLogTypeEnum.java renamed to src/main/java/cn/iocoder/dashboard/framework/logger/operatelog/core/enums/OperateLogTypeEnum.java
1   -package cn.iocoder.dashboard.modules.system.enums.logger;
  1 +package cn.iocoder.dashboard.framework.logger.operatelog.core.enums;
2 2  
3 3 import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
4 4 import lombok.AllArgsConstructor;
... ... @@ -11,7 +11,7 @@ import lombok.Getter;
11 11 */
12 12 @Getter
13 13 @AllArgsConstructor
14   -public enum SysOperateLogTypeEnum {
  14 +public enum OperateLogTypeEnum {
15 15  
16 16 /**
17 17 * 查询
... ...
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/mapper/BaseMapperX.java 0 → 100644
  1 +package cn.iocoder.dashboard.framework.mybatis.core.mapper;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
  6 +import com.baomidou.mybatisplus.core.conditions.Wrapper;
  7 +import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  8 +import com.baomidou.mybatisplus.core.metadata.IPage;
  9 +import org.apache.ibatis.annotations.Param;
  10 +
  11 +/**
  12 + * 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
  13 + */
  14 +public interface BaseMapperX<T> extends BaseMapper<T> {
  15 +
  16 + default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
  17 + // MyBatis Plus 查询
  18 + IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
  19 + selectPage(mpPage, queryWrapper);
  20 + // 转换返回
  21 + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
  22 + }
  23 +
  24 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/SysAuthController.java
... ... @@ -54,7 +54,6 @@ public class SysAuthController {
54 54  
55 55 @ApiOperation("获取登陆用户的权限信息")
56 56 @GetMapping("/get-permission-info")
57   - @OperateLog
58 57 public CommonResult<SysAuthPermissionInfoRespVO> getPermissionInfo() {
59 58 // 获得用户信息
60 59 SysUserDO user = userService.getUser(getLoginUserId());
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.http
1 1 ### 请求 /captcha/get-image 接口 => 成功
2   -GET {{baseUrl}}/captcha/get-image
  2 +GET {{baseUrl}}/system/captcha/get-image
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/common/SysCaptchaController.java
... ... @@ -23,7 +23,7 @@ public class SysCaptchaController {
23 23  
24 24 @ApiOperation("生成图片验证码")
25 25 @GetMapping("/get-image")
26   - private CommonResult<SysCaptchaImageRespVO> getCaptchaImage() {
  26 + public CommonResult<SysCaptchaImageRespVO> getCaptchaImage() {
27 27 return success(captchaService.getCaptchaImage());
28 28 }
29 29  
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/SysOperateLogController.http 0 → 100644
  1 +### 请求 /system/operate-log/demo 接口 => 成功
  2 +GET {{baseUrl}}/system/operate-log/demo
  3 +Authorization: Bearer {{token}}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/SysOperateLogController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.logger;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  6 +import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
  7 +import cn.iocoder.dashboard.framework.logger.operatelog.core.util.OperateLogUtils;
  8 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
  9 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogRespVO;
  10 +import cn.iocoder.dashboard.modules.system.convert.logger.SysOperateLogConvert;
  11 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
  12 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
  13 +import cn.iocoder.dashboard.modules.system.service.logger.SysOperateLogService;
  14 +import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
  15 +import cn.iocoder.dashboard.util.collection.CollectionUtils;
  16 +import cn.iocoder.dashboard.util.collection.MapUtils;
  17 +import io.swagger.annotations.Api;
  18 +import io.swagger.annotations.ApiOperation;
  19 +import org.springframework.validation.annotation.Validated;
  20 +import org.springframework.web.bind.annotation.GetMapping;
  21 +import org.springframework.web.bind.annotation.RequestMapping;
  22 +import org.springframework.web.bind.annotation.RestController;
  23 +
  24 +import javax.annotation.Resource;
  25 +import java.util.ArrayList;
  26 +import java.util.Collection;
  27 +import java.util.List;
  28 +import java.util.Map;
  29 +
  30 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  31 +
  32 +@Api(tags = "操作日志 API")
  33 +@RestController
  34 +@RequestMapping("/system/operate-log")
  35 +public class SysOperateLogController {
  36 +
  37 + @Resource
  38 + private SysOperateLogService operateLogService;
  39 +
  40 + @Resource
  41 + private SysUserService userService;
  42 +
  43 + @ApiOperation("示例")
  44 + @OperateLog(type = OperateLogTypeEnum.OTHER)
  45 + @GetMapping("/demo")
  46 + public CommonResult<Boolean> demo() {
  47 + // 这里可以调用业务逻辑
  48 +
  49 + // 补全操作日志的明细
  50 + OperateLogUtils.setContent("将编号 1 的数据,xxx 字段修改成了 yyyy");
  51 + OperateLogUtils.addExt("orderId", 1);
  52 +
  53 + // 响应
  54 + return success(true);
  55 + }
  56 +
  57 + @ApiOperation("查看操作日志分页列表")
  58 + @GetMapping("/page")
  59 +// @PreAuthorize("@ss.hasPermi('system:operate-log:query')")
  60 + public CommonResult<PageResult<SysOperateLogRespVO>> pageOperateLog(@Validated SysOperateLogPageReqVO reqVO) {
  61 + PageResult<SysOperateLogDO> pageResult = operateLogService.pageOperateLog(reqVO);
  62 +
  63 + // 获得拼接需要的数据
  64 + Collection<Long> userIds = CollectionUtils.convertList(pageResult.getList(), SysOperateLogDO::getUserId);
  65 + Map<Long, SysUserDO> userMap = userService.getUserMap(userIds);
  66 + // 拼接数据
  67 + List<SysOperateLogRespVO> list = new ArrayList<>(pageResult.getList().size());
  68 + pageResult.getList().forEach(operateLog -> {
  69 + SysOperateLogRespVO respVO = SysOperateLogConvert.INSTANCE.convert(operateLog);
  70 + list.add(respVO);
  71 + // 拼接用户信息
  72 + MapUtils.findAndThen(userMap, operateLog.getUserId(), user -> respVO.setUserNickname(user.getNickname()));
  73 + });
  74 + return success(new PageResult<>(list, pageResult.getTotal()));
  75 + }
  76 +
  77 +// @Log(title = "操作日志", businessType = BusinessType.EXPORT)
  78 +// @PreAuthorize("@ss.hasPermi('system:operate-log:export')")
  79 +// @GetMapping("/export")
  80 +// public AjaxResult export(SysOperLog operLog) {
  81 +// List<SysOperLog> list = operLogService.selectOperLogList(operLog);
  82 +// ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
  83 +// return util.exportExcel(list, "操作日志");
  84 +// }
  85 +
  86 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/package-info.java deleted
1   -package cn.iocoder.dashboard.modules.system.controller.logger;
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/vo/SysOperateLogBaseVO.java
... ... @@ -6,6 +6,7 @@ import lombok.Data;
6 6 import javax.validation.constraints.NotEmpty;
7 7 import javax.validation.constraints.NotNull;
8 8 import java.util.Date;
  9 +import java.util.Map;
9 10  
10 11 /**
11 12 * 操作日志 Base VO,提供给添加、修改、详细的子 VO 使用
... ... @@ -30,10 +31,16 @@ public class SysOperateLogBaseVO {
30 31 @NotEmpty(message = "操作名")
31 32 private String name;
32 33  
33   - @ApiModelProperty(value = "操作分类", required = true, example = "操作分类", notes = "参见 SysOperateLogTypeEnum 枚举类")
  34 + @ApiModelProperty(value = "操作分类", required = true, example = "1", notes = "参见 SysOperateLogTypeEnum 枚举类")
34 35 @NotNull(message = "操作分类不能为空")
35 36 private Integer type;
36 37  
  38 + @ApiModelProperty(value = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。")
  39 + private String content;
  40 +
  41 + @ApiModelProperty(value = "拓展字段", example = "{'orderId': 1}")
  42 + private Map<String, Object> exts;
  43 +
37 44 @ApiModelProperty(value = "请求方法名", required = true, example = "GET")
38 45 @NotEmpty(message = "请求方法名不能为空")
39 46 private String requestMethod;
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/vo/SysOperateLogPageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.logger.vo;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.util.Date;
  11 +
  12 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@ApiModel("操作日志分页列表 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +public class SysOperateLogPageReqVO extends PageParam {
  18 +
  19 + @ApiModelProperty(value = "操作模块", example = "订单", notes = "模拟匹配")
  20 + private String module;
  21 +
  22 + @ApiModelProperty(value = "用户昵称", example = "芋道", notes = "模拟匹配")
  23 + private String userNickname;
  24 +
  25 + @ApiModelProperty(value = "操作分类", example = "1", notes = "参见 SysOperateLogTypeEnum 枚举类")
  26 + private Integer type;
  27 +
  28 + @ApiModelProperty(value = "操作状态", example = "true")
  29 + private Boolean success;
  30 +
  31 + @ApiModelProperty(value = "开始时间", example = "2020-10-24")
  32 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  33 + private Date beginTime;
  34 +
  35 + @ApiModelProperty(value = "结束时间", example = "2020-10-24")
  36 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  37 + private Date endTime;
  38 +
  39 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/controller/logger/vo/SysOperateLogRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.system.controller.logger.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +@ApiModel("操作日志 Response VO")
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@ToString(callSuper = true)
  13 +public class SysOperateLogRespVO extends SysOperateLogBaseVO {
  14 +
  15 + @ApiModelProperty(value = "日志编号", required = true, example = "1024")
  16 + private Long id;
  17 +
  18 + @ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
  19 + private String userNickname;
  20 +
  21 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/system/convert/logger/SysOperateLogConvert.java
1 1 package cn.iocoder.dashboard.modules.system.convert.logger;
2 2  
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
3 4 import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogCreateReqVO;
  5 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogRespVO;
4 6 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
5 7 import org.mapstruct.Mapper;
6 8 import org.mapstruct.factory.Mappers;
... ... @@ -12,4 +14,8 @@ public interface SysOperateLogConvert {
12 14  
13 15 SysOperateLogDO convert(SysOperateLogCreateReqVO bean);
14 16  
  17 + PageResult<SysOperateLogRespVO> convertPage(PageResult<SysOperateLogDO> page);
  18 +
  19 + SysOperateLogRespVO convert(SysOperateLogDO bean);
  20 +
15 21 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/logger/SysOperateLogMapper.java
1 1 package cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger;
2 2  
  3 +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
  7 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
3 8 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
4   -import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 9 import org.apache.ibatis.annotations.Mapper;
6 10  
  11 +import java.util.Collection;
  12 +
7 13 @Mapper
8   -public interface SysOperateLogMapper extends BaseMapper<SysOperateLogDO> {
  14 +public interface SysOperateLogMapper extends BaseMapperX<SysOperateLogDO> {
  15 +
  16 + default PageResult<SysOperateLogDO> selectPage(SysOperateLogPageReqVO reqVO, Collection<Long> userIds) {
  17 + QueryWrapperX<SysOperateLogDO> query = new QueryWrapperX<SysOperateLogDO>()
  18 + .likeIfPresent("module", reqVO.getModule())
  19 + .inIfPresent("user_id", userIds)
  20 + .eqIfPresent("operate_type", reqVO.getType())
  21 + .betweenIfPresent("start_time", reqVO.getBeginTime(), reqVO.getEndTime());
  22 + if (Boolean.TRUE.equals(reqVO.getSuccess())) {
  23 + query.eq("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
  24 + } else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
  25 + query.gt("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
  26 + }
  27 + return selectPage(reqVO, query);
  28 + }
  29 +
9 30 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/user/SysUserMapper.java
... ... @@ -45,5 +45,9 @@ public interface SysUserMapper extends BaseMapper&lt;SysUserDO&gt; {
45 45 .inIfPresent("dept_id", deptIds));
46 46 }
47 47  
  48 + default List<SysUserDO> selectListByNickname(String nickname) {
  49 + return selectList(new QueryWrapperX<SysUserDO>().like("nickname", nickname));
  50 + }
  51 +
48 52 }
49 53  
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dataobject/logger/SysOperateLogDO.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger;
3 3 import cn.iocoder.dashboard.common.pojo.CommonResult;
4 4 import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
5 5 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
6   -import cn.iocoder.dashboard.modules.system.enums.logger.SysOperateLogTypeEnum;
  6 +import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
7 7 import com.baomidou.mybatisplus.annotation.TableField;
8 8 import com.baomidou.mybatisplus.annotation.TableId;
9 9 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -62,22 +62,18 @@ public class SysOperateLogDO extends BaseDO {
62 62 /**
63 63 * 操作分类
64 64 *
65   - * 枚举 {@link SysOperateLogTypeEnum}
  65 + * 枚举 {@link OperateLogTypeEnum}
66 66 */
67 67 @TableField("operate_type")
68 68 private Integer type;
69 69 /**
70 70 * 操作内容,记录整个操作的明细
71 71 * 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
72   - *
73   - * TODO 预留字段
74 72 */
75 73 private String content;
76 74 /**
77 75 * 拓展字段,有些复杂的业务,需要记录一些字段
78 76 * 例如说,记录订单编号,则可以添加 key 为 "orderId",value 为订单编号
79   - *
80   - * TODO 预留字段
81 77 */
82 78 @TableField(typeHandler = FastjsonTypeHandler.class)
83 79 private Map<String, Object> exts;
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/logger/SysOperateLogService.java
1 1 package cn.iocoder.dashboard.modules.system.service.logger;
2 2  
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
3 4 import cn.iocoder.dashboard.framework.logger.operatelog.core.service.OperateLogFrameworkService;
  5 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
  6 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
4 7  
5 8 /**
6 9 * 操作日志 Service 接口
7 10 */
8 11 public interface SysOperateLogService extends OperateLogFrameworkService {
  12 +
  13 + /**
  14 + * 获得操作日志分页列表
  15 + *
  16 + * @param reqVO 分页条件
  17 + * @return 操作日志分页列表
  18 + */
  19 + PageResult<SysOperateLogDO> pageOperateLog(SysOperateLogPageReqVO reqVO);
  20 +
9 21 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/logger/impl/SysOperateLogServiceImpl.java
1 1 package cn.iocoder.dashboard.modules.system.service.logger.impl;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.dashboard.common.pojo.PageResult;
3 6 import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogCreateReqVO;
  7 +import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
4 8 import cn.iocoder.dashboard.modules.system.convert.logger.SysOperateLogConvert;
5 9 import cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger.SysOperateLogMapper;
6 10 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
  11 +import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
7 12 import cn.iocoder.dashboard.modules.system.service.logger.SysOperateLogService;
  13 +import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
8 14 import cn.iocoder.dashboard.util.string.StrUtils;
9 15 import lombok.extern.slf4j.Slf4j;
10 16 import org.springframework.scheduling.annotation.Async;
11 17 import org.springframework.stereotype.Service;
12 18  
13 19 import javax.annotation.Resource;
  20 +import java.util.Collection;
14 21  
15   -import static cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO.*;
  22 +import static cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH;
  23 +import static cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO.RESULT_MAX_LENGTH;
  24 +import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet;
16 25  
17 26 @Service
18 27 @Slf4j
... ... @@ -21,6 +30,9 @@ public class SysOperateLogServiceImpl implements SysOperateLogService {
21 30 @Resource
22 31 private SysOperateLogMapper operateLogMapper;
23 32  
  33 + @Resource
  34 + private SysUserService userService;
  35 +
24 36 @Override
25 37 @Async
26 38 public void createOperateLogAsync(SysOperateLogCreateReqVO reqVO) {
... ... @@ -35,4 +47,18 @@ public class SysOperateLogServiceImpl implements SysOperateLogService {
35 47 }
36 48 }
37 49  
  50 + @Override
  51 + public PageResult<SysOperateLogDO> pageOperateLog(SysOperateLogPageReqVO reqVO) {
  52 + // 处理基于用户昵称的查询
  53 + Collection<Long> userIds = null;
  54 + if (StrUtil.isNotEmpty(reqVO.getUserNickname())) {
  55 + userIds = convertSet(userService.listUsersByNickname(reqVO.getUserNickname()), SysUserDO::getId);
  56 + if (CollUtil.isEmpty(userIds)) {
  57 + return PageResult.empty();
  58 + }
  59 + }
  60 + // 查询分页
  61 + return operateLogMapper.selectPage(reqVO, userIds);
  62 + }
  63 +
38 64 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserService.java
1 1 package cn.iocoder.dashboard.modules.system.service.user;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.dashboard.common.pojo.PageResult;
4 5 import cn.iocoder.dashboard.modules.system.controller.user.vo.user.*;
5 6 import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
  7 +import cn.iocoder.dashboard.util.collection.CollectionUtils;
6 8  
  9 +import java.util.Collection;
  10 +import java.util.HashMap;
7 11 import java.util.List;
  12 +import java.util.Map;
8 13  
9 14 /**
10 15 * 用户 Service 接口
... ... @@ -46,6 +51,35 @@ public interface SysUserService {
46 51 List<SysUserDO> listUsers(SysUserExportReqVO reqVO);
47 52  
48 53 /**
  54 + * 获得用户列表
  55 + *
  56 + * @param ids 用户编号数组
  57 + * @return 用户列表
  58 + */
  59 + List<SysUserDO> listUsers(Collection<Long> ids);
  60 +
  61 + /**
  62 + * 获得用户 Map
  63 + *
  64 + * @param ids 用户编号数组
  65 + * @return 用户 Map
  66 + */
  67 + default Map<Long, SysUserDO> getUserMap(Collection<Long> ids) {
  68 + if (CollUtil.isEmpty(ids)) {
  69 + return new HashMap<>();
  70 + }
  71 + return CollectionUtils.convertMap(listUsers(ids), SysUserDO::getId);
  72 + }
  73 +
  74 + /**
  75 + * 获得用户列表,基于昵称模糊匹配
  76 + *
  77 + * @param nickname 昵称
  78 + * @return 用户列表
  79 + */
  80 + List<SysUserDO> listUsersByNickname(String nickname);
  81 +
  82 + /**
49 83 * 创建用户
50 84 *
51 85 * @param reqVO 用户信息
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/user/SysUserServiceImpl.java
... ... @@ -83,6 +83,16 @@ public class SysUserServiceImpl implements SysUserService {
83 83 return userMapper.selectList(reqVO, this.getDeptCondition(reqVO.getDeptId()));
84 84 }
85 85  
  86 + @Override
  87 + public List<SysUserDO> listUsers(Collection<Long> ids) {
  88 + return userMapper.selectBatchIds(ids);
  89 + }
  90 +
  91 + @Override
  92 + public List<SysUserDO> listUsersByNickname(String nickname) {
  93 + return userMapper.selectListByNickname(nickname);
  94 + }
  95 +
86 96 /**
87 97 * 获得部门条件:查询指定部门的子部门编号们,包括自身
88 98 *
... ...