124
src/api/system/log.ts
Normal file
124
src/api/system/log.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
const LOG_BASE_URL = "/api/v1/logs";
|
||||
|
||||
class LogAPI {
|
||||
/**
|
||||
* 获取日志分页列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
*/
|
||||
static getPage(queryParams: LogPageQuery) {
|
||||
return request<PageResult<LogPageVO[]>>({
|
||||
url: `${LOG_BASE_URL}/page`,
|
||||
method: "GET",
|
||||
data: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取访问趋势
|
||||
*
|
||||
* @param queryParams
|
||||
* @returns
|
||||
*/
|
||||
static getVisitTrend(queryParams: VisitTrendQuery) {
|
||||
return request<VisitTrendVO>({
|
||||
url: `${LOG_BASE_URL}/visit-trend`,
|
||||
method: "GET",
|
||||
data: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取访问趋势
|
||||
*
|
||||
* @param queryParams
|
||||
* @returns
|
||||
*/
|
||||
static getVisitStats() {
|
||||
return request<VisitStatsVO[]>({
|
||||
url: `${LOG_BASE_URL}/visit-stats`,
|
||||
method: "GET",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default LogAPI;
|
||||
|
||||
/**
|
||||
* 日志分页查询对象
|
||||
*/
|
||||
export interface LogPageQuery extends PageQuery {
|
||||
/** 搜索关键字 */
|
||||
keywords: string;
|
||||
/** 操作时间 */
|
||||
createTime: [string, string];
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统日志分页VO
|
||||
*/
|
||||
export interface LogPageVO {
|
||||
/** 主键 */
|
||||
id?: number;
|
||||
/** 日志模块 */
|
||||
module?: string;
|
||||
/** 日志内容 */
|
||||
content?: string;
|
||||
/** 请求路径 */
|
||||
requestUri?: string;
|
||||
/** 请求方法 */
|
||||
method?: string;
|
||||
/** IP 地址 */
|
||||
ip?: string;
|
||||
/** 地区 */
|
||||
region?: string;
|
||||
/** 浏览器 */
|
||||
browser?: string;
|
||||
/** 终端系统 */
|
||||
os?: string;
|
||||
/** 执行时间(毫秒) */
|
||||
executionTime?: number;
|
||||
/** 操作人 */
|
||||
operator?: string;
|
||||
/** 操作时间 */
|
||||
createTime?: string;
|
||||
}
|
||||
|
||||
/** 访问趋势视图对象 */
|
||||
export interface VisitTrendVO {
|
||||
/** 日期列表 */
|
||||
dates: string[];
|
||||
/** 浏览量(PV) */
|
||||
pvList: number[];
|
||||
/** 访客数(UV) */
|
||||
uvList: number[];
|
||||
/** IP数 */
|
||||
ipList: number[];
|
||||
}
|
||||
|
||||
/** 访问趋势查询参数 */
|
||||
export interface VisitTrendQuery {
|
||||
/** 开始日期 */
|
||||
startDate: string;
|
||||
/** 结束日期 */
|
||||
endDate: string;
|
||||
}
|
||||
|
||||
/** 访问统计 */
|
||||
export interface VisitStatsVO {
|
||||
/** 标题 */
|
||||
title: string;
|
||||
/** 类型 */
|
||||
type: "pv" | "uv" | "ip";
|
||||
|
||||
/** 今日访问量 */
|
||||
todayCount: number;
|
||||
/** 总访问量 */
|
||||
totalCount: number;
|
||||
/** 同比增长率(相对于昨天同一时间段的增长率) */
|
||||
growthRate: number;
|
||||
|
||||
totalCountOutput: number;
|
||||
}
|
||||
@@ -48,6 +48,12 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑用户"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/log/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "日志管理"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
@@ -72,6 +72,7 @@ const gridList = reactive([
|
||||
{
|
||||
icon: "/static/icons/log.png",
|
||||
title: "日志管理",
|
||||
url: "/pages/work/log/index",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/performance.png",
|
||||
|
||||
269
src/pages/work/log/index.vue
Normal file
269
src/pages/work/log/index.vue
Normal file
@@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<view class="log">
|
||||
<!-- 筛选 -->
|
||||
<wd-drop-menu close-on-click-modal class="mb-20rpx">
|
||||
<wd-drop-menu-item
|
||||
ref="dropMenu"
|
||||
title="筛选"
|
||||
icon="filter"
|
||||
icon-size="18px"
|
||||
@opened="handleOpened"
|
||||
>
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
label="关键字"
|
||||
type="text"
|
||||
placeholder="请输入关键字"
|
||||
/>
|
||||
<wd-calendar
|
||||
v-model="timeStampArray"
|
||||
label="日期选择"
|
||||
type="daterange"
|
||||
allow-same-day
|
||||
@confirm="handleConfirm"
|
||||
/>
|
||||
<view class="flex flex-row items-center mb-20rpx">
|
||||
<wd-button class="mt-20rpx mb-20rpx" size="medium" @click="search()">查询</wd-button>
|
||||
<wd-button size="medium" type="info" @click="reset">重置</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
|
||||
<!-- 卡片列表 -->
|
||||
<view v-for="(item, index) in pageData" :key="index">
|
||||
<wd-card :title="item.operator">
|
||||
<wd-row>
|
||||
<wd-col v-for="(rowItem, rowIndex) in listPageTypeArray" :key="rowIndex" :span="12">
|
||||
<wd-col :span="rowItem.titleSpan">
|
||||
<view>{{ rowItem.title }}:</view>
|
||||
</wd-col>
|
||||
<wd-col :span="rowItem.keySpan">
|
||||
<view>{{ item[rowItem.key] }}</view>
|
||||
</wd-col>
|
||||
</wd-col>
|
||||
</wd-row>
|
||||
<template #footer>
|
||||
<wd-button size="small" plain @click="getDetail(item)">查看详情</wd-button>
|
||||
</template>
|
||||
</wd-card>
|
||||
</view>
|
||||
|
||||
<!-- 查看详情 -->
|
||||
<wd-action-sheet v-model="detailShow">
|
||||
<view class="p-50rpx">
|
||||
<wd-row v-for="(rowItem, rowIndex) in detailTypeArray" :key="rowIndex" class="mt-20rpx">
|
||||
<wd-col :span="rowItem.titleSpan">
|
||||
<view>{{ rowItem.title }}:</view>
|
||||
</wd-col>
|
||||
<wd-col :span="rowItem.keySpan">
|
||||
<view>{{ logDetail[rowItem.key] }}</view>
|
||||
</wd-col>
|
||||
</wd-row>
|
||||
</view>
|
||||
</wd-action-sheet>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<wd-loadmore custom-class="loadmore" :state="loadMoreState" />
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import LogAPI, { LogPageVO, LogPageQuery } from "@/api/system/log";
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
|
||||
import { dayjs } from "wot-design-uni";
|
||||
|
||||
const loadMoreState = ref<LoadMoreState>("loading");
|
||||
|
||||
const queryParams = reactive<LogPageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
keywords: "",
|
||||
createTime: ["", ""],
|
||||
});
|
||||
|
||||
const timeStampArray = ref<number[]>([]);
|
||||
|
||||
/**
|
||||
* 日期格式化
|
||||
*/
|
||||
function handleConfirm({ value }: Ref<number[]>) {
|
||||
queryParams.createTime[0] = dayjs(value[0]).format("YYYY-MM-DD");
|
||||
queryParams.createTime[1] = dayjs(value[1]).format("YYYY-MM-DD");
|
||||
}
|
||||
/**
|
||||
* 搜索栏
|
||||
*/
|
||||
const dropMenu = ref<DropMenuItemExpose>();
|
||||
function search() {
|
||||
pageData.value = [];
|
||||
dropMenu.value?.close();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置搜索条件
|
||||
*/
|
||||
function reset() {
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.keywords = "";
|
||||
queryParams.createTime = ["", ""];
|
||||
timeStampArray.value = [];
|
||||
pageData.value = [];
|
||||
dropMenu.value?.close();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
// 日志卡片列表数据
|
||||
const pageData = ref<LogPageVO[]>([]);
|
||||
|
||||
onLoad(() => {
|
||||
handleQuery();
|
||||
});
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
function handleQuery() {
|
||||
loadMoreState.value = "loading";
|
||||
LogAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
pageData.value?.push(...data.list);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("系统异常", e);
|
||||
})
|
||||
.finally(() => {
|
||||
loadMoreState.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 触底事件
|
||||
*/
|
||||
onReachBottom(() => {
|
||||
queryParams.pageNum++;
|
||||
handleQuery();
|
||||
});
|
||||
|
||||
/**
|
||||
* 卡片列表展示字段
|
||||
*/
|
||||
interface listPageType {
|
||||
title: string;
|
||||
key: keyof LogPageVO;
|
||||
titleSpan: Number;
|
||||
keySpan: Number;
|
||||
}
|
||||
const listPageTypeArray = ref<listPageType[]>([
|
||||
{
|
||||
title: "模块",
|
||||
key: "module",
|
||||
titleSpan: 8,
|
||||
keySpan: 16,
|
||||
},
|
||||
{
|
||||
title: "内容",
|
||||
key: "content",
|
||||
titleSpan: 8,
|
||||
keySpan: 16,
|
||||
},
|
||||
{
|
||||
title: "时间",
|
||||
key: "createTime",
|
||||
titleSpan: 8,
|
||||
keySpan: 16,
|
||||
},
|
||||
{
|
||||
title: "地区",
|
||||
key: "region",
|
||||
titleSpan: 8,
|
||||
keySpan: 16,
|
||||
},
|
||||
]);
|
||||
|
||||
/**
|
||||
* 卡片内容详情
|
||||
*/
|
||||
const logDetail = ref<LogPageVO>({});
|
||||
const detailShow = ref<boolean>(false);
|
||||
const detailTypeArray = ref<listPageType[]>([
|
||||
{
|
||||
title: "模块",
|
||||
key: "module",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "内容",
|
||||
key: "content",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "时间",
|
||||
key: "createTime",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "地区",
|
||||
key: "region",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "IP",
|
||||
key: "ip",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "浏览器",
|
||||
key: "browser",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "终端系统",
|
||||
key: "os",
|
||||
titleSpan: 6,
|
||||
keySpan: 18,
|
||||
},
|
||||
{
|
||||
title: "执行时间(ms)",
|
||||
key: "executionTime",
|
||||
titleSpan: 8,
|
||||
keySpan: 16,
|
||||
},
|
||||
]);
|
||||
|
||||
function getDetail(item: LogPageVO) {
|
||||
detailShow.value = true;
|
||||
logDetail.value = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回
|
||||
*/
|
||||
function back() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.log {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.wd-col {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
::v-deep .wd-drop-menu__item {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 50rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user