From 032f04e6aabd501a5f37efd9eb738ae82c624772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=80=A1?= Date: Tue, 22 Jul 2025 17:03:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=93=81=E7=B1=BB=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E3=80=81=E6=93=8D=E4=BD=9C=E6=97=A5=E5=BF=97=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=92=8C=E7=99=BB=E5=BD=95=E6=97=A5=E5=BF=97=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B9=B6=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E8=B7=AF=E7=94=B1=E9=85=8D=E7=BD=AE=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/router_system.ts | 17 + .../components/CategoryMaintenance.tsx | 41 +- src/pages/CategoryManagement/index.tsx | 6 +- src/pages/System/LoginLog/index.tsx | 361 ++++++++++++++++++ src/pages/System/LoginLog/service.ts | 85 +++++ src/pages/System/LoginLog/types.ts | 135 +++++++ src/pages/System/OperationLog/index.tsx | 311 +++++++++++++++ src/pages/System/OperationLog/service.ts | 19 + src/pages/System/OperationLog/types.ts | 110 ++++++ 9 files changed, 1050 insertions(+), 35 deletions(-) create mode 100644 src/pages/System/LoginLog/index.tsx create mode 100644 src/pages/System/LoginLog/service.ts create mode 100644 src/pages/System/LoginLog/types.ts create mode 100644 src/pages/System/OperationLog/index.tsx create mode 100644 src/pages/System/OperationLog/service.ts create mode 100644 src/pages/System/OperationLog/types.ts diff --git a/config/router_system.ts b/config/router_system.ts index 16e61e6..a46cb65 100644 --- a/config/router_system.ts +++ b/config/router_system.ts @@ -23,9 +23,26 @@ export default [{ path: '/System/Dict', component: './System/Dict', }, + {//品类管理 + path: '/System/Category', + component: './CategoryManagement', + }, + {//品类管理 + name: '品类详情', + path: '/System/CategoryManagement', + component: './CategoryManagement/components/CategoryMaintenance', + }, {//定时任务管理 path: '/System/Scheduled', component: './System/Scheduled', }, + {//操作日志管理 + path: '/System/OperationLog', + component: './System/OperationLog', + }, + {//登录日志管理 + path: '/System/LoginLog', + component: './System/LoginLog', + }, ], }] diff --git a/src/pages/CategoryManagement/components/CategoryMaintenance.tsx b/src/pages/CategoryManagement/components/CategoryMaintenance.tsx index 908958e..2550ce1 100644 --- a/src/pages/CategoryManagement/components/CategoryMaintenance.tsx +++ b/src/pages/CategoryManagement/components/CategoryMaintenance.tsx @@ -14,10 +14,12 @@ const CategoryList: React.FC = () => { const [expandedKeys, setExpandedKeys] = useState([]); const actionRef = useRef(); const location = useLocation(); - const versionId = location.state?.versionId; - + const params = new URLSearchParams(location.search); + const versionId = params.get('versionId'); +console.log(location,location.state) + console.log(versionId,'versionId') interface DictType { - value: string; + value: number; label: string; } const version_status: DictType[] = [ @@ -52,7 +54,7 @@ const CategoryList: React.FC = () => { fetchData(); }; - const renderOperation = (_, record) => { + const renderOperation = (_: any, record: any) => { if (record.level === 1) return null; // 一级节点无操作 return ( <> @@ -130,30 +132,10 @@ const CategoryList: React.FC = () => { return ( - {/* 查询区域:条件靠左,按钮靠右 */} -
-
- - - - - - -
-
- - -
-
- - {/* 树表格 */} { { title: '更新时间', dataIndex: 'updateDate', valueType: 'dateTime' }, { title: '操作', valueType: 'option', render: renderOperation } ]} - treeData={true} dataSource={treeData} rowKey="id" expandedRowKeys={expandedKeys} @@ -177,9 +158,9 @@ const CategoryList: React.FC = () => { expanded ? [...prev, record.id] : prev.filter(key => key !== record.id) ); }} - toolBarRender={() => ( + toolBarRender={() => [ - )} + ]} pagination={false} /> @@ -218,9 +199,9 @@ const CategoryList: React.FC = () => { diff --git a/src/pages/CategoryManagement/index.tsx b/src/pages/CategoryManagement/index.tsx index fff3f35..77326b1 100644 --- a/src/pages/CategoryManagement/index.tsx +++ b/src/pages/CategoryManagement/index.tsx @@ -148,10 +148,7 @@ const NoticeList: React.FC<{}> = () => { // console.log(versionId,'versionId') // 使用history.push跳转到新页面,并传递id参数 - history.push({ - pathname: '/categoryMaintenance', - state: { versionId: versionId } - }); + history.push(`/System/CategoryManagement?versionId=${versionId}`); }; // 删除操作 @@ -188,7 +185,6 @@ const NoticeList: React.FC<{}> = () => { return ( -
actionRef={actionRef}//action触发后更新表格 diff --git a/src/pages/System/LoginLog/index.tsx b/src/pages/System/LoginLog/index.tsx new file mode 100644 index 0000000..af2a164 --- /dev/null +++ b/src/pages/System/LoginLog/index.tsx @@ -0,0 +1,361 @@ +import React, { useState, useRef } from 'react'; +import { Button, Tag, Tooltip, Spin } from 'antd'; +import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table'; +import dayjs from 'dayjs'; +import tableProps from '@/utils/tableProps'; +import { getLoginLogPage } from './service'; +import type { + LoginLogItem, + SearchFormValues, + LoginLogQueryParams, + BasePageRequest, + UserTypeText, + LoginStatusText, + LoginTypeText, + FirstLoginText +} from './types'; + +/** + * 登录日志查询页面 + */ +const LoginLog: React.FC = () => { + const actionRef = useRef(); + const [spin, setSpin] = useState(false); + + // 用户类型选项 + const userTypeOptions = [ + { label: '集团用户', value: '0' }, + { label: '专家用户', value: '1' }, + { label: '供应商用户', value: '2' }, + ]; + + // 登录状态选项 + const loginStatusOptions = [ + { label: '登录成功', value: 1 }, + { label: '登录失败', value: 0 }, + ]; + + // 登录方式选项 + const loginTypeOptions = [ + { label: '密码登录', value: 'PASSWORD' }, + { label: '短信登录', value: 'SMS' }, + { label: '人脸登录', value: 'FACE' }, + ]; + + // 用户类型文本映射 + const UserTypeText: Record = { + '0': '集团用户', + '1': '专家用户', + '2': '供应商用户' + }; + + // 登录状态文本映射 + const LoginStatusText: Record = { + 0: '登录失败', + 1: '登录成功' + }; + + // 登录方式文本映射 + const LoginTypeText: Record = { + 'PASSWORD': '密码登录', + 'SMS': '短信登录', + 'FACE': '人脸登录' + }; + + // 表格列定义 + const columns: ProColumns[] = [ + { + title: '序号', + valueType: 'index', + width: 50, + }, + { + title: '用户名', + dataIndex: 'username', + width: 120, + ellipsis: true, + render: (text) => text || '-', + }, + { + title: '用户账号', + dataIndex: 'account', + width: 120, + ellipsis: true, + render: (text) => text || '-', + }, + { + title: '用户类型', + dataIndex: 'userType', + width: 100, + valueType: 'select', + valueEnum: { + '0': { text: '集团用户' }, + '1': { text: '专家用户' }, + '2': { text: '供应商用户' }, + }, + render: (_, record) => ( + + {UserTypeText[record.userType] || '未知'} + + ), + }, + { + title: '登录IP', + dataIndex: 'loginIp', + width: 140, + ellipsis: true, + render: (text) => ( + + {text || '-'} + + ), + }, + { + title: '登录状态', + dataIndex: 'loginStatus', + width: 100, + valueType: 'select', + valueEnum: { + 1: { text: '成功' }, + 0: { text: '失败' }, + }, + render: (_, record) => ( + + {LoginStatusText[record.loginStatus] || '未知'} + + ), + }, + { + title: '登录方式', + dataIndex: 'loginType', + width: 100, + valueType: 'select', + valueEnum: { + 'PASSWORD': { text: '密码登录' }, + 'SMS': { text: '短信登录' }, + 'FACE': { text: '人脸登录' }, + }, + render: (_, record) => ( + + {LoginTypeText[record.loginType] || '未知'} + + ), + }, + { + title: '浏览器', + dataIndex: 'browser', + width: 100, + search: false, + render: (text) => text || '-', + }, + { + title: '操作系统', + dataIndex: 'os', + width: 120, + search: false, + render: (text) => text || '-', + }, + { + title: '登录耗时', + dataIndex: 'loginTime', + width: 100, + search: false, + render: (_, record) => { + if (!record.loginTime) return '-'; + const time = record.loginTime; + const color = time > 3000 ? 'red' : time > 1000 ? 'orange' : 'default'; + return ( + + {time}ms + + ); + }, + sorter: true, + }, + { + title: '首次登录', + dataIndex: 'firstLogin', + width: 100, + search: false, + render: (_, record) => { + if (record.firstLogin === undefined || record.firstLogin === null) return '-'; + return ( + + {record.firstLogin === 1 ? '是' : '否'} + + ); + }, + }, + { + title: '提示消息', + dataIndex: 'msg', + width: 200, + ellipsis: true, + search: false, + render: (text) => ( + + {text || '-'} + + ), + }, + { + title: '登录时间', + dataIndex: 'createTime', + width: 180, + sorter: true, + search: false, + render: (_, record) => ( + + {record.createTime ? dayjs(record.createTime).format('YYYY-MM-DD HH:mm:ss') : '-'} + + ), + }, + // 隐藏的详细字段(通过列配置控制显示) + { + title: '日志ID', + dataIndex: 'logId', + width: 150, + ellipsis: true, + hideInTable: true, + search: false, + }, + { + title: '用户ID', + dataIndex: 'userId', + width: 120, + ellipsis: true, + hideInTable: true, + search: false, + }, + { + title: '登录地址', + dataIndex: 'loginLocation', + width: 200, + ellipsis: true, + hideInTable: true, + search: false, + render: (text) => ( + + {text || '-'} + + ), + }, + { + title: 'Token', + dataIndex: 'token', + width: 200, + ellipsis: true, + hideInTable: true, + search: false, + render: (text) => ( + + {text ? `${text.substring(0, 20)}...` : '-'} + + ), + }, + { + title: '用户代理', + dataIndex: 'userAgent', + width: 300, + ellipsis: true, + hideInTable: true, + search: false, + render: (text) => ( + + {text ? `${text.substring(0, 50)}...` : '-'} + + ), + }, + ]; + + // 构建查询参数 + const buildQueryParams = (params: any): LoginLogQueryParams => { + const basePageRequest: BasePageRequest = { + current: params.current || 1, + size: params.pageSize || 10, + }; + + const queryParams: LoginLogQueryParams = { + basePageRequest, + username: params.username, + account: params.account, + userType: params.userType, + loginIp: params.loginIp, + loginStatus: params.loginStatus, + loginType: params.loginType, + createTimeRange: params.createTime ? [params.createTime[0], params.createTime[1]] : undefined, + }; + + // 清理undefined字段 + Object.keys(queryParams).forEach(key => { + if (queryParams[key as keyof LoginLogQueryParams] === undefined) { + delete queryParams[key as keyof LoginLogQueryParams]; + } + }); + + return queryParams; + }; + + return ( + +
+ + actionRef={actionRef} + rowKey="logId" + size="small" + columns={columns} + options={false} + bordered={false} + className='tableSearch' + search={{ labelWidth: 'auto', span: 6 }} + request={async (params) => { + try { + setSpin(true); + const queryParams = buildQueryParams(params); + const response = await getLoginLogPage(queryParams); + + if (response.code === 200) { + return { + data: response.data.records || [], + success: true, + total: response.data.total || 0, + pageSize: response.data.size, + current: response.data.current + }; + } else { + return { + data: [], + success: false, + total: 0, + }; + } + } catch (error) { + console.error('查询登录日志失败:', error); + return { + data: [], + success: false, + total: 0, + }; + } finally { + setSpin(false); + } + }} + pagination={{ + ...tableProps.pagination, + showSizeChanger: true, + showQuickJumper: true, + showTotal: (total) => `共 ${total} 条记录`, + }} + dateFormatter="string" + scroll={{ x: 1800 }} + sticky={true} + onReset={() => { + // 重置操作 + }} + /> +
+
+ ); +}; + +export default LoginLog; \ No newline at end of file diff --git a/src/pages/System/LoginLog/service.ts b/src/pages/System/LoginLog/service.ts new file mode 100644 index 0000000..7d6611c --- /dev/null +++ b/src/pages/System/LoginLog/service.ts @@ -0,0 +1,85 @@ +import request from '@/utils/request'; +import type { + LoginLogQueryParams, + LoginLogItem, + PageResponse, + ApiResponse +} from './types'; + +/** + * 分页查询登录日志 + * @param params 查询参数 + * @returns 分页数据 + */ +export async function getLoginLogPage(params: LoginLogQueryParams): Promise>> { + return request('/api/sys-manager-ebtp-project/v1/loginLog/getPage', { + method: 'POST', + data: params, + }); +} + +/** + * 查询用户最近登录记录 + * @param userId 用户ID + * @param limit 限制条数 + * @returns 登录记录列表 + */ +export async function getRecentLogins(userId: string, limit: number): Promise> { + return request('/api/sys-manager-ebtp-project/v1/loginLog/getRecentLogins', { + method: 'GET', + params: { + userId, + limit + }, + }); +} + +/** + * 获取用户最后一次成功登录记录 + * @param userId 用户ID + * @returns 登录记录 + */ +export async function getLastSuccessLogin(userId: string): Promise> { + return request('/api/sys-manager-ebtp-project/v1/loginLog/getLastSuccessLogin', { + method: 'GET', + params: { + userId + }, + }); +} + +/** + * 检查IP登录失败次数是否超限 + * @param loginIp 登录IP + * @param timeRange 时间范围(分钟) + * @param maxFails 最大失败次数 + * @returns 是否超限 + */ +export async function checkIpLoginFailExceeded(loginIp: string, timeRange: number, maxFails: number): Promise> { + return request('/api/sys-manager-ebtp-project/v1/loginLog/checkIpLoginFailExceeded', { + method: 'GET', + params: { + loginIp, + timeRange, + maxFails + }, + }); +} + +/** + * 检查用户登录失败次数是否超限 + * @param userId 用户ID + * @param timeRange 时间范围(分钟) + * @param maxFails 最大失败次数 + * @returns 是否超限 + */ +export async function checkUserLoginFailExceeded(userId: string, timeRange: number, maxFails: number): Promise> { + return request('/api/sys-manager-ebtp-project/v1/loginLog/checkUserLoginFailExceeded', { + method: 'GET', + params: { + userId, + timeRange, + maxFails + }, + }); +} \ No newline at end of file diff --git a/src/pages/System/LoginLog/types.ts b/src/pages/System/LoginLog/types.ts new file mode 100644 index 0000000..d5255c5 --- /dev/null +++ b/src/pages/System/LoginLog/types.ts @@ -0,0 +1,135 @@ +/** + * 登录日志相关类型定义 + */ + +// 基础分页请求 +export interface BasePageRequest { + current: number; // 当前页码 + size: number; // 每页大小 +} + +// 登录日志查询参数 +export interface LoginLogQueryParams { + basePageRequest: BasePageRequest; + logId?: string; // 日志ID + userId?: string; // 用户ID + username?: string; // 用户名 + account?: string; // 用户账号(工号) + userType?: string; // 用户类型 + loginIp?: string; // 登录IP地址 + loginLocation?: string; // 登录地址 + browser?: string; // 浏览器类型 + os?: string; // 操作系统 + loginStatus?: number; // 登录状态 + loginType?: string; // 登录方式 + msg?: string; // 提示消息 + createTime?: string; // 访问时间 + createTimeRange?: [string, string]; // 创建时间范围 + token?: string; // token + loginTime?: number; // 登录耗时 + firstLogin?: number; // 是否首次登录 + userAgent?: string; // 用户代理信息 +} + +// 登录日志数据项 +export interface LoginLogItem { + logId: string; // 日志ID + userId?: string; // 用户ID + username?: string; // 用户名 + account?: string; // 用户账号(工号) + userType: string; // 用户类型:0-集团用户,1-专家用户,2-供应商用户 + loginIp?: string; // 登录IP地址 + loginLocation?: string; // 登录地址 + browser?: string; // 浏览器类型 + os?: string; // 操作系统 + loginStatus: number; // 登录状态:0-失败,1-成功 + loginType: string; // 登录方式 + msg?: string; // 提示消息 + createTime: string; // 访问时间 + token?: string; // token + loginTime?: number; // 登录耗时(毫秒) + firstLogin?: number; // 是否首次登录:0-否,1-是 + userAgent?: string; // 用户代理信息 +} + +// 分页响应数据 +export interface PageResponse { + records: T[]; // 数据记录 + total: number; // 总记录数 + size: number; // 每页大小 + current: number; // 当前页码 + pages: number; // 总页数 +} + +// API响应结构 +export interface ApiResponse { + code: number; // 响应码 + message: string; // 响应消息 + data: T; // 响应数据 + success: boolean; // 是否成功 +} + +// 用户类型枚举 +export enum UserType { + GROUP = '0', // 集团用户 + EXPERT = '1', // 专家用户 + SUPPLIER = '2' // 供应商用户 +} + +// 登录状态枚举 +export enum LoginStatus { + FAIL = 0, // 失败 + SUCCESS = 1 // 成功 +} + +// 登录方式枚举 +export enum LoginType { + PASSWORD = 'PASSWORD', // 密码登录 + SMS = 'SMS', // 短信登录 + FACE = 'FACE' // 人脸登录 +} + +// 首次登录枚举 +export enum FirstLogin { + NO = 0, // 否 + YES = 1 // 是 +} + +// 查询表单数据 +export interface SearchFormValues { + username?: string; // 用户名 + account?: string; // 账号 + userType?: string; // 用户类型 + loginIp?: string; // 登录IP + loginStatus?: number; // 登录状态 + loginType?: string; // 登录方式 + createTimeRange?: [string, string]; // 创建时间范围 + browser?: string; // 浏览器类型 + os?: string; // 操作系统 +} + +// 用户类型显示文本映射 +export const UserTypeText: Record = { + '0': '集团用户', + '1': '专家用户', + '2': '供应商用户' +}; + +// 登录状态显示文本映射 +export const LoginStatusText: Record = { + 0: '登录失败', + 1: '登录成功' +}; + +// 登录方式显示文本映射 +export const LoginTypeText: Record = { + 'PASSWORD': '密码登录', + 'SMS': '短信登录', + 'FACE': '人脸登录' +}; + +// 首次登录显示文本映射 +export const FirstLoginText: Record = { + 0: '否', + 1: '是' +}; \ No newline at end of file diff --git a/src/pages/System/OperationLog/index.tsx b/src/pages/System/OperationLog/index.tsx new file mode 100644 index 0000000..cb1d939 --- /dev/null +++ b/src/pages/System/OperationLog/index.tsx @@ -0,0 +1,311 @@ +import React, { useState, useRef } from 'react'; +import { Button, Tag, Tooltip, Spin } from 'antd'; +import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table'; +import dayjs from 'dayjs'; +import tableProps from '@/utils/tableProps'; +import { getOperationLogPage } from './service'; +import type { + OperationLogItem, + SearchFormValues, + OperationLogQueryParams, + BasePageRequest +} from './types'; + +/** + * 操作日志查询页面 + */ +const OperationLog: React.FC = () => { + const actionRef = useRef(); + const [spin, setSpin] = useState(false); + + // 操作类型选项 + const operationTypeOptions = [ + { label: '创建', value: 'CREATE' }, + { label: '更新', value: 'UPDATE' }, + { label: '删除', value: 'DELETE' }, + { label: '查询', value: 'SELECT' }, + { label: '其他', value: 'OTHER' }, + ]; + + // 表格列定义 + const columns: ProColumns[] = [ + { + title: '序号', + valueType: 'index', + width: 50, + }, + { + title: '编号', + dataIndex: 'id', + width: 120, + ellipsis: true, + search: false, + }, + { + title: '操作人', + dataIndex: 'userName', + width: 120, + ellipsis: true, + }, + { + title: '操作类型', + dataIndex: 'operationType', + width: 100, + valueType: 'select', + valueEnum: { + CREATE: { text: '创建' }, + UPDATE: { text: '更新' }, + DELETE: { text: '删除' }, + SELECT: { text: '查询' }, + OTHER: { text: '其他' }, + }, + render: (_, record) => { + const colorMap: Record = { + CREATE: 'green', + UPDATE: 'blue', + DELETE: 'red', + SELECT: 'default', + OTHER: 'orange', + }; + return ( + + {record.operationType} + + ); + }, + }, + { + title: '业务模块', + dataIndex: 'businessModule', + width: 120, + ellipsis: true, + search: false, + }, + { + title: '操作描述', + dataIndex: 'detail', + width: 200, + ellipsis: true, + search: false, + render: (text) => ( + + {text} + + ), + }, + { + title: '执行结果', + dataIndex: 'result', + width: 100, + search: false, + render: (_, record) => ( + + {record.result ? '成功' : '失败'} + + ), + }, + { + title: '执行时间', + dataIndex: 'runTime', + width: 100, + search: false, + render: (_, record) => { + const time = record.runTime; + const color = time > 1000 ? 'red' : time > 500 ? 'orange' : 'default'; + return ( + + {time}ms + + ); + }, + sorter: true, + }, + { + title: '创建时间', + dataIndex: 'createTime', + width: 180, + sorter: true, + search: false, + render: (_, record) => {record.createTime ? dayjs(record.createTime).format('YYYY-MM-DD HH:mm:ss') : '-'}, + }, + // 可选显示字段(通过列配置控制) + { + title: '链路ID', + dataIndex: 'transactionId', + width: 150, + ellipsis: true, + hideInTable: true, + search: false, + }, + { + title: '操作内容', + dataIndex: 'content', + width: 200, + ellipsis: true, + hideInTable: true, + search: false, + render: (text) => ( + + {text} + + ), + }, + { + title: '用户ID', + dataIndex: 'userId', + width: 120, + ellipsis: true, + hideInTable: true, + search: false, + }, + { + title: '服务名', + dataIndex: 'serviceName', + width: 150, + ellipsis: true, + hideInTable: true, + search: false, + }, + { + title: '包名', + dataIndex: 'packageName', + width: 200, + ellipsis: true, + hideInTable: true, + search: false, + render: (text) => ( + + {text} + + ), + }, + { + title: '方法名', + dataIndex: 'method', + width: 150, + ellipsis: true, + hideInTable: true, + search: false, + }, + { + title: '请求URL', + dataIndex: 'url', + width: 200, + ellipsis: true, + hideInTable: true, + search: false, + render: (text) => ( + + {text} + + ), + }, + { + title: '日志等级', + dataIndex: 'level', + width: 100, + hideInTable: true, + search: false, + render: (_, record) => { + const colorMap: Record = { + DEBUG: 'default', + INFO: 'blue', + WARN: 'orange', + ERROR: 'red', + }; + return ( + + {record.level} + + ); + }, + }, + ]; + + // 构建查询参数 + const buildQueryParams = (params: any): OperationLogQueryParams => { + const basePageRequest: BasePageRequest = { + current: params.current || 1, + size: params.pageSize || 10, + }; + + const queryParams: OperationLogQueryParams = { + basePageRequest, + userName: params.userName, + operationType: params.operationType, + createTime: params.createTime, + }; + + // 清理undefined字段 + Object.keys(queryParams).forEach(key => { + if (queryParams[key as keyof OperationLogQueryParams] === undefined) { + delete queryParams[key as keyof OperationLogQueryParams]; + } + }); + + return queryParams; + }; + + return ( + +
+ + actionRef={actionRef} + rowKey="id" + size="small" + columns={columns} + options={false} + bordered={false} + className='tableSearch' + search={{ labelWidth: 'auto', span: 6 }} + request={async (params) => { + try { + setSpin(true); + const queryParams = buildQueryParams(params); + const response = await getOperationLogPage(queryParams); + + if (response.code === 200) { + return { + data: response.data.records || [], + success: true, + total: response.data.total || 0, + pageSize: response.data.size, + current: response.data.current + }; + } else { + return { + data: [], + success: false, + total: 0, + }; + } + } catch (error) { + console.error('查询操作日志失败:', error); + return { + data: [], + success: false, + total: 0, + }; + } finally { + setSpin(false); + } + }} + pagination={{ + ...tableProps.pagination, + showSizeChanger: true, + showQuickJumper: true, + showTotal: (total) => `共 ${total} 条记录`, + }} + dateFormatter="string" + scroll={{ x: 1500 }} + sticky={true} + onReset={() => { + // 重置操作 + }} + /> +
+
+ ); +}; + +export default OperationLog; \ No newline at end of file diff --git a/src/pages/System/OperationLog/service.ts b/src/pages/System/OperationLog/service.ts new file mode 100644 index 0000000..b0d5d20 --- /dev/null +++ b/src/pages/System/OperationLog/service.ts @@ -0,0 +1,19 @@ +import request from '@/utils/request'; +import type { + OperationLogQueryParams, + OperationLogItem, + PageResponse, + ApiResponse +} from './types'; + +/** + * 分页查询操作日志 + * @param params 查询参数 + * @returns 分页数据 + */ +export async function getOperationLogPage(params: OperationLogQueryParams): Promise>> { + return request('/api/sys-manager-ebtp-project/v1/operationLog/getPage', { + method: 'POST', + data: params, + }); +} \ No newline at end of file diff --git a/src/pages/System/OperationLog/types.ts b/src/pages/System/OperationLog/types.ts new file mode 100644 index 0000000..980649d --- /dev/null +++ b/src/pages/System/OperationLog/types.ts @@ -0,0 +1,110 @@ +/** + * 操作日志相关类型定义 + */ + +// 基础分页请求 +export interface BasePageRequest { + current: number; // 当前页码 + size: number; // 每页大小 +} + +// 操作日志查询参数 +export interface OperationLogQueryParams { + basePageRequest: BasePageRequest; + id?: string; // 编号 + transactionId?: string; // 链路跟踪标识 + content?: string; // 内容 + result?: boolean; // 结果 + createTime?: string; // 创建时间 + token?: string; // 操作人token + userId?: string; // 操作人ID + userName?: string; // 操作人名称 + operationType?: string; // 操作类型 + serviceName?: string; // 服务名 + businessModule?: string; // 业务所属模块 + packageName?: string; // 包名 + method?: string; // 方法名 + url?: string; // URL + detail?: string; // 日志描述 + runTime?: number; // 方法运行时间 + level?: string; // 日志等级 +} + +// 操作日志数据项 +export interface OperationLogItem { + id: string; // 编号 + transactionId: string; // 链路跟踪标识 + content: string; // 内容 + result: boolean; // 结果 + createTime: string; // 创建时间 + token: string; // 操作人token + userId: string; // 操作人ID + userName: string; // 操作人名称 + operationType: string; // 操作类型 + serviceName: string; // 服务名 + businessModule: string; // 业务所属模块 + packageName: string; // 包名 + method: string; // 方法名 + url: string; // URL + detail: string; // 日志描述 + runTime: number; // 方法运行时间(毫秒) + level: string; // 日志等级 +} + +// 分页响应数据 +export interface PageResponse { + records: T[]; // 数据记录 + total: number; // 总记录数 + size: number; // 每页大小 + current: number; // 当前页码 + pages: number; // 总页数 +} + +// API响应结构 +export interface ApiResponse { + code: number; // 响应码 + message: string; // 响应消息 + data: T; // 响应数据 +} + +// 操作类型枚举 +export enum OperationType { + CREATE = 'CREATE', + UPDATE = 'UPDATE', + DELETE = 'DELETE', + SELECT = 'SELECT', + OTHER = 'OTHER' +} + +// 业务模块枚举 +export enum BusinessModule { + USER = 'USER', + ROLE = 'ROLE', + MENU = 'MENU', + FILE = 'FILE', + OTHER = 'OTHER' +} + +// 日志等级枚举 +export enum LogLevel { + DEBUG = 'DEBUG', + INFO = 'INFO', + WARN = 'WARN', + ERROR = 'ERROR' +} + +// 操作结果枚举 +export enum OperationResult { + SUCCESS = 'SUCCESS', + FAILURE = 'FAILURE' +} + +// 查询表单数据 +export interface SearchFormValues { + userName?: string; // 操作人名称 + operationType?: string; // 操作类型 + businessModule?: string; // 业务模块 + result?: boolean; // 操作结果 + createTimeRange?: [string, string]; // 创建时间范围 + level?: string; // 日志等级 +} \ No newline at end of file