From 45ed89c25fec70e54e3593e06e4122181732664f Mon Sep 17 00:00:00 2001 From: dap <15891557205@163.com> Date: Thu, 12 Sep 2024 09:51:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=99=BB=E5=BD=95=E6=97=A5=E5=BF=97(de?= =?UTF-8?q?mo)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/monitor/logininfo/index.ts | 60 +++++++ .../src/api/monitor/logininfo/model.d.ts | 12 ++ .../src/components/description/src/typing.ts | 2 +- .../description/src/useDescription.ts | 12 +- .../src/views/monitor/logininfor/data.tsx | 147 ++++++++++++++++++ .../src/views/monitor/logininfor/index.vue | 53 ++++++- .../monitor/logininfor/login-info-modal.vue | 33 ++++ cspell.json | 2 + 8 files changed, 314 insertions(+), 7 deletions(-) create mode 100644 apps/web-antd/src/api/monitor/logininfo/index.ts create mode 100644 apps/web-antd/src/api/monitor/logininfo/model.d.ts create mode 100644 apps/web-antd/src/views/monitor/logininfor/data.tsx create mode 100644 apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue diff --git a/apps/web-antd/src/api/monitor/logininfo/index.ts b/apps/web-antd/src/api/monitor/logininfo/index.ts new file mode 100644 index 00000000..59aa0c90 --- /dev/null +++ b/apps/web-antd/src/api/monitor/logininfo/index.ts @@ -0,0 +1,60 @@ +import type { LoginLog } from './model'; + +import type { IDS, PageQuery, PageResult } from '#/api/common'; + +import { commonExport } from '#/api/helper'; +import { requestClient } from '#/api/request'; + +enum Api { + loginInfoClean = '/monitor/logininfor/clean', + loginInfoExport = '/monitor/logininfor/export', + loginInfoList = '/monitor/logininfor/list', + root = '/monitor/logininfor', + userUnlock = '/monitor/logininfor/unlock', +} + +/** + * 登录日志列表 + * @param params 查询参数 + * @returns list[] + */ +export function loginInfoList(params?: PageQuery) { + return requestClient.get>(Api.loginInfoList, { params }); +} + +/** + * 导出登录日志 + * @param data 表单参数 + * @returns excel + */ +export function loginInfoExport(data: any) { + return commonExport(Api.loginInfoExport, data); +} + +/** + * 移除登录日志 + * @param infoIds 登录日志id数组 + * @returns void + */ +export function loginInfoRemove(infoIds: IDS) { + return requestClient.deleteWithMsg(`${Api.root}/${infoIds.join(',')}`); +} + +/** + * 账号解锁 + * @param username 用户名(账号) + * @returns void + */ +export function userUnlock(username: string) { + return requestClient.get(`${Api.userUnlock}/${username}`, { + successMessageMode: 'message', + }); +} + +/** + * 清空全部登录日志 + * @returns void + */ +export function loginInfoClean() { + return requestClient.deleteWithMsg(Api.loginInfoClean); +} diff --git a/apps/web-antd/src/api/monitor/logininfo/model.d.ts b/apps/web-antd/src/api/monitor/logininfo/model.d.ts new file mode 100644 index 00000000..93ab2207 --- /dev/null +++ b/apps/web-antd/src/api/monitor/logininfo/model.d.ts @@ -0,0 +1,12 @@ +export interface LoginLog { + infoId: string; + tenantId: string; + userName: string; + status: string; + ipaddr: string; + loginLocation: string; + browser: string; + os: string; + msg: string; + loginTime: string; +} diff --git a/apps/web-antd/src/components/description/src/typing.ts b/apps/web-antd/src/components/description/src/typing.ts index 41703704..e9de60b8 100644 --- a/apps/web-antd/src/components/description/src/typing.ts +++ b/apps/web-antd/src/components/description/src/typing.ts @@ -36,7 +36,7 @@ export interface DescriptionProps extends DescriptionsProps { } export interface DescInstance { - setDescProps(descProps: Partial): void; + setDescProps(descProps: Partial, delay?: boolean): void; } export type Register = (descInstance: DescInstance) => void; diff --git a/apps/web-antd/src/components/description/src/useDescription.ts b/apps/web-antd/src/components/description/src/useDescription.ts index 27bb4f56..3e8251b3 100644 --- a/apps/web-antd/src/components/description/src/useDescription.ts +++ b/apps/web-antd/src/components/description/src/useDescription.ts @@ -27,8 +27,16 @@ export function useDescription( } const methods: DescInstance = { - setDescProps: (descProps: Partial): void => { - unref(desc)?.setDescProps(descProps); + setDescProps: ( + descProps: Partial, + delay = false, + ): void => { + if (!delay) { + unref(desc)?.setDescProps(descProps); + return; + } + // 奇怪的问题 在modal中需要setTimeout才会生效 + setTimeout(() => unref(desc)?.setDescProps(descProps)); }, }; diff --git a/apps/web-antd/src/views/monitor/logininfor/data.tsx b/apps/web-antd/src/views/monitor/logininfor/data.tsx new file mode 100644 index 00000000..8fa91c0d --- /dev/null +++ b/apps/web-antd/src/views/monitor/logininfor/data.tsx @@ -0,0 +1,147 @@ +import type { ColumnsType } from 'ant-design-vue/es/table'; + +import type { DescItem } from '#/components/description'; + +import { DictEnum } from '@vben/constants'; + +import { Tooltip } from 'ant-design-vue'; + +import { renderBrowserIcon, renderDict, renderOsIcon } from '#/utils/render'; + +export const columns: ColumnsType = [ + { + align: 'center', + dataIndex: 'userName', + title: '用户账号', + }, + { + align: 'center', + dataIndex: 'clientKey', + title: '登录平台', + }, + { + align: 'center', + dataIndex: 'ipaddr', + title: 'IP地址', + }, + { + align: 'center', + dataIndex: 'loginLocation', + title: 'IP地点', + width: 200, + }, + { + align: 'center', + customRender({ value }) { + return renderBrowserIcon(value, true); + }, + dataIndex: 'browser', + title: '浏览器', + }, + { + align: 'center', + customRender({ value }) { + // Windows 10 or Windows Server 2016 太长了 分割一下 详情依旧能看到详细的 + // 为什么不直接保存userAgent让前端解析 很奇怪 + if (value) { + const split = value.split(' or '); + if (split.length === 2) { + value = split[0]; + } + } + return renderOsIcon(value, true); + }, + dataIndex: 'os', + title: '系统', + }, + { + align: 'center', + customRender({ value }) { + return renderDict(value, DictEnum.SYS_COMMON_STATUS); + }, + dataIndex: 'status', + title: '登录结果', + }, + { + align: 'center', + customRender({ value }) { + return ( + + {value} + + ); + }, + dataIndex: 'msg', + ellipsis: true, + title: '信息', + }, + { + align: 'center', + dataIndex: 'loginTime', + title: '日期', + }, + { + align: 'center', + dataIndex: 'action', + title: '操作', + }, +]; + +export const modalSchema: () => DescItem[] = () => [ + { + field: 'status', + label: '登录状态', + labelMinWidth: 80, + render(value) { + return renderDict(value, DictEnum.SYS_COMMON_STATUS); + }, + }, + { + field: 'clientKey', + label: '登录平台', + render(value) { + if (value) { + return value.toUpperCase(); + } + return ''; + }, + }, + { + field: 'ipaddr', + label: '账号信息', + render(_, data) { + const { ipaddr, loginLocation, userName } = data; + return `账号: ${userName} / ${ipaddr} / ${loginLocation}`; + }, + }, + { + field: 'loginTime', + label: '登录时间', + }, + { + field: 'msg', + label: '登录信息', + render(_, data: any) { + const { msg, status } = data; + return ( + + {msg} + + ); + }, + }, + { + field: 'os', + label: '登录设备', + render(value) { + return renderOsIcon(value); + }, + }, + { + field: 'browser', + label: '浏览器', + render(value) { + return renderBrowserIcon(value); + }, + }, +]; diff --git a/apps/web-antd/src/views/monitor/logininfor/index.vue b/apps/web-antd/src/views/monitor/logininfor/index.vue index 06372a15..95ef5a3e 100644 --- a/apps/web-antd/src/views/monitor/logininfor/index.vue +++ b/apps/web-antd/src/views/monitor/logininfor/index.vue @@ -1,9 +1,54 @@ diff --git a/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue b/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue new file mode 100644 index 00000000..9f9eadcd --- /dev/null +++ b/apps/web-antd/src/views/monitor/logininfor/login-info-modal.vue @@ -0,0 +1,33 @@ + + + diff --git a/cspell.json b/cspell.json index 3778dd4f..1024d56a 100644 --- a/cspell.json +++ b/cspell.json @@ -20,7 +20,9 @@ "Gitee", "iconify", "intlify", + "ipaddr", "lockb", + "logininfor", "lucide", "mkdist", "mockjs",