Browse Source

feat: 系统日志

master
buaixuexideshitongxue 1 month ago
parent
commit
ecf4129dfc
  1. 11
      src/api/system/systemLog.ts
  2. 314
      src/views/system/SystemLog.vue

11
src/api/system/systemLog.ts

@ -0,0 +1,11 @@
import request from "@/api/request";
/**
* 访
*/
export function listSystemLog(query) {
return request.get({
url: "/systemLog",
query,
});
}

314
src/views/system/SystemLog.vue

@ -0,0 +1,314 @@
<template>
<div class="container">
<header class="mb-20">
<el-form :label-width="100">
<el-row :gutter="12">
<el-col :span="6">
<el-form-item label="请求人">
<el-input
v-model="query.requester"
placeholder="请输入登录名或姓名"
clearable
@keyup.enter="search"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="接口地址">
<el-input
v-model="query.requestUri"
placeholder="请输入接口地址"
clearable
@keyup.enter="search"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="访问方式">
<el-select
v-model="query.requestMethod"
placeholder="请选择访问方式"
clearable
>
<el-option
v-for="method in requestMethods"
:key="method"
:label="method"
:value="method"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="来源IP">
<el-input
v-model="query.sourceIp"
placeholder="请输入来源IP"
clearable
@keyup.enter="search"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="12">
<el-col :span="6">
<el-form-item label="执行结果">
<el-select
v-model="query.status"
placeholder="请选择执行结果"
clearable
>
<el-option label="成功" :value="1" />
<el-option label="失败" :value="0" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="日志时间">
<el-date-picker
v-model="query.logTimeRange"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
format="YYYY-MM-DD HH:mm:ss"
range-separator="~"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex end">
<el-button type="primary" @click="search">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询
</el-button>
<el-button @click="reset">重置</el-button>
</div>
</header>
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
<el-tab-pane label="登录日志" name="login" />
<el-tab-pane label="操作日志" name="operation" />
</el-tabs>
<div class="table-container">
<el-table :data="logs">
<el-table-column label="请求人" min-width="160">
<template #default="{ row }">
{{ formatRequester(row) }}
</template>
</el-table-column>
<el-table-column
label="接口地址"
prop="requestUri"
min-width="220"
show-overflow-tooltip
/>
<el-table-column
label="访问方式"
prop="requestMethod"
width="100"
align="center"
/>
<el-table-column
label="来源IP"
prop="sourceIp"
min-width="140"
show-overflow-tooltip
/>
<el-table-column label="请求参数" min-width="220">
<template #default="{ row }">
<span class="summary-text">{{ formatSummary(row.requestParams) }}</span>
</template>
</el-table-column>
<el-table-column label="执行耗时" width="110" align="center">
<template #default="{ row }">
{{ row.executionTime }} ms
</template>
</el-table-column>
<el-table-column label="执行结果" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'">
{{ row.status === 1 ? "成功" : "失败" }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="日志时间"
prop="logTime"
width="180"
/>
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="showDetail(row)">
查看详情
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex end mt-8">
<el-pagination
v-model:page-size="query.size"
v-model:current-page="query.current"
:page-sizes="[10, 20, 50]"
:total="total"
layout="total, sizes, prev, pager, next"
@size-change="handleSizeChange"
@current-change="getList"
/>
</div>
</div>
<el-dialog v-model="detailVisible" title="系统日志详情" width="760px">
<el-descriptions :column="2" border>
<el-descriptions-item label="请求人">
{{ formatRequester(activeLog) }}
</el-descriptions-item>
<el-descriptions-item label="日志时间">
{{ activeLog.logTime || "-" }}
</el-descriptions-item>
<el-descriptions-item label="接口地址" :span="2">
{{ activeLog.requestUri || "-" }}
</el-descriptions-item>
<el-descriptions-item label="访问方式">
{{ activeLog.requestMethod || "-" }}
</el-descriptions-item>
<el-descriptions-item label="来源IP">
{{ activeLog.sourceIp || "-" }}
</el-descriptions-item>
<el-descriptions-item label="执行耗时">
{{ activeLog.executionTime ?? 0 }} ms
</el-descriptions-item>
<el-descriptions-item label="执行结果">
<el-tag :type="activeLog.status === 1 ? 'success' : 'danger'">
{{ activeLog.status === 1 ? "成功" : "失败" }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="请求参数" :span="2">
<pre class="detail-content">{{ activeLog.requestParams || "-" }}</pre>
</el-descriptions-item>
<el-descriptions-item label="异常信息" :span="2">
<pre class="detail-content error-content">{{ activeLog.errorMessage || "-" }}</pre>
</el-descriptions-item>
</el-descriptions>
<template #footer>
<el-button @click="detailVisible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { listSystemLog } from "@/api/system/systemLog";
const requestMethods = ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"];
const createDefaultQuery = () => ({
current: 1,
size: 10,
requester: undefined,
requestUri: undefined,
requestMethod: undefined,
sourceIp: undefined,
status: undefined,
logTimeRange: [],
});
const query = ref(createDefaultQuery());
const logs = ref([]);
const total = ref(0);
const detailVisible = ref(false);
const activeLog = ref({});
const activeTab = ref("login");
/**
* 将页面时间范围拆分成后端接收的开始结束时间参数
*/
function buildQueryParams() {
const { logTimeRange, ...params } = query.value;
params.logType = activeTab.value;
if (logTimeRange?.length === 2) {
params.startTime = logTimeRange[0];
params.endTime = logTimeRange[1];
}
return params;
}
function getList() {
listSystemLog(buildQueryParams()).then((data) => {
logs.value = data.records;
total.value = data.total;
});
}
function search() {
query.value.current = 1;
getList();
}
function reset() {
query.value = createDefaultQuery();
getList();
}
function handleSizeChange() {
query.value.current = 1;
getList();
}
function handleTabChange() {
query.value.current = 1;
getList();
}
function formatRequester(row = {}) {
if (row.nickName && row.userName) {
return `${row.nickName}${row.userName}`;
}
return row.nickName || row.userName || "匿名/外部调用";
}
function formatSummary(value) {
if (!value) {
return "-";
}
return value.length > 60 ? `${value.slice(0, 60)}...` : value;
}
function showDetail(row) {
activeLog.value = row;
detailVisible.value = true;
}
getList();
</script>
<style lang="scss" scoped>
.summary-text {
display: inline-block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
.detail-content {
margin: 0;
max-height: 260px;
overflow: auto;
white-space: pre-wrap;
overflow-wrap: anywhere;
font-family: inherit;
line-height: 1.6;
}
.error-content {
color: var(--el-color-danger);
}
</style>
Loading…
Cancel
Save