From 2f2940de1f1461cdd99c61a943a8195bf0e3e81d Mon Sep 17 00:00:00 2001 From: powersir <1576775122@qq.com> Date: Wed, 11 Oct 2023 23:51:00 +0800 Subject: [PATCH] add: api-error-log page --- src/models/api-log.data.ts | 2 +- src/pages/infra/log/api-error-log/index.tsx | 292 ++++++++++++++++++++ src/pages/system/role/index.tsx | 2 +- 3 files changed, 294 insertions(+), 2 deletions(-) diff --git a/src/models/api-log.data.ts b/src/models/api-log.data.ts index bc71d61..0ac021e 100644 --- a/src/models/api-log.data.ts +++ b/src/models/api-log.data.ts @@ -70,7 +70,7 @@ export interface ApiErrorLogPageReqVO extends PageParam { applicationName?: string requestUrl?: string exceptionTime?: Date[] - processStatus: number + processStatus?: number } export interface ApiErrorLogExportReqVO { diff --git a/src/pages/infra/log/api-error-log/index.tsx b/src/pages/infra/log/api-error-log/index.tsx index e69de29..898ab7c 100644 --- a/src/pages/infra/log/api-error-log/index.tsx +++ b/src/pages/infra/log/api-error-log/index.tsx @@ -0,0 +1,292 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { useSetState } from 'ahooks'; +import { Space, Table, Button, Input, FloatButton, Divider, Tag, Card, Tooltip } from 'antd'; +import type { TableColumnsType, InputRef } from 'antd'; +import type { ColumnType, TableProps } from 'antd/es/table'; +import { t } from '@/utils/i18n'; +import { DownloadOutlined, SearchOutlined, ExclamationCircleFilled } from '@ant-design/icons'; +import { antdUtils } from '@/utils/antd'; +import { useRequest } from '@/hooks/use-request'; +import { formatDate } from '@/utils/formatTime' +import apiLogService from '@/request/service/api-log'; +import { + ApiErrorLogPageReqVO, + ApiErrorLogExportReqVO, + ApiErrorLogVO +} from '@/models'; + + +type DataIndex = keyof ApiErrorLogVO; + +const mapOperation = (operation: number) => { + if (operation === 1) { + return (通知) + } else if (operation === 2) { + return (新增) + } else if (operation === 3) { + return (修改) + } else if (operation === 4) { + return (删除) + } else if (operation === 5) { + return (导出) + } else { + return (未知({operation})) + } +} + +export default () => { + const [dataSource, setDataSource] = useState([]); + + const { runAsync: getPageData } = useRequest(apiLogService.getApiErrorLogPageApi, { manual: true }); + const { runAsync: exportOperateLog } = useRequest(apiLogService.exportApiErrorLogApi, { manual: true }); + const { runAsync: updateApiErrorLogStatus } = useRequest(apiLogService.updateApiErrorLogPageApi, { manual: true }); + + const [searchState, setSearchState] = useSetState({ + pageNo: 1, + pageSize: 10 + }); + const [total, setTotal] = useState(0) + const searchInput = useRef(null); + const [onSearching, setOnSearching] = useState(false); + + const load = async () => { + console.log(searchState) + const [error, { code, msg, data }] = await getPageData(searchState); + setOnSearching(false); + if (error || code !== 0) { + antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' }); + return + } + setTotal(data.total); + setDataSource(data.list); + }; + + const getColumnSearchProps = (dataIndex: DataIndex, placeholder: string): ColumnType => ({ + filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => ( +
e.stopPropagation()}> + { + setSelectedKeys(e.target.value && e.target.value !== '' ? [e.target.value] : []) + }} + onSearch={(value) => { + if (value === '' && clearFilters) { + clearFilters!!() + } + confirm(); + }} + onPressEnter={() => confirm()} + allowClear + style={{ marginBottom: 8, display: 'block' }} + enterButton="搜索" + size="middle" + loading={onSearching} + /> +
+ ), + filterIcon: (filtered: boolean) => ( + + ), + onFilterDropdownOpenChange: (visible) => { + if (visible) { + setTimeout(() => searchInput.current?.select(), 100); + } + }, + }); + + const handleUpdateApiErrorLogStatus = async function (item: ApiErrorLogVO, status: number) { + antdUtils.modal?.confirm({ + title: '温馨提示', + icon: , + content: `确认标记为已${status === 1 ? '处理' : '忽略'}?`, + okText: '确定', + cancelText: '取消', + onOk() { + return new Promise(async (resolve) => { + const [error, { code, msg }] = await updateApiErrorLogStatus(item.id, status); + if (error || code !== 0) { + antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' }) + } else { + antdUtils.message?.open({ type: 'success', content: '操作成功' }) + } + await load(); + resolve('') + }).catch(() => antdUtils.message?.open({ + type: 'error', + content: '操作失败', + })); + }, + onCancel() { + }, + }); + } + + const columns: TableColumnsType = [ + { + title: '日志编号', + dataIndex: 'id', + key: 'id', + align: 'center', + fixed: 'left', + width: 100, + }, + { + title: '用户编号', + dataIndex: 'userId', + key: 'userId', + align: 'center', + width: 100, + ...getColumnSearchProps('userId', "请输入用户编号") + }, + { + title: '用户类型', + dataIndex: 'userType', + key: 'userType', + fixed: 'left', + filterSearch: true, + align: 'center', + width: 100, + render: (value: number) => { + if (value === 1) { + return 会员 + } else if (value === 2) { + return 管理员 + } else { + return 未知 + } + } + }, + { + title: '应用名', + dataIndex: 'applicationName', + key: 'applicationName', + align: 'center', + width: 120, + ...getColumnSearchProps('applicationName', "请输入应用名") + }, + { + title: '请求方法', + dataIndex: 'requestMethod', + key: 'requestMethod', + align: 'center', + width: 100, + }, + { + title: '请求地址', + dataIndex: 'requestUrl', + key: 'requestUrl', + align: 'center', + width: 150, + ...getColumnSearchProps('requestUrl', "请输入请求地址") + }, + { + title: '异常时间', + dataIndex: 'exceptionTime', + key: 'exceptionTime', + align: 'center', + width: 150, + render: (value: number) => { + return formatDate(new Date(value), "YYYY-mm-dd HH:MM:SS") + } + }, + { + title: '异常名', + dataIndex: 'exceptionName', + key: 'exceptionName', + align: 'center', + width: 150, + }, + { + title: '处理状态', + dataIndex: 'processStatus', + key: 'processStatus', + align: 'center', + width: 150, + render: (value: number) => { + if (value === 0) { + return 未处理 + } else if (value === 1) { + return 已处理 + } else if (value === 2) { + return 已忽略 + } else { + return 内置 + } + } + }, + { + title: t("QkOmYwne" /* 操作 */), + key: 'action', + fixed: 'right', + align: 'center', + width: 250, + render: (value: ApiErrorLogVO, record) => ( + )}> + { + + }}> 详情 + { + (value.processStatus === 0 ? ( { + handleUpdateApiErrorLogStatus(value, 1) + }}> 已处理 ) : null) + } + { + (value.processStatus === 0 ? ( { + handleUpdateApiErrorLogStatus(value, 2) + }}> 已忽略 ) : null) + } + + ), + }, + ]; + + const exportLogs = async () => { + await exportOperateLog() + } + + useEffect(() => { + load(); + }, [searchState]); + + const onChange: TableProps['onChange'] = (pagination, filters, sorter, extra) => { + const state: ApiErrorLogPageReqVO = { + applicationName: filters.applicationName ? filters.applicationName[0] as string : undefined, + requestUrl: filters.requestUrl ? filters.requestUrl[0] as string : undefined, + userId: filters.userId ? parseInt(filters.userId[0] as string) : undefined, + pageNo: pagination.current, + pageSize: pagination.pageSize + } + setOnSearching(true); + setSearchState(state); + }; + + return ( + <> +
+ + + + 导出日志} + icon={} + onClick={exportLogs} + /> + + + ); +}; diff --git a/src/pages/system/role/index.tsx b/src/pages/system/role/index.tsx index 877ffa4..6dff3e1 100644 --- a/src/pages/system/role/index.tsx +++ b/src/pages/system/role/index.tsx @@ -84,7 +84,7 @@ export default () => { align: 'center', width: 150, render: (value: number) => { - return (value === 1 ? 内置 : 内置) + return (value === 1 ? 内置 : 自定义) } }, {