feat(sysapi): 重构接口日志查询支持动态表名与报文检索
- 替换Java硬编码查询为MyBatis XML动态SQL,支持动态切换日志表 - 新增请求报文与响应报文关键字搜索条件 - 前端字段映射由驼峰调整为下划线,适配Map返回结构 - 日志详情新增JSON一键复制功能与归档遮罩动画
This commit is contained in:
@@ -40,67 +40,12 @@ public class SysApiLogController {
|
||||
private final ISysApiLogHistoryService apiLogHistoryService;
|
||||
|
||||
/**
|
||||
* 分页查询接口日志列表
|
||||
* 分页查询接口日志列表(走XML动态SQL,支持动态表名)
|
||||
*/
|
||||
@GetMapping
|
||||
@Log("查询接口日志列表")
|
||||
public ResponseEntity<Map<String, Object>> query(ApiLogQuery query) {
|
||||
LambdaQueryWrapper<SysApiLog> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
if (query.getDirection() != null) {
|
||||
wrapper.eq(SysApiLog::getDirection, query.getDirection());
|
||||
}
|
||||
|
||||
if (query.getSystemFlag() != null && !query.getSystemFlag().isEmpty()) {
|
||||
wrapper.eq(SysApiLog::getSystemFlag, query.getSystemFlag());
|
||||
}
|
||||
|
||||
if (query.getBizCode() != null && !query.getBizCode().isEmpty()) {
|
||||
wrapper.eq(SysApiLog::getBizCode, query.getBizCode());
|
||||
}
|
||||
|
||||
if (query.getTraceId() != null && !query.getTraceId().isEmpty()) {
|
||||
wrapper.eq(SysApiLog::getTraceId, query.getTraceId());
|
||||
}
|
||||
|
||||
if (query.getApiUrl() != null && !query.getApiUrl().isEmpty()) {
|
||||
wrapper.like(SysApiLog::getApiUrl, query.getApiUrl());
|
||||
}
|
||||
|
||||
if (query.getStatus() != null && !query.getStatus().isEmpty()) {
|
||||
wrapper.eq(SysApiLog::getStatus, query.getStatus());
|
||||
}
|
||||
|
||||
if (query.getBegin_time() != null && !query.getBegin_time().isEmpty()) {
|
||||
String beginTime = query.getBegin_time() + " 00:00:00";
|
||||
wrapper.ge(SysApiLog::getCreateTime, beginTime);
|
||||
}
|
||||
|
||||
if (query.getEnd_time() != null && !query.getEnd_time().isEmpty()) {
|
||||
String endTime = query.getEnd_time() + " 23:59:59";
|
||||
wrapper.le(SysApiLog::getCreateTime, endTime);
|
||||
}
|
||||
|
||||
if (query.getKeyword() != null && !query.getKeyword().isEmpty()) {
|
||||
wrapper.and(w -> w.like(SysApiLog::getBizDesc, query.getKeyword())
|
||||
.or().like(SysApiLog::getApiDesc, query.getKeyword())
|
||||
.or().like(SysApiLog::getRequestParams, query.getKeyword())
|
||||
.or().like(SysApiLog::getResponseBody, query.getKeyword()));
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(SysApiLog::getCreateTime);
|
||||
|
||||
Page<SysApiLog> page = new Page<>(query.getPage()+1, query.getSize());
|
||||
IPage<SysApiLog> result = apiLogService.page(page, wrapper);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("content", result.getRecords());
|
||||
response.put("totalElements", result.getTotal());
|
||||
response.put("totalPages", result.getPages());
|
||||
response.put("size", result.getSize());
|
||||
response.put("number", result.getCurrent());
|
||||
|
||||
return new ResponseEntity<>(response, HttpStatus.OK);
|
||||
public ResponseEntity<Object> query(ApiLogQuery query) {
|
||||
return new ResponseEntity<>(apiLogService.queryApiLog(query), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package org.nl.system.service.sysapi.entity.dto;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import lombok.Data;
|
||||
import org.nl.common.domain.query.PageQuery;
|
||||
|
||||
@@ -30,5 +31,13 @@ public class ApiLogQuery extends PageQuery {
|
||||
|
||||
private String keyword;
|
||||
|
||||
private String requestParams;
|
||||
|
||||
private String responseParams;
|
||||
|
||||
/**
|
||||
* 动态表名,从前台传入,如:sys_api_log 或 sys_api_log_history
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
package org.nl.system.service.sysapi.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.nl.system.service.sysapi.entity.SysApiLog;
|
||||
import org.nl.system.service.sysapi.entity.dto.ApiLogQuery;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ManMan.Yang
|
||||
@@ -13,4 +18,11 @@ import org.nl.system.service.sysapi.entity.SysApiLog;
|
||||
|
||||
@Mapper
|
||||
public interface SysApiLogMapper extends BaseMapper<SysApiLog> {
|
||||
|
||||
/**
|
||||
* 分页查询接口日志(动态表名)
|
||||
* @param query 查询条件
|
||||
* @return List<Map>
|
||||
*/
|
||||
List<Map> queryApiLog(@Param("query") ApiLogQuery query);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.nl.system.service.sysapi.mapper.SysApiLogMapper">
|
||||
|
||||
<select id="queryApiLog" resultType="java.util.Map">
|
||||
SELECT
|
||||
t.log_id,
|
||||
t.direction,
|
||||
t.system_flag,
|
||||
t.biz_code,
|
||||
t.biz_desc,
|
||||
t.api_url,
|
||||
t.api_desc,
|
||||
t.trace_id,
|
||||
t.request_method,
|
||||
t.request_ip,
|
||||
t.request_headers,
|
||||
t.request_params,
|
||||
t.response_body,
|
||||
t.response_status,
|
||||
t.cost_time,
|
||||
t.status,
|
||||
t.error_msg,
|
||||
t.operator,
|
||||
t.create_time
|
||||
FROM
|
||||
${query.tableName} t
|
||||
<where>
|
||||
1 = 1
|
||||
|
||||
<if test="query.direction != null">
|
||||
and t.direction = #{query.direction}
|
||||
</if>
|
||||
|
||||
<if test="query.systemFlag != null and query.systemFlag != ''">
|
||||
and t.system_flag = #{query.systemFlag}
|
||||
</if>
|
||||
|
||||
<if test="query.bizCode != null and query.bizCode != ''">
|
||||
and t.biz_code = #{query.bizCode}
|
||||
</if>
|
||||
|
||||
<if test="query.traceId != null and query.traceId != ''">
|
||||
and t.trace_id = #{query.traceId}
|
||||
</if>
|
||||
|
||||
<if test="query.status != null and query.status != ''">
|
||||
and t.status = #{query.status}
|
||||
</if>
|
||||
|
||||
<if test="query.begin_time != null and query.begin_time != ''">
|
||||
and t.create_time <![CDATA[ >= ]]> CONCAT(#{query.begin_time}, ' 00:00:00')
|
||||
</if>
|
||||
|
||||
<if test="query.end_time != null and query.end_time != ''">
|
||||
and t.create_time <![CDATA[ <= ]]> CONCAT(#{query.end_time}, ' 23:59:59')
|
||||
</if>
|
||||
|
||||
<if test="query.requestParams != null and query.requestParams != ''">
|
||||
and t.request_params LIKE CONCAT('%', #{query.requestParams}, '%')
|
||||
</if>
|
||||
|
||||
<if test="query.responseParams != null and query.responseParams != ''">
|
||||
and t.response_body LIKE CONCAT('%', #{query.responseParams}, '%')
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY t.create_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -2,9 +2,12 @@ package org.nl.system.service.sysapi.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.nl.system.service.sysapi.entity.SysApiLog;
|
||||
import org.nl.system.service.sysapi.entity.dto.ApiLogQuery;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ManMan.Yang
|
||||
* @version V1.1
|
||||
@@ -18,4 +21,11 @@ public interface ISysApiLogService extends IService<SysApiLog> {
|
||||
void saveAsync(SysApiLog apiLog);
|
||||
|
||||
ResponseEntity<T> archiveLogs();
|
||||
|
||||
/**
|
||||
* 分页查询接口日志(走XML动态SQL)
|
||||
* @param query 查询条件
|
||||
* @return Object
|
||||
*/
|
||||
Object queryApiLog(ApiLogQuery query);
|
||||
}
|
||||
|
||||
@@ -3,13 +3,17 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.nl.common.TableDataInfo;
|
||||
import org.nl.common.utils.IdUtil;
|
||||
import org.nl.modules.wql.util.SpringContextHolder;
|
||||
import org.nl.system.service.param.impl.SysParamServiceImpl;
|
||||
import org.nl.system.service.sysapi.entity.SysApiLog;
|
||||
import org.nl.system.service.sysapi.entity.SysApiLogHistory;
|
||||
import org.nl.system.service.sysapi.entity.dto.ApiLogQuery;
|
||||
import org.nl.system.service.sysapi.mapper.SysApiLogHistoryMapper;
|
||||
import org.nl.system.service.sysapi.mapper.SysApiLogMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -20,6 +24,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -91,4 +96,18 @@ public class SysApiLogServiceImpl extends ServiceImpl<SysApiLogMapper, SysApiLog
|
||||
throw new RuntimeException("日志归档失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object queryApiLog(ApiLogQuery query) {
|
||||
// 默认查主表 sys_api_log
|
||||
if (StrUtil.isEmpty(query.getTableName())) {
|
||||
query.setTableName("sys_api_log");
|
||||
}
|
||||
// 使用 PageHelper 分页(排序已在 XML 中定义)
|
||||
Page<Object> page = PageHelper.startPage(query.getPage() + 1, query.getSize());
|
||||
List<Map> list = this.baseMapper.queryApiLog(query);
|
||||
TableDataInfo<Map> build = TableDataInfo.build(list);
|
||||
build.setTotalElements(page.getTotal());
|
||||
return build;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getBizCodeList(systemFlag,direction) {
|
||||
export function getBizCodeList(systemFlag, direction) {
|
||||
return request({
|
||||
url: 'api/sysApiLog/bizCodeList',
|
||||
method: 'get',
|
||||
|
||||
@@ -6,29 +6,31 @@
|
||||
:inline="true"
|
||||
class="demo-form-inline"
|
||||
label-position="right"
|
||||
label-width="90px"
|
||||
label-width="120px"
|
||||
label-suffix=":"
|
||||
>
|
||||
<el-form-item label="关键字">
|
||||
<el-input
|
||||
v-model="query.keyword"
|
||||
clearable
|
||||
<el-form-item label="查询日志表">
|
||||
<el-select
|
||||
v-model="query.tableName"
|
||||
size="mini"
|
||||
placeholder="请输入关键字查询"
|
||||
class="filter-item"
|
||||
style="width: 200px;"
|
||||
/>
|
||||
@change="handleTableNameChange"
|
||||
>
|
||||
<el-option label="sys_api_log" value="sys_api_log" />
|
||||
<el-option label="sys_api_log_history" value="sys_api_log_history" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="接口走向">
|
||||
<el-form-item label="接口走向类型">
|
||||
<el-select
|
||||
v-model="query.direction"
|
||||
clearable
|
||||
size="mini"
|
||||
placeholder="请选择"
|
||||
class="filter-item"
|
||||
@change="directionChanged"
|
||||
>
|
||||
<el-option label="出站" :value="0" />
|
||||
<el-option label="入站" :value="1" />
|
||||
<el-option label="LMS请求外部系统" :value="0" />
|
||||
<el-option label="外部系统请求LMS" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="系统标识">
|
||||
@@ -50,7 +52,6 @@
|
||||
<el-select
|
||||
v-model="query.bizCode"
|
||||
clearable
|
||||
filterable
|
||||
size="mini"
|
||||
placeholder="请选择"
|
||||
class="filter-item"
|
||||
@@ -85,6 +86,26 @@
|
||||
value-format="yyyy-MM-dd"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="请求报文">
|
||||
<el-input
|
||||
v-model="query.requestParams"
|
||||
clearable
|
||||
size="mini"
|
||||
placeholder="请输入请求报文关键字查询"
|
||||
class="filter-item"
|
||||
style="width: 200px;"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="响应报文">
|
||||
<el-input
|
||||
v-model="query.responseParams"
|
||||
clearable
|
||||
size="mini"
|
||||
placeholder="请输入响应报文关键字查询"
|
||||
class="filter-item"
|
||||
style="width: 200px;"
|
||||
/>
|
||||
</el-form-item>
|
||||
<rrOperation />
|
||||
</el-form>
|
||||
</div>
|
||||
@@ -94,7 +115,6 @@
|
||||
class="filter-item"
|
||||
type="primary"
|
||||
icon="el-icon-folder-checked"
|
||||
:loading="archiveLoading"
|
||||
@click="handleArchive"
|
||||
>
|
||||
日志归档
|
||||
@@ -117,29 +137,31 @@
|
||||
<el-tag v-else-if="scope.row.direction === 1" type="primary"><i class="el-icon-download"></i>入站</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="systemFlag" label="系统标识" width="100" />
|
||||
<el-table-column prop="bizCode" label="业务类型" width="260" />
|
||||
<el-table-column prop="bizDesc" label="业务描述" show-overflow-tooltip width="500" />
|
||||
<el-table-column prop="system_flag" label="系统标识" width="100" />
|
||||
<el-table-column prop="biz_code" label="业务类型" width="260" />
|
||||
<el-table-column prop="biz_desc" label="业务描述" show-overflow-tooltip width="500" />
|
||||
<el-table-column prop="request_method" label="请求协议" show-overflow-tooltip min-width="200" />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status === 'SUCCESS'" type="success">请求成功</el-tag>
|
||||
<el-tag v-else-if="scope.row.status === 'FAIL'" type="danger">请求失败</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="costTime" label="耗时(ms)" width="100" align="center">
|
||||
<el-table-column prop="cost_time" label="耗时(ms)" width="100" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.costTime <= 300" type="success">{{ scope.row.costTime }}ms</el-tag>
|
||||
<el-tag v-else-if="scope.row.costTime <= 1000" type="warning">{{ scope.row.costTime }}ms</el-tag>
|
||||
<el-tag v-else type="danger">{{ scope.row.costTime }}ms</el-tag>
|
||||
<el-tag v-if="scope.row.cost_time <= 300" type="success">{{ scope.row.cost_time }}ms</el-tag>
|
||||
<el-tag v-else-if="scope.row.cost_time <= 1000" type="warning">{{ scope.row.cost_time }}ms</el-tag>
|
||||
<el-tag v-else type="danger">{{ scope.row.cost_time }}ms</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="请求时间" width="180">
|
||||
<el-table-column prop="create_time" label="请求时间" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
<span>{{ parseTime(scope.row.create_time) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="requestParams" label="请求参数" show-overflow-tooltip min-width="200" />
|
||||
<el-table-column prop="responseBody" label="响应结果" show-overflow-tooltip min-width="200" />
|
||||
|
||||
<el-table-column prop="request_params" label="请求报文" show-overflow-tooltip min-width="200" />
|
||||
<el-table-column prop="response_body" label="响应报文" show-overflow-tooltip min-width="200" />
|
||||
<el-table-column label="详情" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="primary" plain @click="showDetail(scope.row)">查看详情</el-button>
|
||||
@@ -159,40 +181,57 @@
|
||||
>
|
||||
<div class="drawer-content">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="日志ID">{{ currentRow.logId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="链路追踪ID">{{ currentRow.traceId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="日志ID">{{ currentRow.log_id }}</el-descriptions-item>
|
||||
<el-descriptions-item label="接口走向">
|
||||
<el-tag v-if="currentRow.direction === 0" type="success" size="small"><i class="el-icon-upload2"></i>出站</el-tag>
|
||||
<el-tag v-else-if="currentRow.direction === 1" type="primary" size="small"><i class="el-icon-download"></i>入站</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="系统标识">{{ currentRow.systemFlag }}</el-descriptions-item>
|
||||
<el-descriptions-item label="业务类型">{{ currentRow.bizCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="业务描述">{{ currentRow.bizDesc }}</el-descriptions-item>
|
||||
<el-descriptions-item label="接口地址" :span="2">{{ currentRow.apiUrl }}</el-descriptions-item>
|
||||
<el-descriptions-item label="请求方法">{{ currentRow.requestMethod }}</el-descriptions-item>
|
||||
<el-descriptions-item label="请求IP">{{ currentRow.requestIp }}</el-descriptions-item>
|
||||
<el-descriptions-item label="系统标识">{{ currentRow.system_flag }}</el-descriptions-item>
|
||||
<el-descriptions-item label="业务类型">{{ currentRow.biz_code }}</el-descriptions-item>
|
||||
<el-descriptions-item label="业务描述">{{ currentRow.biz_desc }}</el-descriptions-item>
|
||||
<el-descriptions-item label="接口地址" :span="2">{{ currentRow.api_url }}</el-descriptions-item>
|
||||
<el-descriptions-item label="请求方法">{{ currentRow.request_method }}</el-descriptions-item>
|
||||
<el-descriptions-item label="请求IP">{{ currentRow.request_ip }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag v-if="currentRow.status === 'SUCCESS'" type="success" size="small">SUCCESS</el-tag>
|
||||
<el-tag v-else-if="currentRow.status === 'FAIL'" type="danger" size="small">FAIL</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="响应状态码">{{ currentRow.responseStatus }}</el-descriptions-item>
|
||||
<el-descriptions-item label="耗时">{{ currentRow.costTime }}ms</el-descriptions-item>
|
||||
<el-descriptions-item label="请求时间">{{ parseTime(currentRow.createTime) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="错误信息" :span="2" v-if="currentRow.errorMsg">
|
||||
<span style="color: #f56c6c;">{{ currentRow.errorMsg }}</span>
|
||||
<el-descriptions-item label="响应状态码">{{ currentRow.response_status }}</el-descriptions-item>
|
||||
<el-descriptions-item label="耗时">{{ currentRow.cost_time }}ms</el-descriptions-item>
|
||||
<el-descriptions-item label="请求时间">{{ parseTime(currentRow.create_time) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="错误信息" :span="2" v-if="currentRow.error_msg">
|
||||
<span style="color: #f56c6c;">{{ currentRow.error_msg }}</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider content-position="left">请求头</el-divider>
|
||||
<pre class="json-content">{{ formatJson(currentRow.requestHeaders) }}</pre>
|
||||
<div class="json-wrapper">
|
||||
<el-button class="copy-btn" type="text" icon="el-icon-document-copy" @click="copyJson(currentRow.request_headers)">复制</el-button>
|
||||
<pre class="json-content">{{ formatJson(currentRow.request_headers) }}</pre>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">请求参数</el-divider>
|
||||
<pre class="json-content">{{ formatJson(currentRow.requestParams) }}</pre>
|
||||
<el-divider content-position="left">请求报文</el-divider>
|
||||
<div class="json-wrapper">
|
||||
<el-button class="copy-btn" type="text" icon="el-icon-document-copy" @click="copyJson(currentRow.request_params)">复制</el-button>
|
||||
<pre class="json-content">{{ formatJson(currentRow.request_params) }}</pre>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">响应结果</el-divider>
|
||||
<pre class="json-content">{{ formatJson(currentRow.responseBody) }}</pre>
|
||||
<el-divider content-position="left">响应报文</el-divider>
|
||||
<div class="json-wrapper">
|
||||
<el-button class="copy-btn" type="text" icon="el-icon-document-copy" @click="copyJson(currentRow.response_body)">复制</el-button>
|
||||
<pre class="json-content">{{ formatJson(currentRow.response_body) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</el-drawer>
|
||||
<!-- 归档全局遮罩 -->
|
||||
<div v-if="archiveLoading" class="archive-overlay">
|
||||
<div class="archive-overlay__box">
|
||||
<p>日志归档中,请稍候...</p>
|
||||
<div class="archive-overlay__bar">
|
||||
<div class="archive-overlay__bar-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -216,7 +255,13 @@ export default {
|
||||
title: '接口日志',
|
||||
url: 'api/sysApiLog',
|
||||
query: {
|
||||
createTime: [dateStr, dateStr]
|
||||
createTime: [dateStr, dateStr],
|
||||
tableName: 'sys_api_log',
|
||||
direction: null,
|
||||
systemFlag: null,
|
||||
bizCode: null, // 关键:提前声明,Vue.observable 才能追踪
|
||||
status: null,
|
||||
keyword: null
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -238,15 +283,20 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSystemFlagChange() {
|
||||
this.query.bizCode = undefined
|
||||
handleTableNameChange(){
|
||||
this.query.direction = null;
|
||||
this.query.systemFlag = null
|
||||
this.query.bizCode = null
|
||||
this.bizCodeList = []
|
||||
if (this.query.systemFlag) {
|
||||
},
|
||||
handleSystemFlagChange() {
|
||||
this.query.bizCode = null
|
||||
this.bizCodeList = []
|
||||
if (this.query.systemFlag != null && this.query.systemFlag !== '' && this.query.direction != null && this.query.direction !== '') {
|
||||
apiLog.getBizCodeList(this.query.systemFlag, this.query.direction).then(res => {
|
||||
this.bizCodeList = res
|
||||
})
|
||||
}
|
||||
this.crud.toQuery()
|
||||
},
|
||||
showDetail(row) {
|
||||
this.currentRow = row
|
||||
@@ -256,6 +306,11 @@ export default {
|
||||
this.drawerVisible = false
|
||||
this.currentRow = {}
|
||||
},
|
||||
directionChanged() {
|
||||
this.query.systemFlag = null
|
||||
this.query.bizCode = null
|
||||
this.bizCodeList = []
|
||||
},
|
||||
formatJson(json) {
|
||||
if (!json) return ''
|
||||
try {
|
||||
@@ -264,6 +319,30 @@ export default {
|
||||
return json
|
||||
}
|
||||
},
|
||||
copyJson(raw) {
|
||||
if (!raw) {
|
||||
this.$message.warning('暂无内容可复制')
|
||||
return
|
||||
}
|
||||
let text = raw
|
||||
try {
|
||||
text = JSON.stringify(JSON.parse(raw), null, 2)
|
||||
} catch (e) {
|
||||
// 非 JSON 格式,直接使用原始文本
|
||||
}
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
this.$message.success('已复制到剪贴板')
|
||||
}).catch(() => {
|
||||
// 降级方案
|
||||
const textarea = document.createElement('textarea')
|
||||
textarea.value = text
|
||||
document.body.appendChild(textarea)
|
||||
textarea.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(textarea)
|
||||
this.$message.success('已复制到剪贴板')
|
||||
})
|
||||
},
|
||||
handleArchive() {
|
||||
this.$confirm('确认将历史接口日志数据进行归档备份吗?此操作可能需要较长时间。', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
@@ -328,6 +407,24 @@ export default {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.json-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 10;
|
||||
color: #409eff;
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
color: #66b1ff;
|
||||
}
|
||||
|
||||
::v-deep .el-drawer__header {
|
||||
margin-bottom: 10px;
|
||||
padding: 15px 20px;
|
||||
@@ -344,15 +441,56 @@ export default {
|
||||
.biz-code-item .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
::v-deep .el-drawer__body {
|
||||
padding: 0;
|
||||
}
|
||||
.biz-code-item {
|
||||
min-width: 350px;
|
||||
|
||||
.archive-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.45);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.biz-code-item .el-select {
|
||||
.archive-overlay__box {
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
.archive-overlay__box p {
|
||||
margin-bottom: 20px;
|
||||
font-size: 18px;
|
||||
letter-spacing: 4px;
|
||||
color: aqua;
|
||||
}
|
||||
|
||||
.archive-overlay__bar {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
background-color: rgba(255, 255, 255, 0.55);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.archive-overlay__bar-inner {
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
background-color: aqua;
|
||||
border-radius: 4px;
|
||||
animation: archive-bar-slide 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes archive-bar-slide {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(430%);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user