diff --git a/mock/asyncRoutes.ts b/mock/asyncRoutes.ts index a8c86184b..48ccada4f 100644 --- a/mock/asyncRoutes.ts +++ b/mock/asyncRoutes.ts @@ -95,7 +95,7 @@ const systemMonitorRouter = { }, { path: "/monitor/system-logs", - component: "monitor/logs/system", + component: "monitor/logs/system/index", name: "SystemLog", meta: { icon: "ri:file-search-line", diff --git a/mock/system.ts b/mock/system.ts index 6d391b7d0..b81c22565 100644 --- a/mock/system.ts +++ b/mock/system.ts @@ -757,7 +757,7 @@ export default defineFakeRoute([ title: "menus.hsSystemLog", name: "SystemLog", path: "/monitor/system-logs", - component: "monitor/logs/system", + component: "monitor/logs/system/index", rank: null, redirect: "", icon: "ri:file-search-line", @@ -1138,5 +1138,63 @@ export default defineFakeRoute([ } }; } + }, + // 系统日志 + { + url: "/system-logs", + method: "post", + response: ({ body }) => { + let list = [ + { + id: 1, // 日志ID + /** + * 日志级别 + * 0 debug调试(最低级别的日志,用于调试和开发阶段) + * 1 info信息(默认级别,用于记录一般的信息) + * 2 warn警告(表示可能出现的问题或潜在的错误,但不会影响系统的正常运行) + * 3 error错误(表示发生了错误,但不会导致系统崩溃) + * 4 fatal致命(最高级别的日志,表示发生了严重错误,导致系统无法继续运行) + */ + level: 1, + module: "菜单管理", // 所属模块 + url: "/menu", // 请求接口 + method: "post", // 请求方法 + ip: faker.internet.ipv4(), + address: "中国河南省信阳市", + system: "macOS", + browser: "Chrome", + /** + * 请求耗时(单位:ms 毫秒) + * 正常耗时:一般认为在几百毫秒(0.1-0.5秒)范围内的请求耗时较为正常 + * 较慢耗时:在1秒以上的耗时可以被认为是较慢的请求,但具体是否较慢还需要根据具体业务场景和性能要求来判断 + */ + takesTime: 10, + requestTime: new Date() // 请求时间 + }, + { + id: 2, + level: 0, + module: "地图", + url: "/get-map-info", + method: "get", + ip: faker.internet.ipv4(), + address: "中国广东省深圳市", + system: "Windows", + browser: "Firefox", + takesTime: 1200, + requestTime: new Date() + } + ]; + list = list.filter(item => item.module.includes(body?.module)); + return { + success: true, + data: { + list, + total: list.length, // 总条目数 + pageSize: 10, // 每页显示条目个数 + currentPage: 1 // 当前页数 + } + }; + } } ]); diff --git a/src/api/system.ts b/src/api/system.ts index 9d8062f12..84c4f5e01 100644 --- a/src/api/system.ts +++ b/src/api/system.ts @@ -63,3 +63,8 @@ export const getLoginLogsList = (data?: object) => { export const getOperationLogsList = (data?: object) => { return http.request("post", "/operation-logs", { data }); }; + +/** 获取系统监控-系统日志列表 */ +export const getSystemLogsList = (data?: object) => { + return http.request("post", "/system-logs", { data }); +}; diff --git a/src/views/monitor/logs/operation/hook.tsx b/src/views/monitor/logs/operation/hook.tsx index 067777996..11ffcf25c 100644 --- a/src/views/monitor/logs/operation/hook.tsx +++ b/src/views/monitor/logs/operation/hook.tsx @@ -82,10 +82,10 @@ export function useRole(tableRef: Ref) { }, { label: "操作时间", - prop: "loginTime", + prop: "operatingTime", minWidth: 180, - formatter: ({ loginTime }) => - dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss") + formatter: ({ operatingTime }) => + dayjs(operatingTime).format("YYYY-MM-DD HH:mm:ss") } ]; diff --git a/src/views/monitor/logs/system.vue b/src/views/monitor/logs/system.vue deleted file mode 100644 index 7f7a93fd0..000000000 --- a/src/views/monitor/logs/system.vue +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/src/views/monitor/logs/system/hook.tsx b/src/views/monitor/logs/system/hook.tsx new file mode 100644 index 000000000..e78c434cf --- /dev/null +++ b/src/views/monitor/logs/system/hook.tsx @@ -0,0 +1,228 @@ +import dayjs from "dayjs"; +import { message } from "@/utils/message"; +import { getSystemLogsList } from "@/api/system"; +import type { PaginationProps } from "@pureadmin/table"; +import { type Ref, reactive, ref, onMounted, toRaw } from "vue"; +import { getKeyList, useCopyToClipboard } from "@pureadmin/utils"; +import Info from "@iconify-icons/ri/question-line"; + +export function useRole(tableRef: Ref) { + const form = reactive({ + module: "", + requestTime: "" + }); + const dataList = ref([]); + const loading = ref(true); + const selectedNum = ref(0); + const { copied, update } = useCopyToClipboard(); + + const pagination = reactive({ + total: 0, + pageSize: 10, + currentPage: 1, + background: true + }); + + // const getLevelType = (type, text = false) => { + // switch (type) { + // case 0: + // return text ? "debug" : "primary"; + // case 1: + // return text ? "info" : "success"; + // case 2: + // return text ? "warn" : "info"; + // case 3: + // return text ? "error" : "warning"; + // case 4: + // return text ? "fatal" : "danger"; + // } + // }; + + const columns: TableColumnList = [ + { + label: "勾选列", // 如果需要表格多选,此处label必须设置 + type: "selection", + fixed: "left", + reserveSelection: true // 数据刷新后保留选项 + }, + { + label: "ID", + prop: "id", + minWidth: 90 + }, + { + label: "所属模块", + prop: "module", + minWidth: 100 + }, + { + headerRenderer: () => ( + + 请求接口 + + + ), + prop: "url", + minWidth: 140 + }, + { + label: "请求方法", + prop: "method", + minWidth: 140 + }, + { + label: "IP 地址", + prop: "ip", + minWidth: 100 + }, + { + label: "地点", + prop: "address", + minWidth: 140 + }, + { + label: "操作系统", + prop: "system", + minWidth: 100 + }, + { + label: "浏览器类型", + prop: "browser", + minWidth: 100 + }, + // { + // label: "级别", + // prop: "level", + // minWidth: 90, + // cellRenderer: ({ row, props }) => ( + // + // {getLevelType(row.level, true)} + // + // ) + // }, + { + label: "请求耗时", + prop: "takesTime", + minWidth: 100, + cellRenderer: ({ row, props }) => ( + + {row.takesTime} ms + + ) + }, + { + label: "请求时间", + prop: "requestTime", + minWidth: 180, + formatter: ({ requestTime }) => + dayjs(requestTime).format("YYYY-MM-DD HH:mm:ss") + } + // { + // label: "操作", + // fixed: "right", + // slot: "operation" + // } + ]; + + function handleSizeChange(val: number) { + console.log(`${val} items per page`); + } + + function handleCurrentChange(val: number) { + console.log(`current page: ${val}`); + } + + /** 当CheckBox选择项发生变化时会触发该事件 */ + function handleSelectionChange(val) { + selectedNum.value = val.length; + // 重置表格高度 + tableRef.value.setAdaptive(); + } + + /** 取消选择 */ + function onSelectionCancel() { + selectedNum.value = 0; + // 用于多选表格,清空用户的选择 + tableRef.value.getTableRef().clearSelection(); + } + + /** 拷贝请求接口,表格单元格被双击时触发 */ + function handleCellDblclick({ url }) { + update(url); + copied.value + ? message(`${url} 已拷贝`, { type: "success" }) + : message("拷贝失败", { type: "warning" }); + } + + /** 批量删除 */ + function onbatchDel() { + // 返回当前选中的行 + const curSelected = tableRef.value.getTableRef().getSelectionRows(); + // 接下来根据实际业务,通过选中行的某项数据,比如下面的id,调用接口进行批量删除 + message(`已删除序号为 ${getKeyList(curSelected, "id")} 的数据`, { + type: "success" + }); + tableRef.value.getTableRef().clearSelection(); + onSearch(); + } + + /** 清空日志 */ + function clearAll() { + // 根据实际业务,调用接口删除所有日志数据 + message("已删除所有日志数据", { + type: "success" + }); + onSearch(); + } + + async function onSearch() { + loading.value = true; + const { data } = await getSystemLogsList(toRaw(form)); + dataList.value = data.list; + pagination.total = data.total; + pagination.pageSize = data.pageSize; + pagination.currentPage = data.currentPage; + + setTimeout(() => { + loading.value = false; + }, 500); + } + + const resetForm = formEl => { + if (!formEl) return; + formEl.resetFields(); + onSearch(); + }; + + onMounted(() => { + onSearch(); + }); + + return { + form, + loading, + columns, + dataList, + pagination, + selectedNum, + onSearch, + clearAll, + resetForm, + onbatchDel, + handleSizeChange, + onSelectionCancel, + handleCellDblclick, + handleCurrentChange, + handleSelectionChange + }; +} diff --git a/src/views/monitor/logs/system/index.vue b/src/views/monitor/logs/system/index.vue new file mode 100644 index 000000000..691b7864e --- /dev/null +++ b/src/views/monitor/logs/system/index.vue @@ -0,0 +1,156 @@ + + + + +