diff --git a/apps/web-antd/src/api/monitor/online/index.ts b/apps/web-antd/src/api/monitor/online/index.ts new file mode 100644 index 00000000..88289775 --- /dev/null +++ b/apps/web-antd/src/api/monitor/online/index.ts @@ -0,0 +1,40 @@ +import type { OnlineUser } from './model'; + +import type { PageQuery } from '#/api/common'; + +import { requestClient } from '#/api/request'; + +enum Api { + onlineList = '/monitor/online/list', + root = '/monitor/online', +} + +/** + * 当前账号的在线设备 个人中心使用 + * @returns OnlineUser[] + */ +export function onlineDeviceList() { + return requestClient.get(Api.root); +} + +export function onlineList(params?: PageQuery) { + return requestClient.get(Api.onlineList, { params }); +} + +/** + * 强制下线 + * @param tokenId 用户token + * @returns void + */ +export function forceLogout(tokenId: string) { + return requestClient.delete(`${Api.root}/${tokenId}`); +} + +/** + * 个人中心用的 跟上面的不同是用的Post + * @param tokenId 用户token + * @returns void + */ +export function forceLogout2(tokenId: string) { + return requestClient.post(`${Api.root}/${tokenId}`); +} diff --git a/apps/web-antd/src/api/monitor/online/model.d.ts b/apps/web-antd/src/api/monitor/online/model.d.ts new file mode 100644 index 00000000..b93395fe --- /dev/null +++ b/apps/web-antd/src/api/monitor/online/model.d.ts @@ -0,0 +1,10 @@ +export interface OnlineUser { + tokenId: string; + deptName: string; + userName: string; + ipaddr: string; + loginLocation: string; + browser: string; + os: string; + loginTime: number; +} diff --git a/apps/web-antd/src/api/monitor/operlog/index.ts b/apps/web-antd/src/api/monitor/operlog/index.ts new file mode 100644 index 00000000..c061b447 --- /dev/null +++ b/apps/web-antd/src/api/monitor/operlog/index.ts @@ -0,0 +1,31 @@ +import type { OperationLog } from './model'; + +import type { IDS, PageQuery, PageResult } from '#/api/common'; + +import { commonExport } from '#/api/helper'; +import { requestClient } from '#/api/request'; + +enum Api { + operLogClean = '/monitor/operlog/clean', + operLogExport = '/monitor/operlog/export', + operLogList = '/monitor/operlog/list', + root = '/monitor/operlog', +} + +export function operLogList(params?: PageQuery) { + return requestClient.get>(Api.operLogList, { + params, + }); +} + +export function operLogDelete(operIds: IDS) { + return requestClient.deleteWithMsg(`${Api.root}/${operIds}`); +} + +export function operLogClean() { + return requestClient.deleteWithMsg(Api.operLogClean); +} + +export function operLogExport(data: any) { + return commonExport(Api.operLogExport, data); +} diff --git a/apps/web-antd/src/api/monitor/operlog/model.d.ts b/apps/web-antd/src/api/monitor/operlog/model.d.ts new file mode 100644 index 00000000..42bc5822 --- /dev/null +++ b/apps/web-antd/src/api/monitor/operlog/model.d.ts @@ -0,0 +1,21 @@ +export interface OperationLog { + operId: string; + tenantId: string; + title: string; + businessType: number; + businessTypes?: any; + method: string; + requestMethod: string; + operatorType: number; + operName: string; + deptName: string; + operUrl: string; + operIp: string; + operLocation: string; + operParam: string; + jsonResult: string; + status: number; + errorMsg: string; + operTime: string; + costTime: number; +} diff --git a/apps/web-antd/src/views/monitor/operlog/OperationPreviewDrawer.vue b/apps/web-antd/src/views/monitor/operlog/OperationPreviewDrawer.vue new file mode 100644 index 00000000..3e178a4b --- /dev/null +++ b/apps/web-antd/src/views/monitor/operlog/OperationPreviewDrawer.vue @@ -0,0 +1,32 @@ + + + diff --git a/apps/web-antd/src/views/monitor/operlog/data.ts b/apps/web-antd/src/views/monitor/operlog/data.ts deleted file mode 100644 index 2deb49e5..00000000 --- a/apps/web-antd/src/views/monitor/operlog/data.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { FormSchemaGetter } from '#/adapter'; - -import { DictEnum } from '@vben/constants'; - -import { getDictOptions } from '#/utils/dict'; - -export const querySchema: FormSchemaGetter = () => [ - { - component: 'Input', - componentProps: { - placeholder: '请输入', - }, - fieldName: 'title', - label: '系统模块', - }, - { - component: 'Input', - componentProps: { - placeholder: '请输入', - }, - fieldName: 'operName', - label: '操作人员', - }, - { - component: 'Select', - componentProps: { - options: getDictOptions(DictEnum.SYS_OPER_TYPE), - placeholder: '请选择', - }, - fieldName: 'businessType', - label: '操作类型', - }, - { - component: 'Input', - componentProps: { - placeholder: '请输入', - }, - fieldName: 'operIp', - label: '操作IP', - }, - { - component: 'Select', - componentProps: { - options: getDictOptions(DictEnum.SYS_COMMON_STATUS), - placeholder: '请选择', - }, - fieldName: 'status', - label: '状态', - }, - { - component: 'RangePicker', - fieldName: 'createTime', - label: '操作时间', - }, -]; diff --git a/apps/web-antd/src/views/monitor/operlog/data.tsx b/apps/web-antd/src/views/monitor/operlog/data.tsx new file mode 100644 index 00000000..5a749da1 --- /dev/null +++ b/apps/web-antd/src/views/monitor/operlog/data.tsx @@ -0,0 +1,223 @@ +import type { ColumnType } from 'ant-design-vue/es/table'; + +import type { FormSchemaGetter } from '#/adapter'; +import type { DescItem } from '#/components/description'; + +import { DictEnum } from '@vben/constants'; + +import { Tag } from 'ant-design-vue'; + +import { getDictOptions } from '#/utils/dict'; +import { + renderDict, + renderHttpMethodTag, + renderJsonPreview, +} from '#/utils/render'; + +export const querySchema: FormSchemaGetter = () => [ + { + component: 'Input', + componentProps: { + placeholder: '请输入', + }, + fieldName: 'title', + label: '系统模块', + }, + { + component: 'Input', + componentProps: { + placeholder: '请输入', + }, + fieldName: 'operName', + label: '操作人员', + }, + { + component: 'Select', + componentProps: { + options: getDictOptions(DictEnum.SYS_OPER_TYPE), + placeholder: '请选择', + }, + fieldName: 'businessType', + label: '操作类型', + }, + { + component: 'Input', + componentProps: { + placeholder: '请输入', + }, + fieldName: 'operIp', + label: '操作IP', + }, + { + component: 'Select', + componentProps: { + options: getDictOptions(DictEnum.SYS_COMMON_STATUS), + placeholder: '请选择', + }, + fieldName: 'status', + label: '状态', + }, + { + component: 'RangePicker', + fieldName: 'createTime', + label: '操作时间', + }, +]; + +export const columns: ColumnType[] = [ + { + align: 'center', + dataIndex: 'title', + title: '系统模块', + }, + { + align: 'center', + customRender({ value }) { + return renderDict(value, DictEnum.SYS_OPER_TYPE); + }, + dataIndex: 'businessType', + title: '操作类型', + }, + { + align: 'center', + dataIndex: 'operName', + title: '操作人员', + }, + { + align: 'center', + dataIndex: 'operIp', + title: 'IP地址', + }, + { + align: 'center', + dataIndex: 'operLocation', + title: 'IP信息', + }, + { + align: 'center', + customRender({ value }) { + return renderDict(value, DictEnum.SYS_COMMON_STATUS); + }, + dataIndex: 'status', + title: '操作状态', + }, + { + align: 'center', + dataIndex: 'operTime', + sorter: true, + title: '操作日期', + }, + { + align: 'center', + customRender({ text }) { + return `${text} ms`; + }, + dataIndex: 'costTime', + sorter: true, + title: '操作耗时', + }, + { + align: 'center', + dataIndex: 'action', + fixed: 'right', + title: '操作', + }, +]; + +export const descSchema: DescItem[] = [ + { + field: 'operId', + label: '日志编号', + }, + { + field: 'status', + label: '操作结果', + render(value) { + return renderDict(value, DictEnum.SYS_COMMON_STATUS); + }, + }, + { + field: 'title', + label: '操作模块', + labelMinWidth: 80, + render(value, { businessType }) { + const operType = renderDict(businessType, DictEnum.SYS_OPER_TYPE); + return ( +
+ {value} + {operType} +
+ ); + }, + }, + { + field: 'operIp', + label: '操作信息', + render(_, data) { + return `账号: ${data.operName} / ${data.deptName} / ${data.operIp} / ${data.operLocation}`; + }, + }, + { + field: 'operUrl', + label: '请求信息', + render(_, data) { + const { operUrl, requestMethod } = data; + const methodTag = renderHttpMethodTag(requestMethod); + return ( + + {methodTag} {operUrl} + + ); + }, + }, + { + field: 'errorMsg', + label: '异常信息', + render(value) { + return {value}; + }, + show: (data) => { + return data && data.errorMsg !== ''; + }, + }, + { + field: 'method', + label: '方法', + }, + { + field: 'operParam', + label: '请求参数', + render(value) { + return ( +
+ {renderJsonPreview(value)} +
+ ); + }, + }, + { + field: 'jsonResult', + label: '响应参数', + render(value) { + return ( +
+ {renderJsonPreview(value)} +
+ ); + }, + show(data) { + return data && data.jsonResult; + }, + }, + { + field: 'costTime', + label: '耗时', + render(value) { + return `${value} ms`; + }, + }, + { + field: 'operTime', + label: '操作时间', + }, +]; diff --git a/apps/web-antd/src/views/monitor/operlog/index.vue b/apps/web-antd/src/views/monitor/operlog/index.vue index 7e009d1f..05ef5f9e 100644 --- a/apps/web-antd/src/views/monitor/operlog/index.vue +++ b/apps/web-antd/src/views/monitor/operlog/index.vue @@ -1,11 +1,20 @@ diff --git a/cspell.json b/cspell.json index d3ffbc57..428db62f 100644 --- a/cspell.json +++ b/cspell.json @@ -19,6 +19,7 @@ "execa", "Gitee", "iconify", + "iconoir", "intlify", "ipaddr", "lockb", @@ -26,12 +27,14 @@ "lucide", "mkdist", "mockjs", + "naiveui", "nocheck", "noopener", "noreferrer", "nprogress", "nuxt", "oper", + "operlog", "pinia", "prefixs", "publint", @@ -43,6 +46,7 @@ "styl", "taze", "ui-kit", + "uicons", "unplugin", "unref", "vben", @@ -51,13 +55,7 @@ "vitepress", "vnode", "vueuse", - "yxxx", - "echarts", - "sortablejs", - "etag", - "naiveui", - "uicons", - "iconoir" + "yxxx" ], "ignorePaths": [ "**/node_modules/**",