mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-09-17 02:46:39 +08:00
v3.26.0 【优化】分页请求2次;【优化】菜单展开单个代码优化;【优化】操作记录返回结果;【优化】json viewer升级;【优化】S3协议优化;【优化】代码生成字典优化;
This commit is contained in:
parent
8135e0ec10
commit
d2c55e35ff
@ -67,7 +67,7 @@ public class AdminInterceptor implements HandlerInterceptor {
|
||||
Method method = ((HandlerMethod) handler).getMethod();
|
||||
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
|
||||
if (noNeedLogin != null) {
|
||||
checkActiveTimeout(requestEmployee);
|
||||
updateActiveTimeout(requestEmployee);
|
||||
SmartRequestUtil.setRequestUser(requestEmployee);
|
||||
return true;
|
||||
}
|
||||
@ -77,8 +77,8 @@ public class AdminInterceptor implements HandlerInterceptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检测token 活跃频率
|
||||
checkActiveTimeout(requestEmployee);
|
||||
// 更新活跃
|
||||
updateActiveTimeout(requestEmployee);
|
||||
|
||||
|
||||
// --------------- 第三步: 校验 权限 ---------------
|
||||
@ -123,15 +123,12 @@ public class AdminInterceptor implements HandlerInterceptor {
|
||||
|
||||
|
||||
/**
|
||||
* 检测:token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结
|
||||
* 更新活跃时间
|
||||
*/
|
||||
private void checkActiveTimeout(RequestEmployee requestEmployee) {
|
||||
// 用户不在线,也不用检测
|
||||
private void updateActiveTimeout(RequestEmployee requestEmployee) {
|
||||
if (requestEmployee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
StpUtil.checkActiveTimeout();
|
||||
StpUtil.updateLastActiveToNow();
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class FileConfig implements WebMvcConfigurer {
|
||||
StaticCredentialsProvider.create(
|
||||
AwsBasicCredentials.create(accessKey, secretKey)))
|
||||
.serviceConfiguration(S3Configuration.builder()
|
||||
.pathStyleAccessEnabled(false)
|
||||
.pathStyleAccessEnabled(true)
|
||||
.chunkedEncodingEnabled(false)
|
||||
.build())
|
||||
.build();
|
||||
|
@ -101,7 +101,18 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
|
||||
userMetadata.put(USER_METADATA_FILE_FORMAT, fileType);
|
||||
userMetadata.put(USER_METADATA_FILE_SIZE, String.valueOf(file.getSize()));
|
||||
|
||||
PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).metadata(userMetadata).contentLength(file.getSize()).contentType(this.getContentType(fileType)).contentEncoding(StandardCharsets.UTF_8.name()).contentDisposition("attachment;filename=" + urlEncoderFilename).build();
|
||||
// 根据文件路径获取并设置访问权限
|
||||
ObjectCannedACL acl = this.getACL(path);
|
||||
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
|
||||
.bucket(cloudConfig.getBucketName())
|
||||
.key(fileKey)
|
||||
.metadata(userMetadata)
|
||||
.contentLength(file.getSize())
|
||||
.contentType(this.getContentType(fileType))
|
||||
.contentEncoding(StandardCharsets.UTF_8.name())
|
||||
.contentDisposition("attachment;filename=" + urlEncoderFilename)
|
||||
.acl(acl)
|
||||
.build();
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = file.getInputStream();
|
||||
@ -112,10 +123,6 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
|
||||
} finally {
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
}
|
||||
// 根据文件路径获取并设置访问权限
|
||||
ObjectCannedACL acl = this.getACL(path);
|
||||
PutObjectAclRequest aclRequest = PutObjectAclRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).acl(this.getACL(path)).build();
|
||||
s3Client.putObjectAcl(aclRequest);
|
||||
// 返回上传结果
|
||||
FileUploadVO uploadVO = new FileUploadVO();
|
||||
uploadVO.setFileName(originalFileName);
|
||||
|
@ -11,6 +11,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.base.common.constant.StringConst;
|
||||
import net.lab1024.sa.base.common.domain.RequestUser;
|
||||
import net.lab1024.sa.base.common.domain.ResponseDTO;
|
||||
import net.lab1024.sa.base.common.util.SmartIpUtil;
|
||||
import net.lab1024.sa.base.common.util.SmartRequestUtil;
|
||||
import net.lab1024.sa.base.module.support.operatelog.OperateLogDao;
|
||||
@ -46,7 +47,7 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
* @Date 2021-12-08 20:48:52
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@ -71,14 +72,14 @@ public abstract class OperateLogAspect {
|
||||
public void logPointCut() {
|
||||
}
|
||||
|
||||
@AfterReturning(pointcut = "logPointCut()")
|
||||
public void doAfterReturning(JoinPoint joinPoint) {
|
||||
handleLog(joinPoint, null);
|
||||
@AfterReturning(pointcut = "logPointCut()", returning = "responseDTO")
|
||||
public void doAfterReturning(JoinPoint joinPoint, Object responseDTO) {
|
||||
handleLog(joinPoint, null, responseDTO);
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "logPointCut()", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
|
||||
handleLog(joinPoint, e);
|
||||
handleLog(joinPoint, e, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,16 +110,15 @@ public abstract class OperateLogAspect {
|
||||
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
}
|
||||
|
||||
protected void handleLog(final JoinPoint joinPoint, final Exception e) {
|
||||
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object responseDTO) {
|
||||
try {
|
||||
OperateLog operateLog = this.getAnnotationLog(joinPoint);
|
||||
if (operateLog == null) {
|
||||
return;
|
||||
}
|
||||
this.submitLog(joinPoint, e);
|
||||
this.submitLog(joinPoint, e, responseDTO);
|
||||
} catch (Exception exp) {
|
||||
log.error("保存操作日志异常:{}", exp.getMessage());
|
||||
exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,11 +173,8 @@ public abstract class OperateLogAspect {
|
||||
/**
|
||||
* 提交存储操作日志
|
||||
*
|
||||
* @param joinPoint
|
||||
* @param e
|
||||
* @throws Exception
|
||||
*/
|
||||
private void submitLog(final JoinPoint joinPoint, final Throwable e) throws Exception {
|
||||
private void submitLog(final JoinPoint joinPoint, final Throwable e, Object responseDTO) {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
//设置用户信息
|
||||
RequestUser user = SmartRequestUtil.getRequestUser();
|
||||
@ -191,7 +188,7 @@ public abstract class OperateLogAspect {
|
||||
String methodName = joinPoint.getSignature().getName();
|
||||
String operateMethod = className + "." + methodName;
|
||||
String failReason = null;
|
||||
Boolean successFlag = true;
|
||||
boolean successFlag = true;
|
||||
if (e != null) {
|
||||
successFlag = false;
|
||||
failReason = getExceptionString(e);
|
||||
@ -210,15 +207,32 @@ public abstract class OperateLogAspect {
|
||||
.userAgent(user.getUserAgent())
|
||||
.failReason(failReason)
|
||||
.successFlag(successFlag).build();
|
||||
|
||||
Operation apiOperation = this.getApiOperation(joinPoint);
|
||||
if (apiOperation != null) {
|
||||
operateLogEntity.setContent(apiOperation.summary());
|
||||
}
|
||||
|
||||
Tag api = this.getApi(joinPoint);
|
||||
if (api != null) {
|
||||
String name = api.name();
|
||||
operateLogEntity.setModule(StrUtil.join(",", name));
|
||||
}
|
||||
|
||||
// 处理返回值 ResponseDTO
|
||||
if(responseDTO instanceof ResponseDTO) {
|
||||
ResponseDTO response = (ResponseDTO) responseDTO;
|
||||
ResponseDTO logResponseDTO = new ResponseDTO(
|
||||
response.getCode(),
|
||||
response.getLevel(),
|
||||
response.getOk(),
|
||||
response.getMsg(),
|
||||
null
|
||||
);
|
||||
logResponseDTO.setDataType(response.getDataType());
|
||||
operateLogEntity.setResponse(JSON.toJSONString(logResponseDTO));
|
||||
}
|
||||
|
||||
taskExecutor.execute(() -> {
|
||||
this.saveLog(operateLogEntity);
|
||||
});
|
||||
|
@ -71,6 +71,11 @@ public class OperateLogEntity {
|
||||
*/
|
||||
private String param;
|
||||
|
||||
/**
|
||||
* 返回值
|
||||
*/
|
||||
private String response;
|
||||
|
||||
/**
|
||||
* 客户ip
|
||||
*/
|
||||
|
@ -47,6 +47,9 @@ public class OperateLogVO {
|
||||
@Schema(description = "请求参数")
|
||||
private String param;
|
||||
|
||||
@Schema(description = "返回值")
|
||||
private String response;
|
||||
|
||||
@Schema(description = "客户ip")
|
||||
private String ip;
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
@ -106,7 +106,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
|
@ -22,7 +22,7 @@
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Dict")
|
||||
<a-form-item label="${field.label}" class="smart-query-form-item">
|
||||
<DictSelect dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
<DictSelect :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Enum")
|
||||
|
@ -48,7 +48,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
@ -106,7 +106,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
|
@ -22,7 +22,7 @@
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Dict")
|
||||
<a-form-item label="${field.label}" class="smart-query-form-item">
|
||||
<DictSelect dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
<DictSelect :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Enum")
|
||||
|
@ -26,7 +26,7 @@
|
||||
AND (INSTR(module,#{query.keywords}) OR INSTR(content,#{query.keywords}))
|
||||
</if>
|
||||
<if test="query.requestKeywords != null and query.requestKeywords != ''">
|
||||
AND (INSTR(url,#{query.requestKeywords}) OR INSTR(method,#{query.requestKeywords}) OR INSTR(param,#{query.requestKeywords}))
|
||||
AND (INSTR(url,#{query.requestKeywords}) OR INSTR(method,#{query.requestKeywords}) OR INSTR(param,#{query.requestKeywords}) OR INSTR(response,#{query.requestKeywords}))
|
||||
</if>
|
||||
<if test="query.successFlag != null">
|
||||
AND success_flag = #{query.successFlag}
|
||||
|
@ -67,7 +67,7 @@ public class AdminInterceptor implements HandlerInterceptor {
|
||||
Method method = ((HandlerMethod) handler).getMethod();
|
||||
NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class);
|
||||
if (noNeedLogin != null) {
|
||||
checkActiveTimeout(requestEmployee);
|
||||
updateActiveTimeout(requestEmployee);
|
||||
SmartRequestUtil.setRequestUser(requestEmployee);
|
||||
return true;
|
||||
}
|
||||
@ -77,8 +77,8 @@ public class AdminInterceptor implements HandlerInterceptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检测token 活跃频率
|
||||
checkActiveTimeout(requestEmployee);
|
||||
// 更新活跃
|
||||
updateActiveTimeout(requestEmployee);
|
||||
|
||||
|
||||
// --------------- 第三步: 校验 权限 ---------------
|
||||
@ -123,15 +123,12 @@ public class AdminInterceptor implements HandlerInterceptor {
|
||||
|
||||
|
||||
/**
|
||||
* 检测:token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结
|
||||
* 更新活跃时间
|
||||
*/
|
||||
private void checkActiveTimeout(RequestEmployee requestEmployee) {
|
||||
// 用户不在线,也不用检测
|
||||
private void updateActiveTimeout(RequestEmployee requestEmployee) {
|
||||
if (requestEmployee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
StpUtil.checkActiveTimeout();
|
||||
StpUtil.updateLastActiveToNow();
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class FileConfig implements WebMvcConfigurer {
|
||||
StaticCredentialsProvider.create(
|
||||
AwsBasicCredentials.create(accessKey, secretKey)))
|
||||
.serviceConfiguration(S3Configuration.builder()
|
||||
.pathStyleAccessEnabled(false)
|
||||
.pathStyleAccessEnabled(true)
|
||||
.chunkedEncodingEnabled(false)
|
||||
.build())
|
||||
.build();
|
||||
|
@ -106,7 +106,18 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
|
||||
userMetadata.put(USER_METADATA_FILE_FORMAT, fileType);
|
||||
userMetadata.put(USER_METADATA_FILE_SIZE, String.valueOf(file.getSize()));
|
||||
|
||||
PutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).metadata(userMetadata).contentLength(file.getSize()).contentType(this.getContentType(fileType)).contentEncoding(StandardCharsets.UTF_8.name()).contentDisposition("attachment;filename=" + urlEncoderFilename).build();
|
||||
// 根据文件路径获取并设置访问权限
|
||||
ObjectCannedACL acl = this.getACL(path);
|
||||
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
|
||||
.bucket(cloudConfig.getBucketName())
|
||||
.key(fileKey)
|
||||
.metadata(userMetadata)
|
||||
.contentLength(file.getSize())
|
||||
.contentType(this.getContentType(fileType))
|
||||
.contentEncoding(StandardCharsets.UTF_8.name())
|
||||
.contentDisposition("attachment;filename=" + urlEncoderFilename)
|
||||
.acl(acl)
|
||||
.build();
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = file.getInputStream();
|
||||
@ -117,10 +128,6 @@ public class FileStorageCloudServiceImpl implements IFileStorageService {
|
||||
} finally {
|
||||
IOUtils.closeQuietly(inputStream);
|
||||
}
|
||||
// 根据文件路径获取并设置访问权限
|
||||
ObjectCannedACL acl = this.getACL(path);
|
||||
PutObjectAclRequest aclRequest = PutObjectAclRequest.builder().bucket(cloudConfig.getBucketName()).key(fileKey).acl(this.getACL(path)).build();
|
||||
s3Client.putObjectAcl(aclRequest);
|
||||
// 返回上传结果
|
||||
FileUploadVO uploadVO = new FileUploadVO();
|
||||
uploadVO.setFileName(originalFileName);
|
||||
|
@ -3,11 +3,12 @@ package net.lab1024.sa.base.module.support.operatelog.core;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.lab1024.sa.base.common.constant.StringConst;
|
||||
import net.lab1024.sa.base.common.domain.RequestUser;
|
||||
import net.lab1024.sa.base.common.domain.ResponseDTO;
|
||||
import net.lab1024.sa.base.common.util.SmartIpUtil;
|
||||
import net.lab1024.sa.base.common.util.SmartRequestUtil;
|
||||
import net.lab1024.sa.base.module.support.operatelog.OperateLogDao;
|
||||
@ -20,7 +21,6 @@ import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.bind.BindResult;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@ -36,7 +36,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.BindException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@ -48,7 +47,7 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
* @Date 2021-12-08 20:48:52
|
||||
* @Wechat zhuoda1024
|
||||
* @Email lab1024@163.com
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
* @Copyright <a href="https://1024lab.net">1024创新实验室</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@ -73,14 +72,14 @@ public abstract class OperateLogAspect {
|
||||
public void logPointCut() {
|
||||
}
|
||||
|
||||
@AfterReturning(pointcut = "logPointCut()")
|
||||
public void doAfterReturning(JoinPoint joinPoint) {
|
||||
handleLog(joinPoint, null);
|
||||
@AfterReturning(pointcut = "logPointCut()", returning = "responseDTO")
|
||||
public void doAfterReturning(JoinPoint joinPoint, Object responseDTO) {
|
||||
handleLog(joinPoint, null, responseDTO);
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "logPointCut()", throwing = "e")
|
||||
public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
|
||||
handleLog(joinPoint, e);
|
||||
handleLog(joinPoint, e, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,16 +110,15 @@ public abstract class OperateLogAspect {
|
||||
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
}
|
||||
|
||||
protected void handleLog(final JoinPoint joinPoint, final Exception e) {
|
||||
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object responseDTO) {
|
||||
try {
|
||||
OperateLog operateLog = this.getAnnotationLog(joinPoint);
|
||||
if (operateLog == null) {
|
||||
return;
|
||||
}
|
||||
this.submitLog(joinPoint, e);
|
||||
this.submitLog(joinPoint, e, responseDTO);
|
||||
} catch (Exception exp) {
|
||||
log.error("保存操作日志异常:{}", exp.getMessage());
|
||||
exp.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,11 +173,8 @@ public abstract class OperateLogAspect {
|
||||
/**
|
||||
* 提交存储操作日志
|
||||
*
|
||||
* @param joinPoint
|
||||
* @param e
|
||||
* @throws Exception
|
||||
*/
|
||||
private void submitLog(final JoinPoint joinPoint, final Throwable e) throws Exception {
|
||||
private void submitLog(final JoinPoint joinPoint, final Throwable e, Object responseDTO) {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
//设置用户信息
|
||||
RequestUser user = SmartRequestUtil.getRequestUser();
|
||||
@ -193,7 +188,7 @@ public abstract class OperateLogAspect {
|
||||
String methodName = joinPoint.getSignature().getName();
|
||||
String operateMethod = className + "." + methodName;
|
||||
String failReason = null;
|
||||
Boolean successFlag = true;
|
||||
boolean successFlag = true;
|
||||
if (e != null) {
|
||||
successFlag = false;
|
||||
failReason = getExceptionString(e);
|
||||
@ -212,15 +207,32 @@ public abstract class OperateLogAspect {
|
||||
.userAgent(user.getUserAgent())
|
||||
.failReason(failReason)
|
||||
.successFlag(successFlag).build();
|
||||
|
||||
Operation apiOperation = this.getApiOperation(joinPoint);
|
||||
if (apiOperation != null) {
|
||||
operateLogEntity.setContent(apiOperation.summary());
|
||||
}
|
||||
|
||||
Tag api = this.getApi(joinPoint);
|
||||
if (api != null) {
|
||||
String name = api.name();
|
||||
operateLogEntity.setModule(StrUtil.join(",", name));
|
||||
}
|
||||
|
||||
// 处理返回值 ResponseDTO
|
||||
if(responseDTO instanceof ResponseDTO) {
|
||||
ResponseDTO response = (ResponseDTO) responseDTO;
|
||||
ResponseDTO logResponseDTO = new ResponseDTO(
|
||||
response.getCode(),
|
||||
response.getLevel(),
|
||||
response.getOk(),
|
||||
response.getMsg(),
|
||||
null
|
||||
);
|
||||
logResponseDTO.setDataType(response.getDataType());
|
||||
operateLogEntity.setResponse(JSON.toJSONString(logResponseDTO));
|
||||
}
|
||||
|
||||
taskExecutor.execute(() -> {
|
||||
this.saveLog(operateLogEntity);
|
||||
});
|
||||
|
@ -71,6 +71,11 @@ public class OperateLogEntity {
|
||||
*/
|
||||
private String param;
|
||||
|
||||
/**
|
||||
* 返回值
|
||||
*/
|
||||
private String response;
|
||||
|
||||
/**
|
||||
* 客户ip
|
||||
*/
|
||||
|
@ -47,6 +47,9 @@ public class OperateLogVO {
|
||||
@Schema(description = "请求参数")
|
||||
private String param;
|
||||
|
||||
@Schema(description = "返回值")
|
||||
private String response;
|
||||
|
||||
@Schema(description = "客户ip")
|
||||
private String ip;
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
@ -106,7 +106,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
|
@ -22,7 +22,7 @@
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Dict")
|
||||
<a-form-item label="${field.label}" class="smart-query-form-item">
|
||||
<DictSelect dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
<DictSelect :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Enum")
|
||||
|
@ -48,7 +48,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
@ -106,7 +106,7 @@
|
||||
#end
|
||||
#if($field.frontComponent == "DictSelect")
|
||||
<a-form-item label="$codeGeneratorTool.removeEnumDesc($!{field.label})" name="${field.fieldName}">
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
<DictSelect width="100%" v-model:value="form.${field.fieldName}" :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="$!{field.label}"/>
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.frontComponent == "Date")
|
||||
|
@ -22,7 +22,7 @@
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Dict")
|
||||
<a-form-item label="${field.label}" class="smart-query-form-item">
|
||||
<DictSelect dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
<DictSelect :dict-code="DICT_CODE_ENUM.$!{field.dict} || '$!{field.dict}'" placeholder="${field.label}" v-model:value="queryForm.${field.fieldName}" width="${field.width}" />
|
||||
</a-form-item>
|
||||
#end
|
||||
#if($field.queryTypeEnum == "Enum")
|
||||
|
@ -26,7 +26,7 @@
|
||||
AND (INSTR(module,#{query.keywords}) OR INSTR(content,#{query.keywords}))
|
||||
</if>
|
||||
<if test="query.requestKeywords != null and query.requestKeywords != ''">
|
||||
AND (INSTR(url,#{query.requestKeywords}) OR INSTR(method,#{query.requestKeywords}) OR INSTR(param,#{query.requestKeywords}))
|
||||
AND (INSTR(url,#{query.requestKeywords}) OR INSTR(method,#{query.requestKeywords}) OR INSTR(param,#{query.requestKeywords}) OR INSTR(response,#{query.requestKeywords}))
|
||||
</if>
|
||||
<if test="query.successFlag != null">
|
||||
AND success_flag = #{query.successFlag}
|
||||
|
@ -43,7 +43,7 @@
|
||||
"vue": "3.4.27",
|
||||
"vue-i18n": "9.13.1",
|
||||
"vue-router": "4.3.2",
|
||||
"vue3-json-viewer": "2.2.2"
|
||||
"vue3-json-viewer": "2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "5.0.4",
|
||||
|
@ -51,7 +51,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
<a-modal v-model:open="visibleDiff" width="90%" title="数据比对" :footer="null">
|
||||
|
@ -71,7 +71,6 @@
|
||||
v-model:pageSize="params.pageSize"
|
||||
:total="total"
|
||||
@change="queryEmployee"
|
||||
@showSizeChange="queryEmployee"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -27,7 +27,7 @@ export const appDefaultConfig = {
|
||||
// 圆角
|
||||
borderRadius: 6,
|
||||
// 菜单展开模式
|
||||
flatPattern: false,
|
||||
menuSingleExpandFlag: true,
|
||||
// 标签页
|
||||
pageTagFlag: true,
|
||||
// 标签页样式: default、 antd、chrome
|
||||
|
@ -21,11 +21,11 @@ export default {
|
||||
'setting.menu.layout': 'Menu Layout',
|
||||
'setting.menu.width': 'Menu Width',
|
||||
'setting.menu.theme': 'Menu Theme',
|
||||
'setting.menu.expand': 'Menu Expand',
|
||||
'setting.page.width': 'Page Width',
|
||||
'setting.border.radius': 'Border Radius',
|
||||
'setting.compact': 'Page Compact',
|
||||
'setting.bread': 'Show Bread',
|
||||
'setting.flatPattern': 'Flat Pattern',
|
||||
'setting.pagetag': 'Show PageTag',
|
||||
'setting.pagetag.style': 'PageTag Style',
|
||||
'setting.footer': 'Show Footer',
|
||||
|
@ -21,11 +21,11 @@ export default {
|
||||
'setting.menu.layout': '菜单布局',
|
||||
'setting.menu.width': '菜单宽度',
|
||||
'setting.menu.theme': '菜单主题',
|
||||
'setting.menu.expand': '菜单展开',
|
||||
'setting.compact': '页面紧凑',
|
||||
'setting.border.radius': '页面圆角',
|
||||
'setting.page.width': '页面宽度',
|
||||
'setting.bread': '面包屑',
|
||||
'setting.flatPattern': '菜单展开模式',
|
||||
'setting.pagetag': '标签页',
|
||||
'setting.pagetag.style': '标签页样式',
|
||||
'setting.footer': '页脚',
|
||||
|
@ -83,8 +83,8 @@
|
||||
<a-radio-button value="chrome">Chrome</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.flatPattern')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
|
||||
<a-switch @change="changeFlatPattern" v-model:checked="formState.flatPattern" checked-children="多个" un-checked-children="单个" />
|
||||
<a-form-item :label="$t('setting.menu.expand')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
|
||||
<a-switch @change="changeMenuExpandFlag" v-model:checked="formState.menuSingleExpandFlag" checked-children="单个" un-checked-children="多个" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.pagetag')">
|
||||
<a-switch @change="changePageTagFlag" v-model:checked="formState.pageTagFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
@ -213,8 +213,8 @@
|
||||
borderRadius: appConfigStore.borderRadius,
|
||||
// 标签页
|
||||
pageTagFlag: appConfigStore.pageTagFlag,
|
||||
// 标签页
|
||||
flatPattern: appConfigStore.flatPattern,
|
||||
// 菜单展开方式
|
||||
menuSingleExpandFlag: appConfigStore.menuSingleExpandFlag,
|
||||
// 标签页 样式
|
||||
pageTagStyle: appConfigStore.pageTagStyle,
|
||||
// 面包屑
|
||||
@ -303,9 +303,9 @@
|
||||
});
|
||||
}
|
||||
|
||||
function changeFlatPattern(e) {
|
||||
function changeMenuExpandFlag(e) {
|
||||
appConfigStore.$patch({
|
||||
flatPattern: e,
|
||||
menuSingleExpandFlag: e,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
import { useUserStore } from '/@/store/modules/system/user';
|
||||
|
||||
const theme = computed(() => useAppConfigStore().$state.sideMenuTheme);
|
||||
const flatPattern = computed(() => useAppConfigStore().$state.flatPattern);
|
||||
const menuSingleExpandFlag = computed(() => useAppConfigStore().$state.menuSingleExpandFlag);
|
||||
|
||||
const props = defineProps({
|
||||
collapsed: {
|
||||
@ -46,8 +46,7 @@
|
||||
});
|
||||
|
||||
const menuTree = computed(() => useUserStore().getMenuTree || []);
|
||||
const rootSubmenuKeys = computed(()=>menuTree.value.map(item=>item.menuId));
|
||||
|
||||
const rootSubmenuKeys = computed(() => menuTree.value.map((item) => item.menuId));
|
||||
|
||||
//展开的菜单
|
||||
let currentRoute = useRoute();
|
||||
@ -76,9 +75,15 @@
|
||||
let parentList = menuParentIdListMap.get(currentRoute.name) || [];
|
||||
|
||||
// 如果是折叠菜单的话,则不需要设置openkey
|
||||
if (!props.collapsed) {
|
||||
if (props.collapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let needOpenKeys = _.map(parentList, 'name').map(Number);
|
||||
if (menuSingleExpandFlag.value) {
|
||||
openKeys.value = [...needOpenKeys];
|
||||
} else {
|
||||
// 使用lodash的union函数,进行 去重合并两个数组
|
||||
let needOpenKeys = _.map(parentList, 'name').map(Number);
|
||||
openKeys.value = _.union(openKeys.value, needOpenKeys);
|
||||
}
|
||||
}
|
||||
@ -92,17 +97,18 @@
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
function onOpenChange(openKeysParams){
|
||||
if(flatPattern.value){
|
||||
return;
|
||||
|
||||
function onOpenChange(openKeysParams) {
|
||||
if (!menuSingleExpandFlag.value) {
|
||||
return;
|
||||
}
|
||||
const latestOpenKey = openKeysParams.find((key) => openKeys.value.indexOf(key) === -1);
|
||||
if (rootSubmenuKeys.value.indexOf(latestOpenKey) === -1) {
|
||||
openKeys.value = openKeysParams;
|
||||
} else {
|
||||
openKeys.value = latestOpenKey ? [latestOpenKey] : [];
|
||||
}
|
||||
}
|
||||
const latestOpenKey = openKeysParams.find(key => openKeys.value.indexOf(key) === -1);
|
||||
if (rootSubmenuKeys.value.indexOf(latestOpenKey) === -1) {
|
||||
openKeys.value = openKeysParams;
|
||||
} else {
|
||||
openKeys.value = latestOpenKey ? [latestOpenKey] : [];
|
||||
}
|
||||
};
|
||||
defineExpose({
|
||||
updateOpenKeysAndSelectKeys,
|
||||
});
|
||||
|
@ -149,7 +149,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -78,7 +78,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -63,7 +63,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryEmployee"
|
||||
@showSizeChange="queryEmployee"
|
||||
:show-total="showTableTotal"
|
||||
/>
|
||||
</div>
|
||||
|
@ -75,7 +75,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -102,7 +102,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -53,7 +53,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryViewRecord"
|
||||
@showSizeChange="queryViewRecord"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -72,7 +72,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryNoticeList"
|
||||
@showSizeChange="queryNoticeList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -122,7 +122,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryNoticeList"
|
||||
@showSizeChange="queryNoticeList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -107,7 +107,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -74,7 +74,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -66,7 +66,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -98,7 +98,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -64,7 +64,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryList"
|
||||
@showSizeChange="queryList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -103,7 +103,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -79,7 +79,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -88,7 +88,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryHelpDocList"
|
||||
@showSizeChange="queryHelpDocList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -49,7 +49,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryViewRecord"
|
||||
@showSizeChange="queryViewRecord"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -117,7 +117,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryJobList"
|
||||
@showSizeChange="queryJobList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -71,7 +71,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryLogList"
|
||||
@showSizeChange="queryLogList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -136,7 +136,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryJobList"
|
||||
@showSizeChange="queryJobList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -102,7 +102,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="onSearch"
|
||||
@showSizeChange="onSearch"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -89,7 +89,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -47,7 +47,6 @@
|
||||
v-model:pageSize="queryParam.pageSize"
|
||||
:total="total"
|
||||
@change="queryList"
|
||||
@showSizeChange="queryList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -78,7 +78,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -12,6 +12,10 @@
|
||||
<div class="info-box">
|
||||
<a-row class="smart-margin-top10">
|
||||
<a-col :span="16">
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="12"> 用户id:{{ detail.operateUserId }}</a-col>
|
||||
<a-col :span="12"> 用户名称: {{ detail.operateUserName }}</a-col>
|
||||
</a-row>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="12"> 请求url: {{ detail.url }}</a-col>
|
||||
<a-col :span="12"> 请求日期: {{ detail.createTime }}</a-col>
|
||||
@ -21,8 +25,7 @@
|
||||
<a-col :span="12"> IP地区: {{ detail.ipRegion }}</a-col>
|
||||
</a-row>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="12"> 用户id:{{ detail.operateUserId }}</a-col>
|
||||
<a-col :span="12"> 用户名称: {{ detail.operateUserName }}</a-col>
|
||||
<a-col :span="12"> 客户端: {{ detail.os }} / {{ detail.browser }} {{ detail.device ? '/' + detail.device : detail.device }}</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
@ -32,21 +35,26 @@
|
||||
</a-typography-text>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<div class="info-box">
|
||||
<h4>请求明细:</h4>
|
||||
<a-col :span="24"> 方法: {{ detail.method }}</a-col>
|
||||
<a-col :span="24"> 说明: {{ detail.module }} - {{ detail.content }}</a-col>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="24"> 方法: {{ detail.method }}</a-col>
|
||||
</a-row>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="24"> 说明: {{ detail.module }} - {{ detail.content }}</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<div class="info-box">
|
||||
<h4>请求参数:</h4>
|
||||
<JsonViewer :value="detail.param ? JSON.parse(detail.param) : ''" theme="jv-dark" copyable boxed sort />
|
||||
<JsonViewer :value="detail.param ? JSON.parse(detail.param) : ''" :expanded="true" :expandDepth="10" copyable boxed sort theme="light" />
|
||||
</div>
|
||||
<div class="info-box" v-if="detail.successFlag">
|
||||
<h4>返回结果:</h4>
|
||||
<JsonViewer :value="detail.response ? JSON.parse(detail.response) : ''" :expanded="true" :expandDepth="10" copyable boxed sort theme="light" />
|
||||
</div>
|
||||
<div class="info-box" v-if="detail.failReason">
|
||||
<h4>请求失败原因:</h4>
|
||||
<div>
|
||||
<a-card>
|
||||
{{ detail.failReason }}
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
@ -57,6 +65,7 @@
|
||||
import { operateLogApi } from '/@/api/support/operate-log-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import uaparser from 'ua-parser-js';
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
@ -87,11 +96,16 @@
|
||||
param: '',
|
||||
url: '',
|
||||
});
|
||||
|
||||
async function getDetail(operateLogId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
let res = await operateLogApi.detail(operateLogId);
|
||||
detail = Object.assign(detail, res.data);
|
||||
let ua = uaparser(res.data.userAgent);
|
||||
detail.browser = ua.browser.name;
|
||||
detail.os = ua.os.name;
|
||||
detail.device = ua.device.vendor ? ua.device.vendor + ua.device.model : '';
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
@ -107,10 +121,11 @@
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
.detail-info {
|
||||
.ant-col {
|
||||
line-height: 1.46;
|
||||
@ -118,6 +133,7 @@
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-right-title {
|
||||
text-align: right;
|
||||
color: grey;
|
||||
|
@ -14,7 +14,7 @@
|
||||
<a-input style="width: 150px" v-model:value="queryForm.keywords" placeholder="模块/操作内容" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请求关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 220px" v-model:value="queryForm.requestKeywords" placeholder="请求地址/请求方法/请求参数" />
|
||||
<a-input style="width: 270px" v-model:value="queryForm.requestKeywords" placeholder="请求地址/请求方法/请求参数/返回结果" />
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名称" class="smart-query-form-item">
|
||||
<a-input style="width: 100px" v-model:value="queryForm.userName" placeholder="用户名称" />
|
||||
@ -24,7 +24,7 @@
|
||||
<a-range-picker @change="changeCreateDate" v-model:value="createDateRange" :presets="defaultChooseTimeRange" style="width: 240px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="快速筛选" class="smart-query-form-item">
|
||||
<a-form-item label="状态:" class="smart-query-form-item">
|
||||
<a-radio-group v-model:value="queryForm.successFlag" @change="onSearch">
|
||||
<a-radio-button :value="undefined">全部</a-radio-button>
|
||||
<a-radio-button :value="true">成功</a-radio-button>
|
||||
@ -51,18 +51,23 @@
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false" :hoverable="true" style="height: 100%">
|
||||
<a-card size="small" :bordered="false" :hoverable="true" >
|
||||
<a-row justify="end">
|
||||
<TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.SUPPORT.CONFIG" :refresh="ajaxQuery" />
|
||||
</a-row>
|
||||
<a-table size="small" :loading="tableLoading" :dataSource="tableData" :columns="columns" bordered rowKey="operateLogId" :pagination="false">
|
||||
<template #bodyCell="{ text, record, column }">
|
||||
<template v-if="column.dataIndex === 'response'">
|
||||
<a-typography-text v-if="text && text.ok">{{ text ? text.msg : '-' }}</a-typography-text>
|
||||
<a-typography-text v-else type="warning">{{ text ? text.msg : '-' }}</a-typography-text>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'successFlag'">
|
||||
<a-tag :color="text ? 'success' : 'error'">{{ text ? '成功' : '失败' }}</a-tag>
|
||||
<a-tag :color="text ? 'success' : 'error'">{{ text ? '成功' : '报错' }}</a-tag>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'userAgent'">
|
||||
<div>{{ record.browser }} / {{ record.os }} / {{ record.device }}</div>
|
||||
<div>{{ record.os }} / {{ record.browser }} {{ record.device ? '/' + record.device : record.device }}</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'operateUserType'">
|
||||
@ -88,7 +93,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
@ -135,14 +139,15 @@
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'IP',
|
||||
dataIndex: 'ip',
|
||||
title: '返回结果',
|
||||
dataIndex: 'response',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'IP地区',
|
||||
dataIndex: 'ipRegion',
|
||||
ellipsis: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '客户端',
|
||||
@ -150,20 +155,15 @@
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '请求方法',
|
||||
dataIndex: 'method',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '请求结果',
|
||||
dataIndex: 'successFlag',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
title: '操作时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'successFlag',
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
@ -212,6 +212,10 @@
|
||||
let responseModel = await operateLogApi.queryList(queryForm);
|
||||
|
||||
for (const e of responseModel.data.list) {
|
||||
if(e.response){
|
||||
e.response = JSON.parse(e.response);
|
||||
}
|
||||
|
||||
if (!e.userAgent) {
|
||||
continue;
|
||||
}
|
||||
|
@ -32,7 +32,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -63,7 +63,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -75,7 +75,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -68,7 +68,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -94,7 +94,6 @@
|
||||
v-model:pageSize="params.pageSize"
|
||||
:total="total"
|
||||
@change="queryEmployee"
|
||||
@showSizeChange="queryEmployee"
|
||||
:show-total="showTableTotal"
|
||||
/>
|
||||
</div>
|
||||
|
@ -8,23 +8,24 @@
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012
|
||||
-->
|
||||
<template>
|
||||
<a-modal :open="visible" width="600px" :bodyStyle="{height:'480px'}" title="" :closable="false" :maskClosable="true">
|
||||
<a-row><div style="font-weight:bolder;margin: 0 auto;font-size: 16px">助力卓大抖音1000个粉丝,开播写代码🎉🎉</div> </a-row>
|
||||
<a-row><div style="font-weight:bolder;margin: 20px auto;font-size: 15px">和1024创新实验室一起,热爱代码,热爱生活,永远年轻,永远前行🎉🎉</div> </a-row>
|
||||
<a-modal :open="visible" width="600px" :bodyStyle="{height:'360px'}" title="" :closable="false" :maskClosable="true">
|
||||
<a-row><div style="font-weight:bolder;margin: 0 auto;font-size: 16px;color: red;">重磅更新:国产数据库支持🎉🎉</div> </a-row>
|
||||
<a-row><div style="font-weight:bolder;margin: 10px auto;font-size: 16px;color: red;">支持:达梦、人大金仓、华为高斯GaussDB 等🎉🎉</div> </a-row>
|
||||
<br />
|
||||
<div class="app-qr-box">
|
||||
<div class="app-qr">
|
||||
<a-image
|
||||
:width="300"
|
||||
:width="200"
|
||||
style="border-radius: 15px;"
|
||||
src="https://img.smartadmin.1024lab.net/wechat/douyin.png"
|
||||
src="https://img.smartadmin.1024lab.net/wechat/zhuoda-wechat.jpg"
|
||||
/>
|
||||
|
||||
<span class="qr-desc strong"> 打开【抖音APP】-点击【左上角侧边栏】-【点击扫一扫】-【进行关注】</span>
|
||||
<span class="qr-desc strong"> 添加“卓大”微信,备注对应数据库,如 达梦</span>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button type="primary" @click="hide">知道了</a-button>
|
||||
<a-button type="default" @click="hide">知道了</a-button>
|
||||
<a-button danger type="default" @click="goto" target="_blank" href="https://smartadmin.vip/views/other/china-db/">去看看国产数据库,了解一下</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
@ -36,6 +37,9 @@ defineExpose({
|
||||
});
|
||||
|
||||
const visible = ref(true);
|
||||
function goto(){
|
||||
|
||||
}
|
||||
function show() {
|
||||
visible.value = true;
|
||||
}
|
||||
@ -64,8 +68,7 @@ defineExpose({
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
color: red;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
overflow-x: hidden;
|
||||
> img {
|
||||
|
@ -108,7 +108,7 @@
|
||||
let lunarMonth = lunar.getMonthInChinese();
|
||||
let lunarDay = lunar.getDayInChinese();
|
||||
//节气
|
||||
let jieqi = lunar.getPrevJieQi().getName();
|
||||
let jieqi = lunar.getJieQi();
|
||||
let next = lunar.getNextJieQi();
|
||||
let nextJieqi = next.getName() + ' ' + next.getSolar().toYmd();
|
||||
|
||||
|
@ -86,7 +86,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -68,7 +68,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryRoleEmployee"
|
||||
@showSizeChange="queryRoleEmployee"
|
||||
:show-total="showTableTotal"
|
||||
/>
|
||||
</div>
|
||||
|
@ -44,7 +44,7 @@
|
||||
"vue": "3.4.27",
|
||||
"vue-i18n": "9.13.1",
|
||||
"vue-router": "4.3.2",
|
||||
"vue3-json-viewer": "2.2.2"
|
||||
"vue3-json-viewer": "2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "5.1.4",
|
||||
|
@ -51,7 +51,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
<a-modal v-model:open="visibleDiff" width="90%" title="数据比对" :footer="null">
|
||||
|
@ -71,7 +71,6 @@
|
||||
v-model:pageSize="params.pageSize"
|
||||
:total="total"
|
||||
@change="queryEmployee"
|
||||
@showSizeChange="queryEmployee"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -27,7 +27,7 @@ export const appDefaultConfig = {
|
||||
// 圆角
|
||||
borderRadius: 6,
|
||||
// 菜单展开模式
|
||||
flatPattern: false,
|
||||
menuSingleExpandFlag: true,
|
||||
// 标签页
|
||||
pageTagFlag: true,
|
||||
// 标签页样式: default、 antd、chrome
|
||||
|
@ -21,11 +21,11 @@ export default {
|
||||
'setting.menu.layout': 'Menu Layout',
|
||||
'setting.menu.width': 'Menu Width',
|
||||
'setting.menu.theme': 'Menu Theme',
|
||||
'setting.menu.expand': 'Menu Expand',
|
||||
'setting.page.width': 'Page Width',
|
||||
'setting.border.radius': 'Border Radius',
|
||||
'setting.compact': 'Page Compact',
|
||||
'setting.bread': 'Show Bread',
|
||||
'setting.flatPattern': 'Flat Pattern',
|
||||
'setting.pagetag': 'Show PageTag',
|
||||
'setting.pagetag.style': 'PageTag Style',
|
||||
'setting.footer': 'Show Footer',
|
||||
|
@ -21,11 +21,11 @@ export default {
|
||||
'setting.menu.layout': '菜单布局',
|
||||
'setting.menu.width': '菜单宽度',
|
||||
'setting.menu.theme': '菜单主题',
|
||||
'setting.menu.expand': '菜单展开',
|
||||
'setting.compact': '页面紧凑',
|
||||
'setting.border.radius': '页面圆角',
|
||||
'setting.page.width': '页面宽度',
|
||||
'setting.bread': '面包屑',
|
||||
'setting.flatPattern': '菜单展开模式',
|
||||
'setting.pagetag': '标签页',
|
||||
'setting.pagetag.style': '标签页样式',
|
||||
'setting.footer': '页脚',
|
||||
|
@ -83,8 +83,8 @@
|
||||
<a-radio-button value="chrome">Chrome</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.flatPattern')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
|
||||
<a-switch @change="changeFlatPattern" v-model:checked="formState.flatPattern" checked-children="多个" un-checked-children="单个" />
|
||||
<a-form-item :label="$t('setting.menu.expand')" v-if="formState.layout === LAYOUT_ENUM.SIDE.value">
|
||||
<a-switch @change="changeMenuExpandFlag" v-model:checked="formState.menuSingleExpandFlag" checked-children="单个" un-checked-children="多个" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('setting.pagetag')">
|
||||
<a-switch @change="changePageTagFlag" v-model:checked="formState.pageTagFlag" checked-children="显示" un-checked-children="隐藏" />
|
||||
@ -213,8 +213,8 @@
|
||||
borderRadius: appConfigStore.borderRadius,
|
||||
// 标签页
|
||||
pageTagFlag: appConfigStore.pageTagFlag,
|
||||
// 标签页
|
||||
flatPattern: appConfigStore.flatPattern,
|
||||
// 菜单展开方式
|
||||
menuSingleExpandFlag: appConfigStore.menuSingleExpandFlag,
|
||||
// 标签页 样式
|
||||
pageTagStyle: appConfigStore.pageTagStyle,
|
||||
// 面包屑
|
||||
@ -303,9 +303,9 @@
|
||||
});
|
||||
}
|
||||
|
||||
function changeFlatPattern(e) {
|
||||
function changeMenuExpandFlag(e) {
|
||||
appConfigStore.$patch({
|
||||
flatPattern: e,
|
||||
menuSingleExpandFlag: e,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
import { useUserStore } from '/@/store/modules/system/user';
|
||||
|
||||
const theme = computed(() => useAppConfigStore().$state.sideMenuTheme);
|
||||
const flatPattern = computed(() => useAppConfigStore().$state.flatPattern);
|
||||
const menuSingleExpandFlag = computed(() => useAppConfigStore().$state.menuSingleExpandFlag);
|
||||
|
||||
const props = defineProps({
|
||||
collapsed: {
|
||||
@ -46,8 +46,7 @@
|
||||
});
|
||||
|
||||
const menuTree = computed(() => useUserStore().getMenuTree || []);
|
||||
const rootSubmenuKeys = computed(()=>menuTree.value.map(item=>item.menuId));
|
||||
|
||||
const rootSubmenuKeys = computed(() => menuTree.value.map((item) => item.menuId));
|
||||
|
||||
//展开的菜单
|
||||
let currentRoute = useRoute();
|
||||
@ -76,9 +75,15 @@
|
||||
let parentList = menuParentIdListMap.get(currentRoute.name) || [];
|
||||
|
||||
// 如果是折叠菜单的话,则不需要设置openkey
|
||||
if (!props.collapsed) {
|
||||
if (props.collapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let needOpenKeys = _.map(parentList, 'name').map(Number);
|
||||
if (menuSingleExpandFlag.value) {
|
||||
openKeys.value = [...needOpenKeys];
|
||||
} else {
|
||||
// 使用lodash的union函数,进行 去重合并两个数组
|
||||
let needOpenKeys = _.map(parentList, 'name').map(Number);
|
||||
openKeys.value = _.union(openKeys.value, needOpenKeys);
|
||||
}
|
||||
}
|
||||
@ -92,17 +97,18 @@
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
function onOpenChange(openKeysParams){
|
||||
if(flatPattern.value){
|
||||
return;
|
||||
|
||||
function onOpenChange(openKeysParams) {
|
||||
if (!menuSingleExpandFlag.value) {
|
||||
return;
|
||||
}
|
||||
const latestOpenKey = openKeysParams.find((key) => openKeys.value.indexOf(key) === -1);
|
||||
if (rootSubmenuKeys.value.indexOf(latestOpenKey) === -1) {
|
||||
openKeys.value = openKeysParams;
|
||||
} else {
|
||||
openKeys.value = latestOpenKey ? [latestOpenKey] : [];
|
||||
}
|
||||
}
|
||||
const latestOpenKey = openKeysParams.find(key => openKeys.value.indexOf(key) === -1);
|
||||
if (rootSubmenuKeys.value.indexOf(latestOpenKey) === -1) {
|
||||
openKeys.value = openKeysParams;
|
||||
} else {
|
||||
openKeys.value = latestOpenKey ? [latestOpenKey] : [];
|
||||
}
|
||||
};
|
||||
defineExpose({
|
||||
updateOpenKeysAndSelectKeys,
|
||||
});
|
||||
|
@ -149,7 +149,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -78,7 +78,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -63,7 +63,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryEmployee"
|
||||
@showSizeChange="queryEmployee"
|
||||
:show-total="showTableTotal"
|
||||
/>
|
||||
</div>
|
||||
|
@ -75,7 +75,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -102,7 +102,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -53,7 +53,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryViewRecord"
|
||||
@showSizeChange="queryViewRecord"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -72,7 +72,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryNoticeList"
|
||||
@showSizeChange="queryNoticeList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -122,7 +122,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryNoticeList"
|
||||
@showSizeChange="queryNoticeList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -107,7 +107,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -74,7 +74,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -66,7 +66,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -98,7 +98,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -64,7 +64,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryList"
|
||||
@showSizeChange="queryList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -103,7 +103,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -79,7 +79,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -88,7 +88,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryHelpDocList"
|
||||
@showSizeChange="queryHelpDocList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -49,7 +49,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryViewRecord"
|
||||
@showSizeChange="queryViewRecord"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -117,7 +117,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryJobList"
|
||||
@showSizeChange="queryJobList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -71,7 +71,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryLogList"
|
||||
@showSizeChange="queryLogList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -136,7 +136,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryJobList"
|
||||
@showSizeChange="queryJobList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -102,7 +102,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="onSearch"
|
||||
@showSizeChange="onSearch"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -89,7 +89,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -47,7 +47,6 @@
|
||||
v-model:pageSize="queryParam.pageSize"
|
||||
:total="total"
|
||||
@change="queryList"
|
||||
@showSizeChange="queryList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -78,7 +78,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
@ -12,6 +12,10 @@
|
||||
<div class="info-box">
|
||||
<a-row class="smart-margin-top10">
|
||||
<a-col :span="16">
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="12"> 用户id:{{ detail.operateUserId }}</a-col>
|
||||
<a-col :span="12"> 用户名称: {{ detail.operateUserName }}</a-col>
|
||||
</a-row>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="12"> 请求url: {{ detail.url }}</a-col>
|
||||
<a-col :span="12"> 请求日期: {{ detail.createTime }}</a-col>
|
||||
@ -21,8 +25,7 @@
|
||||
<a-col :span="12"> IP地区: {{ detail.ipRegion }}</a-col>
|
||||
</a-row>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="12"> 用户id:{{ detail.operateUserId }}</a-col>
|
||||
<a-col :span="12"> 用户名称: {{ detail.operateUserName }}</a-col>
|
||||
<a-col :span="12"> 客户端: {{ detail.os }} / {{ detail.browser }} {{ detail.device ? '/' + detail.device : detail.device }}</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
@ -32,21 +35,26 @@
|
||||
</a-typography-text>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<div class="info-box">
|
||||
<h4>请求明细:</h4>
|
||||
<a-col :span="24"> 方法: {{ detail.method }}</a-col>
|
||||
<a-col :span="24"> 说明: {{ detail.module }} - {{ detail.content }}</a-col>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="24"> 方法: {{ detail.method }}</a-col>
|
||||
</a-row>
|
||||
<a-row class="detail-info">
|
||||
<a-col :span="24"> 说明: {{ detail.module }} - {{ detail.content }}</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
<div class="info-box">
|
||||
<h4>请求参数:</h4>
|
||||
<JsonViewer :value="detail.param ? JSON.parse(detail.param) : ''" theme="jv-dark" copyable boxed sort />
|
||||
<JsonViewer :value="detail.param ? JSON.parse(detail.param) : ''" :expanded="true" :expandDepth="10" copyable boxed sort theme="light" />
|
||||
</div>
|
||||
<div class="info-box" v-if="detail.successFlag">
|
||||
<h4>返回结果:</h4>
|
||||
<JsonViewer :value="detail.response ? JSON.parse(detail.response) : ''" :expanded="true" :expandDepth="10" copyable boxed sort theme="light" />
|
||||
</div>
|
||||
<div class="info-box" v-if="detail.failReason">
|
||||
<h4>请求失败原因:</h4>
|
||||
<div>
|
||||
<a-card>
|
||||
{{ detail.failReason }}
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
@ -57,6 +65,7 @@
|
||||
import { operateLogApi } from '/@/api/support/operate-log-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import uaparser from 'ua-parser-js';
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
@ -87,11 +96,16 @@
|
||||
param: '',
|
||||
url: '',
|
||||
});
|
||||
|
||||
async function getDetail(operateLogId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
let res = await operateLogApi.detail(operateLogId);
|
||||
detail = Object.assign(detail, res.data);
|
||||
let ua = uaparser(res.data.userAgent);
|
||||
detail.browser = ua.browser.name;
|
||||
detail.os = ua.os.name;
|
||||
detail.device = ua.device.vendor ? ua.device.vendor + ua.device.model : '';
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
@ -107,10 +121,11 @@
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 10px 8px;
|
||||
}
|
||||
|
||||
.detail-info {
|
||||
.ant-col {
|
||||
line-height: 1.46;
|
||||
@ -118,6 +133,7 @@
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-right-title {
|
||||
text-align: right;
|
||||
color: grey;
|
||||
|
@ -14,7 +14,7 @@
|
||||
<a-input style="width: 150px" v-model:value="queryForm.keywords" placeholder="模块/操作内容" />
|
||||
</a-form-item>
|
||||
<a-form-item label="请求关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 220px" v-model:value="queryForm.requestKeywords" placeholder="请求地址/请求方法/请求参数" />
|
||||
<a-input style="width: 270px" v-model:value="queryForm.requestKeywords" placeholder="请求地址/请求方法/请求参数/返回结果" />
|
||||
</a-form-item>
|
||||
<a-form-item label="用户名称" class="smart-query-form-item">
|
||||
<a-input style="width: 100px" v-model:value="queryForm.userName" placeholder="用户名称" />
|
||||
@ -24,7 +24,7 @@
|
||||
<a-range-picker @change="changeCreateDate" v-model:value="createDateRange" :presets="defaultChooseTimeRange" style="width: 240px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="快速筛选" class="smart-query-form-item">
|
||||
<a-form-item label="状态:" class="smart-query-form-item">
|
||||
<a-radio-group v-model:value="queryForm.successFlag" @change="onSearch">
|
||||
<a-radio-button :value="undefined">全部</a-radio-button>
|
||||
<a-radio-button :value="true">成功</a-radio-button>
|
||||
@ -51,18 +51,23 @@
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false" :hoverable="true" style="height: 100%">
|
||||
<a-card size="small" :bordered="false" :hoverable="true" >
|
||||
<a-row justify="end">
|
||||
<TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.SUPPORT.CONFIG" :refresh="ajaxQuery" />
|
||||
</a-row>
|
||||
<a-table size="small" :loading="tableLoading" :dataSource="tableData" :columns="columns" bordered rowKey="operateLogId" :pagination="false">
|
||||
<template #bodyCell="{ text, record, column }">
|
||||
<template v-if="column.dataIndex === 'response'">
|
||||
<a-typography-text v-if="text && text.ok">{{ text ? text.msg : '-' }}</a-typography-text>
|
||||
<a-typography-text v-else type="warning">{{ text ? text.msg : '-' }}</a-typography-text>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'successFlag'">
|
||||
<a-tag :color="text ? 'success' : 'error'">{{ text ? '成功' : '失败' }}</a-tag>
|
||||
<a-tag :color="text ? 'success' : 'error'">{{ text ? '成功' : '报错' }}</a-tag>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'userAgent'">
|
||||
<div>{{ record.browser }} / {{ record.os }} / {{ record.device }}</div>
|
||||
<div>{{ record.os }} / {{ record.browser }} {{ record.device ? '/' + record.device : record.device }}</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'operateUserType'">
|
||||
@ -88,7 +93,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
@ -135,14 +139,15 @@
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'IP',
|
||||
dataIndex: 'ip',
|
||||
title: '返回结果',
|
||||
dataIndex: 'response',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: 'IP地区',
|
||||
dataIndex: 'ipRegion',
|
||||
ellipsis: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '客户端',
|
||||
@ -150,20 +155,15 @@
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '请求方法',
|
||||
dataIndex: 'method',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '请求结果',
|
||||
dataIndex: 'successFlag',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '时间',
|
||||
title: '操作时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'successFlag',
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
@ -212,6 +212,10 @@
|
||||
let responseModel = await operateLogApi.queryList(queryForm);
|
||||
|
||||
for (const e of responseModel.data.list) {
|
||||
if(e.response){
|
||||
e.response = JSON.parse(e.response);
|
||||
}
|
||||
|
||||
if (!e.userAgent) {
|
||||
continue;
|
||||
}
|
||||
|
@ -32,7 +32,6 @@
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user