From fac4cc46737a648167a1173ba637641ade27aa6f Mon Sep 17 00:00:00 2001 From: valarchie <343928303@qq.com> Date: Sun, 16 Jul 2023 21:44:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/system/log.ts | 55 ++++ src/utils/http/index.ts | 2 +- src/views/system/log/loginLog/index.vue | 195 +++++++++++++++ src/views/system/log/loginLog/utils/hook.tsx | 234 ++++++++++++++++++ src/views/system/log/operationLog/index.vue | 2 +- .../system/log/operationLog/utils/hook.tsx | 1 + 6 files changed, 487 insertions(+), 2 deletions(-) create mode 100644 src/views/system/log/loginLog/index.vue create mode 100644 src/views/system/log/loginLog/utils/hook.tsx diff --git a/src/api/system/log.ts b/src/api/system/log.ts index 1fb4712..d6b00ce 100644 --- a/src/api/system/log.ts +++ b/src/api/system/log.ts @@ -59,3 +59,58 @@ export const deleteOperationLogApi = (data: Array) => { } }); }; + +/** 登录日志查询类 */ +export interface LoginLogQuery extends BasePageQuery { + beginTime?: string; + endTime?: string; + ipAddress?: string; + status?: string; + username?: string; +} + +/** + * 登录日志信息 + */ +export interface LoginLogsDTO { + browser?: string; + infoId?: string; + ipAddress?: string; + loginLocation?: string; + loginTime?: Date; + msg?: string; + operationSystem?: string; + /** TODO 这个登录状态的设计很奇怪 需要重构掉 */ + status?: number; + statusStr?: string; + username?: string; +} + +/** 获取操作日志列表 */ +export const getLoginLogListApi = (params?: LoginLogQuery) => { + return http.request>>( + "get", + "/logs/loginLogs", + { + params + } + ); +}; + +export const exportLoginLogExcelApi = ( + params: LoginLogQuery, + fileName: string +) => { + return http.download("/logs/loginLogs/excel", fileName, { + params + }); +}; + +export const deleteLoginLogApi = (data: Array) => { + return http.request>("delete", "/logs/loginLogs", { + params: { + // 需要将数组转换为字符串 否则Axios会将参数变成 noticeIds[0]:1 noticeIds[1]:2 这种格式,后端接收参数不成功 + ids: data.toString() + } + }); +}; diff --git a/src/utils/http/index.ts b/src/utils/http/index.ts index 141cef1..e960e02 100644 --- a/src/utils/http/index.ts +++ b/src/utils/http/index.ts @@ -87,7 +87,7 @@ class PureHttp { "/captchaImage", "/getConfig" ]; - return whiteList.some(v => config.url.indexOf(v) > -1) + return whiteList.some(v => config.url.endsWith(v)) ? config : new Promise(resolve => { const data = getToken(); diff --git a/src/views/system/log/loginLog/index.vue b/src/views/system/log/loginLog/index.vue new file mode 100644 index 0000000..860cee1 --- /dev/null +++ b/src/views/system/log/loginLog/index.vue @@ -0,0 +1,195 @@ + + + + + diff --git a/src/views/system/log/loginLog/utils/hook.tsx b/src/views/system/log/loginLog/utils/hook.tsx new file mode 100644 index 0000000..0f5a385 --- /dev/null +++ b/src/views/system/log/loginLog/utils/hook.tsx @@ -0,0 +1,234 @@ +import dayjs from "dayjs"; +import { message } from "@/utils/message"; +import { ElMessageBox, Sort } from "element-plus"; +import { + getLoginLogListApi, + deleteLoginLogApi, + exportLoginLogExcelApi, + LoginLogQuery +} from "@/api/system/log"; +import { reactive, ref, onMounted, toRaw } from "vue"; +import { useUserStoreHook } from "@/store/modules/user"; +import { CommonUtils } from "@/utils/common"; +import { PaginationProps } from "@pureadmin/table"; + +const loginLogStatusMap = + useUserStoreHook().dictionaryMap["sysLoginLog.status"]; + +export function useLoginLogHook() { + const defaultSort: Sort = { + prop: "loginTime", + order: "descending" + }; + + const pagination: PaginationProps = { + total: 0, + pageSize: 10, + currentPage: 1, + background: true + }; + + const timeRange = ref([]); + + const searchFormParams = reactive({ + ipAddress: undefined, + username: undefined, + status: undefined, + beginTime: undefined, + endTime: undefined, + timeRangeColumn: defaultSort.prop + }); + + const dataList = ref([]); + const pageLoading = ref(true); + const multipleSelection = ref([]); + + const columns: TableColumnList = [ + { + type: "selection", + align: "left" + }, + { + label: "日志编号", + prop: "logId", + minWidth: 100 + }, + { + label: "用户名", + prop: "username", + minWidth: 120, + sortable: "custom" + }, + { + label: "IP地址", + prop: "ipAddress", + minWidth: 120 + }, + { + label: "登录地点", + prop: "loginLocation", + minWidth: 120 + }, + { + label: "操作系统", + prop: "operationSystem", + minWidth: 120 + }, + { + label: "浏览器", + prop: "browser", + minWidth: 120 + }, + { + label: "状态", + prop: "status", + minWidth: 120, + cellRenderer: ({ row, props }) => ( + + {loginLogStatusMap[row.status].label} + + ) + }, + { + label: "状态名", + prop: "statusStr", + minWidth: 120, + hide: true + }, + { + label: "登录时间", + minWidth: 160, + prop: "loginTime", + sortable: "custom", + formatter: ({ loginTime }) => + dayjs(loginTime).format("YYYY-MM-DD HH:mm:ss") + }, + { + label: "操作", + fixed: "right", + width: 140, + slot: "operation" + } + ]; + + async function onSearch() { + // 点击搜索的时候 需要重置分页 + pagination.currentPage = 1; + getLoginLogList(); + } + + function resetForm(formEl, tableRef) { + if (!formEl) return; + // 清空查询参数 + formEl.resetFields(); + // 清空排序 + searchFormParams.orderColumn = undefined; + searchFormParams.orderDirection = undefined; + // 清空时间查询 TODO 这块有点繁琐 有可以优化的地方吗? + // Form组件的resetFields方法无法清除datepicker里面的数据。 + timeRange.value = []; + searchFormParams.beginTime = undefined; + searchFormParams.endTime = undefined; + tableRef.getTableRef().clearSort(); + // 重置分页并查询 + onSearch(); + } + + async function getLoginLogList(sort: Sort = defaultSort) { + pageLoading.value = true; + if (sort != null) { + CommonUtils.fillSortParams(searchFormParams, sort); + } + CommonUtils.fillPaginationParams(searchFormParams, pagination); + CommonUtils.fillTimeRangeParams(searchFormParams, timeRange.value); + + const { data } = await getLoginLogListApi(toRaw(searchFormParams)).finally( + () => { + pageLoading.value = false; + } + ); + dataList.value = data.rows; + pagination.total = data.total; + } + + async function exportAllExcel(sort: Sort = defaultSort) { + if (sort != null) { + CommonUtils.fillSortParams(searchFormParams, sort); + } + CommonUtils.fillPaginationParams(searchFormParams, pagination); + CommonUtils.fillTimeRangeParams(searchFormParams, timeRange.value); + + exportLoginLogExcelApi(toRaw(searchFormParams), "登录日志.xls"); + } + + async function handleDelete(row) { + await deleteLoginLogApi([row.logId]).then(() => { + message(`您删除了操作编号为${row.logId}的这条数据`, { + type: "success" + }); + // 刷新列表 + getLoginLogList(); + }); + } + + async function handleBulkDelete(tableRef) { + if (multipleSelection.value.length === 0) { + message("请选择需要删除的数据", { type: "warning" }); + return; + } + + ElMessageBox.confirm( + `确认要删除编号为[ ${multipleSelection.value} ]的日志吗?`, + "系统提示", + { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning", + dangerouslyUseHTMLString: true, + draggable: true + } + ) + .then(async () => { + await deleteLoginLogApi(multipleSelection.value).then(() => { + message(`您删除了日志编号为[ ${multipleSelection.value} ]的数据`, { + type: "success" + }); + // 刷新列表 + getLoginLogList(); + }); + }) + .catch(() => { + message("取消删除", { + type: "info" + }); + // 清空checkbox选择的数据 + tableRef.getTableRef().clearSelection(); + }); + } + + onMounted(() => { + getLoginLogList(); + }); + + return { + searchFormParams, + pageLoading, + columns, + dataList, + pagination, + defaultSort, + timeRange, + multipleSelection, + onSearch, + exportAllExcel, + // exportExcel, + getLoginLogList, + resetForm, + handleDelete, + handleBulkDelete + }; +} diff --git a/src/views/system/log/operationLog/index.vue b/src/views/system/log/operationLog/index.vue index a86cff9..918fa81 100644 --- a/src/views/system/log/operationLog/index.vue +++ b/src/views/system/log/operationLog/index.vue @@ -133,7 +133,7 @@ const { - +