diff --git a/package.json b/package.json index 70dd662..f1d05e9 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "md-editor-v3": "^5.6.1", "pinia": "^3.0.3", "pinia-plugin-persistedstate": "^4.5.0", - "pro-naive-ui": "^3.0.3", + "pro-naive-ui": "^3.1.1", "quill": "^2.0.3", "radash": "^12.1.1", "vue": "^3.5.20", diff --git a/src/App.vue b/src/App.vue index a6717f2..8ee6402 100644 --- a/src/App.vue +++ b/src/App.vue @@ -20,6 +20,10 @@ const propOverrides = { preset: 'card', }, ProDataTable: { + tableCardProps: { + size: 'small', + }, + size: 'small', paginateSinglePage: false, }, } diff --git a/src/api/monitor/login-log.ts b/src/api/monitor/login-log.ts new file mode 100644 index 0000000..8a8fffe --- /dev/null +++ b/src/api/monitor/login-log.ts @@ -0,0 +1,31 @@ +import { request } from '@/utils/alova' + +export type LoginLogSearchQuery = Partial & Api.PageParams + +/** + * 分页查询登录日志列表 + */ +export function getLoginLogPage(params: LoginLogSearchQuery) { + return request.Get>('/login-log', { params }) +} + +/** + * 获取登录日志详情 + */ +export function getLoginLogDetail(id: number) { + return request.Get(`/login-log/${id}`) +} + +/** + * 删除登录日志 + */ +export function deleteLoginLog(ids: string) { + return request.Delete(`/login-log/${ids}`) +} + +/** + * 清空登录日志 + */ +export function clearLoginLog() { + return request.Delete('/login-log/clean') +} diff --git a/src/api/monitor/oper-log.ts b/src/api/monitor/oper-log.ts new file mode 100644 index 0000000..7dc22d7 --- /dev/null +++ b/src/api/monitor/oper-log.ts @@ -0,0 +1,31 @@ +import { request } from '@/utils/alova' + +export interface OperLogQueryParams extends Api.PageParams { +} +/** + * 分页查询操作日志列表 + */ +export function getOperLogPage(params: OperLogQueryParams) { + return request.Get>('/oper-log', { params }) +} + +/** + * 获取操作日志详情 + */ +export function getOperLogDetail(id: number) { + return request.Get(`/oper-log/${id}`) +} + +/** + * 删除操作日志 + */ +export function deleteOperLog(ids: string) { + return request.Delete(`/oper-log/${ids}`) +} + +/** + * 清空操作日志 + */ +export function clearOperLog() { + return request.Delete('/oper-log/clean') +} diff --git a/src/modules/navie-pro.ts b/src/modules/navie-pro.ts index ac480c7..5b3c1f7 100644 --- a/src/modules/navie-pro.ts +++ b/src/modules/navie-pro.ts @@ -1,12 +1,14 @@ import { create, + ProDateRange, + ProDateTimeRange, ProInput, ProSelect, } from 'pro-naive-ui' import type { App } from 'vue' const proNaive = create({ - components: [ProInput, ProSelect], + components: [ProInput, ProSelect, ProDateRange, ProDateTimeRange], }) export function install(app: App) { diff --git a/src/router/guard.ts b/src/router/guard.ts index 769d2a4..7ef0661 100644 --- a/src/router/guard.ts +++ b/src/router/guard.ts @@ -127,7 +127,7 @@ export function setupRouterGuard(router: Router) { router.beforeResolve((to) => { // 设置菜单高亮 - routeStore.setActiveMenu(to.meta.activePath ?? to.fullPath) + routeStore.setActiveMenu(to.meta.activePath || to.fullPath) // 添加tabs tabStore.addTab(to) // 设置高亮标签 diff --git a/src/typings/entities/login-log.d.ts b/src/typings/entities/login-log.d.ts new file mode 100644 index 0000000..7cd2483 --- /dev/null +++ b/src/typings/entities/login-log.d.ts @@ -0,0 +1,43 @@ +declare namespace Entity { + /** + * 登录日志 + */ + interface LoginLog { + /** + * 日志编号 + */ + id: number + /** + * 用户账号 + */ + username: string + /** + * 登录IP地址 + */ + ipaddr: string + /** + * 登录地点 + */ + loginLocation: string + /** + * 浏览器类型 + */ + browser: string + /** + * 操作系统 + */ + os: string + /** + * 登录状态(0成功 1失败) + */ + status: number + /** + * 提示消息 + */ + msg: string + /** + * 访问时间 + */ + loginTime: string + } +} diff --git a/src/typings/entities/oper-log.d.ts b/src/typings/entities/oper-log.d.ts new file mode 100644 index 0000000..248687a --- /dev/null +++ b/src/typings/entities/oper-log.d.ts @@ -0,0 +1,75 @@ +declare namespace Entity { + /** + * 操作日志 + */ + interface OperLog { + /** + * 日志编号 + */ + id: number + /** + * 模块标题 + */ + title: string + /** + * 方法名称 + */ + method: string + /** + * 请求方式 + */ + requestMethod: string + /** + * 操作人员 + */ + operName: string + /** + * 部门名称 + */ + deptName: string + /** + * 请求URL + */ + operUrl: string + /** + * 主机地址 + */ + operIp: string + /** + * 操作地点 + */ + operLocation: string + /** + * 浏览器类型 + */ + browser: string + /** + * 操作系统 + */ + os: string + /** + * 请求参数 + */ + operParam: string + /** + * 返回参数 + */ + jsonResult: string + /** + * 操作状态(0正常 1异常) + */ + status: number + /** + * 错误消息 + */ + errorMsg: string + /** + * 消耗时间 + */ + costTime: string + /** + * 操作时间 + */ + operTime: Date + } +} diff --git a/src/typings/global.d.ts b/src/typings/global.d.ts index 6158a6e..41a37ef 100644 --- a/src/typings/global.d.ts +++ b/src/typings/global.d.ts @@ -9,6 +9,11 @@ declare namespace Entity { /* 各类接口返回的数据类型, 具体内容在 ./api */ declare namespace Api { + interface PageParams { + pageNum: number + pageSize: number + } + interface Response { /** 业务状态码 */ code: number diff --git a/src/views/monitor/login-log/columns.tsx b/src/views/monitor/login-log/columns.tsx new file mode 100644 index 0000000..afea731 --- /dev/null +++ b/src/views/monitor/login-log/columns.tsx @@ -0,0 +1,155 @@ +import type { DataTableColumns } from 'naive-ui' +import { NButton, NSpace, NTag } from 'naive-ui' +import type { ProSearchFormColumns } from 'pro-naive-ui' +import { renderProCopyableText } from 'pro-naive-ui' + +// 登录日志搜索表单数据类型 +export interface LoginLogSearchFormData { + ipaddr?: string + userName?: string + status?: number + loginTime?: string +} + +// 登录日志搜索表单列配置 +export const searchColumns: ProSearchFormColumns = [ + { + title: '登录地址', + path: 'ipaddr', + field: 'input', + fieldProps: { + clearable: true, + }, + }, + { + title: '用户名称', + path: 'username', + field: 'input', + fieldProps: { + clearable: true, + }, + }, + { + title: '状态', + path: 'status', + field: 'select', + fieldProps: { + clearable: true, + options: [ + { label: '成功', value: '0' }, + { label: '失败', value: '1' }, + ], + }, + }, + { + title: '登录时间', + path: 'loginTime', + field: 'date-time-range', + fieldProps: { + clearable: true, + format: 'yyyy-MM-dd HH:mm:ss', + valueFormat: 'yyyy-MM-dd HH:mm:ss', + defaultTime: ['00:00:00', '23:59:59'], + }, + }, +] + +// 表格列配置 +export function createTableColumns(options: { + onDelete: (infoId: number) => void +}): DataTableColumns { + const { onDelete } = options + + return [ + { + type: 'selection', + }, + { + title: '用户名称', + key: 'username', + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '登录地址', + key: 'ipaddr', + width: 130, + align: 'center', + render: row => renderProCopyableText(row.ipaddr), + }, + { + title: '登录地点', + key: 'loginLocation', + width: 150, + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '浏览器', + key: 'browser', + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '操作系统', + key: 'os', + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '登录状态', + key: 'status', + width: 80, + align: 'center', + render: (row) => { + return ( + + {row.status === 0 ? '成功' : '失败'} + + ) + }, + }, + { + title: '操作信息', + key: 'msg', + width: 200, + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '登录日期', + key: 'loginTime', + align: 'center', + }, + { + title: '操作', + key: 'actions', + width: 150, + align: 'center', + fixed: 'right', + render: (row) => { + return ( + + onDelete(row.id)} + > + 删除 + + + ) + }, + }, + ] +} diff --git a/src/views/monitor/login-log/index.vue b/src/views/monitor/login-log/index.vue new file mode 100644 index 0000000..c23e1c5 --- /dev/null +++ b/src/views/monitor/login-log/index.vue @@ -0,0 +1,149 @@ + + + diff --git a/src/views/monitor/oper-log/columns.tsx b/src/views/monitor/oper-log/columns.tsx new file mode 100644 index 0000000..5b9dddd --- /dev/null +++ b/src/views/monitor/oper-log/columns.tsx @@ -0,0 +1,168 @@ +import type { DataTableColumns } from 'naive-ui' +import { NButton, NSpace, NTag } from 'naive-ui' +import type { ProSearchFormColumns } from 'pro-naive-ui' +import { renderProCopyableText } from 'pro-naive-ui' + +// 操作日志搜索表单数据类型 +export interface OperationLogSearchFormData { + operUrl?: string + title?: string + operName?: string + businessType?: number + status?: 0 | 1 + operTime?: [string, string] +} + +// 操作日志搜索表单列配置 +export const searchColumns: ProSearchFormColumns = [ + { + title: '操作地址', + path: 'operUrl', + field: 'input', + fieldProps: { + clearable: true, + }, + }, + { + title: '系统模块', + path: 'title', + field: 'input', + fieldProps: { + clearable: true, + }, + }, + { + title: '操作人员', + path: 'operName', + field: 'input', + fieldProps: { + clearable: true, + }, + }, + { + title: '状态', + path: 'status', + field: 'select', + fieldProps: { + clearable: true, + options: [ + { label: '正常', value: 0 }, + { label: '异常', value: 1 }, + ], + }, + }, + { + title: '操作时间', + path: 'operTime', + field: 'date-time-range', + fieldProps: { + clearable: true, + format: 'yyyy-MM-dd', + valueFormat: 'yyyy-MM-dd HH:mm:ss', + defaultTime: ['00:00:00', '23:59:59'], + }, + }, +] + +// 表格列配置 +export function createTableColumns(options: { + onView: (row: Entity.OperLog) => void + onDelete: (operId: number) => void +}): DataTableColumns { + const { onView, onDelete } = options + + return [ + { + type: 'selection', + width: 55, + align: 'center', + }, + { + title: '系统模块', + key: 'title', + width: 150, + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '操作人员', + key: 'operName', + width: 120, + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '主机地址', + key: 'operIp', + width: 130, + align: 'center', + render: row => renderProCopyableText(row.operIp), + }, + { + title: '操作地点', + key: 'operLocation', + width: 150, + align: 'center', + ellipsis: { + tooltip: true, + }, + }, + { + title: '操作状态', + key: 'status', + width: 100, + align: 'center', + render: (row) => { + return ( + + {row.status === 0 ? '正常' : '异常'} + + ) + }, + }, + { + title: '操作日期', + key: 'operTime', + width: 180, + align: 'center', + }, + { + title: '消耗时间', + key: 'costTime', + width: 100, + align: 'center', + render: row => `${row.costTime}`, + }, + { + title: '操作', + key: 'actions', + width: 150, + align: 'center', + fixed: 'right', + render: (row) => { + return ( + + onView(row)} + > + 详细 + + onDelete(row.id)} + > + 删除 + + + ) + }, + }, + ] +} diff --git a/src/views/monitor/oper-log/components/DetailModal.vue b/src/views/monitor/oper-log/components/DetailModal.vue new file mode 100644 index 0000000..ca543f8 --- /dev/null +++ b/src/views/monitor/oper-log/components/DetailModal.vue @@ -0,0 +1,119 @@ + + + diff --git a/src/views/monitor/oper-log/index.vue b/src/views/monitor/oper-log/index.vue new file mode 100644 index 0000000..68e5bb7 --- /dev/null +++ b/src/views/monitor/oper-log/index.vue @@ -0,0 +1,170 @@ + + +