Quellcode durchsuchen

add:api-access-log page

dev
powersir vor 11 Monaten
Ursprung
Commit
411cedaa59
2 geänderte Dateien mit 297 neuen und 5 gelöschten Zeilen
  1. +272
    -0
      src/pages/infra/log/api-access-log/index.tsx
  2. +25
    -5
      src/pages/infra/log/api-error-log/index.tsx

+ 272
- 0
src/pages/infra/log/api-access-log/index.tsx Datei anzeigen

@@ -0,0 +1,272 @@
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 {
ApiAccessLogPageReqVO,
ApiAccessLogExportReqVO,
ApiAccessLogVO
} from '@/models';


type DataIndex = keyof ApiAccessLogVO;

const mapOperation = (operation: number) => {
if (operation === 1) {
return (<Tag color="purple">通知</Tag>)
} else if (operation === 2) {
return (<Tag color="purple">新增</Tag>)
} else if (operation === 3) {
return (<Tag color="yellow">修改</Tag>)
} else if (operation === 4) {
return (<Tag color="red">删除</Tag>)
} else if (operation === 5) {
return (<Tag color="blue">导出</Tag>)
} else {
return (<Tag color="red">未知({operation})</Tag>)
}
}

export default () => {
const [dataSource, setDataSource] = useState<ApiAccessLogVO[]>([]);

const { runAsync: getPageData } = useRequest(apiLogService.getApiAccessLogPageApi, { manual: true });
const { runAsync: exportOperateLog } = useRequest(apiLogService.exportApiAccessLogApi, { manual: true });

const [searchState, setSearchState] = useSetState<ApiAccessLogPageReqVO>({
pageNo: 1,
pageSize: 10
});
const [total, setTotal] = useState(0)
const searchInput = useRef<InputRef>(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<ApiAccessLogVO> => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => (
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}>
<Input.Search
ref={searchInput}
placeholder={placeholder}
value={selectedKeys[0]}
onChange={(e) => {
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}
/>
</div>
),
filterIcon: (filtered: boolean) => (
<SearchOutlined style={{ color: filtered ? 'primaryColor' : undefined }} />
),
onFilterDropdownOpenChange: (visible) => {
if (visible) {
setTimeout(() => searchInput.current?.select(), 100);
}
},
});

const columns: TableColumnsType<ApiAccessLogVO> = [
{
title: '日志编号',
dataIndex: 'id',
key: 'id',
align: 'center',
fixed: 'left',
width: 100,
},
{
title: '链路追踪',
dataIndex: 'traceId',
key: 'traceId',
align: 'center',
width: 100,
},
{
title: '用户编号',
dataIndex: 'userId',
key: 'userId',
align: 'center',
width: 100,
...getColumnSearchProps('userId', "请输入用户编号")
},
{
title: '用户类型',
dataIndex: 'userType',
key: 'userType',
fixed: 'left',
align: 'center',
width: 100,
filters: [
{ text: '会员', value: 1 },
{ text: '管理员', value: 2 },
],
filterMultiple: false,
filterSearch: false,
render: (value: number) => {
if (value === 1) {
return <Tag color="purple">会员</Tag>
} else if (value === 2) {
return <Tag color="blue">管理员</Tag>
} else {
return <Tag color="red">未知</Tag>
}
}
},
{
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,
render: (text, record) => (
<Tooltip title={text}>
<div className='text-ellipsis overflow-hidden whitespace-nowrap max-w-xs'>
{text}
</div>
</Tooltip>
),
...getColumnSearchProps('requestUrl', "请输入请求地址")
},
{
title: '请求时间',
dataIndex: 'beginTime',
key: 'beginTime',
align: 'center',
width: 150,
render: (value: number) => {
return formatDate(new Date(value), "YYYY-mm-dd HH:MM:SS")
}
},
{
title: '执行时长',
dataIndex: 'duration',
key: 'duration',
align: 'center',
},
{
title: '操作结果',
dataIndex: 'resultCode',
key: 'resultCode',
align: 'center',
width: 150,
render: (value: number) => {
if (value === 0) {
return <Tag color="purple">成功</Tag>
} else if (value === 1) {
return <Tag color="red">失败</Tag>
} else {
return <Tag color="red">未知</Tag>
}
}
},
{
title: t("QkOmYwne" /* 操作 */),
key: 'action',
fixed: 'right',
align: 'center',
width: 100,
render: (value: ApiAccessLogVO, record) => (
<Space size="small" split={(<Divider type='vertical' />)}>
<a onClick={() => {

}}> 详情 </a>
</Space>
),
},
];

const exportLogs = async () => {
await exportOperateLog();
}

useEffect(() => {
load();
}, [searchState]);

const onChange: TableProps<ApiAccessLogVO>['onChange'] = (pagination, filters, sorter, extra) => {
const state: ApiAccessLogPageReqVO = {
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,
userType: filters.userType ? filters.userType[0] as number : undefined,
pageNo: pagination.current,
pageSize: pagination.pageSize
}
setOnSearching(true);
setSearchState(state);
};

return (
<>
<div>
<Card className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<Table rowKey="id"
scroll={{ x: true }}
columns={columns}
dataSource={dataSource}
onChange={onChange}
className='bg-transparent'
pagination={{
position: ['bottomRight'],
current: searchState.pageNo,
pageSize: searchState.pageSize,
total
}}
/>
</Card>
<FloatButton
type='primary'
tooltip={<div>导出日志</div>}
icon={<DownloadOutlined />}
onClick={exportLogs}
/>
</div>
</>
);
};

+ 25
- 5
src/pages/infra/log/api-error-log/index.tsx Datei anzeigen

@@ -145,9 +145,14 @@ export default () => {
dataIndex: 'userType',
key: 'userType',
fixed: 'left',
filterSearch: true,
align: 'center',
width: 100,
filters: [
{ text: '会员', value: 1 },
{ text: '管理员', value: 2 },
],
filterMultiple: false,
filterSearch: false,
render: (value: number) => {
if (value === 1) {
return <Tag color="purple">会员</Tag>
@@ -179,7 +184,15 @@ export default () => {
key: 'requestUrl',
align: 'center',
width: 150,
render: (text, record) => (
<Tooltip title={text}>
<div className='text-ellipsis overflow-hidden whitespace-nowrap max-w-xs'>
{text}
</div>
</Tooltip>
),
...getColumnSearchProps('requestUrl', "请输入请求地址")
},
{
title: '异常时间',
@@ -196,7 +209,13 @@ export default () => {
dataIndex: 'exceptionName',
key: 'exceptionName',
align: 'center',
width: 150,
render: (text, record) => (
<Tooltip title={text}>
<p className='text-ellipsis overflow-hidden whitespace-nowrap max-w-xs'>
{text}
</p>
</Tooltip>
)
},
{
title: '处理状态',
@@ -206,13 +225,13 @@ export default () => {
width: 150,
render: (value: number) => {
if (value === 0) {
return <Tag color="red">未处理</Tag>
return <Tag color="yellow">未处理</Tag>
} else if (value === 1) {
return <Tag color="purple">已处理</Tag>
} else if (value === 2) {
return <Tag color="blue">已忽略</Tag>
} else {
return <Tag color="purple">内置</Tag>
return <Tag color="red">未知</Tag>
}
}
},
@@ -243,7 +262,7 @@ export default () => {
];

const exportLogs = async () => {
await exportOperateLog()
await exportOperateLog();
}

useEffect(() => {
@@ -255,6 +274,7 @@ export default () => {
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,
userType: filters.userType ? filters.userType[0] as number : undefined,
pageNo: pagination.current,
pageSize: pagination.pageSize
}


Laden…
Abbrechen
Speichern