diff --git a/src/api/system/monitor.ts b/src/api/system/monitor.ts new file mode 100644 index 0000000..af2e892 --- /dev/null +++ b/src/api/system/monitor.ts @@ -0,0 +1,35 @@ +import { http } from "@/utils/http"; + +export interface OnlineUserQuery { + ipAddress: string; + username: string; +} + +export interface OnlineUserInfo { + browser?: string; + deptName?: string; + ipAddress?: string; + loginLocation?: string; + loginTime?: number; + operationSystem?: string; + tokenId?: string; + username?: string; +} + +/** 获取操作日志列表 */ +export const getOnlineUserListApi = (params?: OnlineUserQuery) => { + return http.request>>( + "get", + "/monitor/onlineUsers", + { + params + } + ); +}; + +export const logoutOnlineUserApi = (tokenId: string) => { + return http.request>( + "delete", + `/monitor/onlineUser/${tokenId}` + ); +}; diff --git a/src/utils/common.ts b/src/utils/common.ts index 29630db..2dceac6 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -114,6 +114,18 @@ export class CommonUtils { writeFile(workBook, `${excelName}.xlsx`); } + static paginateList(dataList: any[], pagination: PaginationProps): any[] { + // 计算起始索引 + const startIndex = (pagination.currentPage - 1) * pagination.pageSize; + + // 截取数组 + const endIndex = startIndex + pagination.pageSize; + const paginatedList = dataList.slice(startIndex, endIndex); + + // 返回截取后的数组 + return paginatedList; + } + // 私有构造函数,防止类被实例化 private constructor() {} } diff --git a/src/views/monitor/onlineUser/index.vue b/src/views/monitor/onlineUser/index.vue new file mode 100644 index 0000000..6501dd6 --- /dev/null +++ b/src/views/monitor/onlineUser/index.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/src/views/monitor/onlineUser/utils/hook.tsx b/src/views/monitor/onlineUser/utils/hook.tsx new file mode 100644 index 0000000..103517e --- /dev/null +++ b/src/views/monitor/onlineUser/utils/hook.tsx @@ -0,0 +1,141 @@ +import dayjs from "dayjs"; +import { message } from "@/utils/message"; +import { + OnlineUserQuery, + getOnlineUserListApi, + logoutOnlineUserApi +} from "@/api/system/monitor"; +import { reactive, ref, onMounted, toRaw } from "vue"; +import { PaginationProps } from "@pureadmin/table"; +import { CommonUtils } from "@/utils/common"; + +export function useHook() { + const pagination: PaginationProps = { + total: 0, + pageSize: 10, + currentPage: 1, + background: true + }; + + const timeRange = ref([]); + + const searchFormParams = reactive({ + ipAddress: undefined, + username: undefined + }); + + // 该分页使用前端分页 所以需要一个原始数组来保存原有数据 + let originalDataList = []; + const dataList = ref([]); + const pageLoading = ref(true); + + const columns: TableColumnList = [ + { + label: "会话编号", + prop: "tokenId", + minWidth: 100 + }, + { + label: "用户名", + prop: "username", + minWidth: 120 + }, + { + label: "所属部门", + prop: "deptName", + minWidth: 120 + }, + { + label: "IP地址", + prop: "ipAddress", + minWidth: 120 + }, + { + label: "登录地点", + prop: "loginLocation", + minWidth: 120 + }, + { + label: "操作系统", + prop: "operationSystem", + minWidth: 120 + }, + { + label: "浏览器", + prop: "browser", + minWidth: 120 + }, + { + label: "登录时间", + minWidth: 160, + prop: "loginTime", + formatter: ({ loginTime }) => + dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss") + }, + { + label: "操作", + fixed: "right", + width: 140, + slot: "operation" + } + ]; + + async function onSearch() { + // 点击搜索的时候 需要重置分页 + pagination.currentPage = 1; + + pageLoading.value = true; + + const { data } = await getOnlineUserListApi( + toRaw(searchFormParams) + ).finally(() => { + pageLoading.value = false; + }); + + originalDataList = data.rows; + pagination.total = data.rows.length; + + getList(); + } + + function resetForm(formEl, tableRef) { + if (!formEl) return; + // 清空查询参数 + formEl.resetFields(); + tableRef.getTableRef().clearSort(); + pagination.currentPage = 1; + // 重置分页并查询 + onSearch(); + } + + async function getList() { + dataList.value = CommonUtils.paginateList(originalDataList, pagination); + } + + async function handleLogout(row) { + await logoutOnlineUserApi(row.tokenId).then(() => { + message(`您强制登出了用户:${row.username}`, { + type: "success" + }); + // 刷新列表 + onSearch(); + }); + } + + onMounted(() => { + onSearch(); + }); + + return { + searchFormParams, + pageLoading, + columns, + dataList, + pagination, + timeRange, + onSearch, + getList, + resetForm, + handleLogout + }; +}