From 7606bb7d8d239482eed16e7ca504bc3b15207055 Mon Sep 17 00:00:00 2001 From: ZhuRui Date: Thu, 30 Jul 2026 17:23:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A4=84=E7=90=86=20ignore=20=E5=B9=B2?= =?UTF-8?q?=E6=89=B0=E9=97=AE=E9=A2=98=20=E4=BC=98=E5=8C=96=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +- src/api/logs/index.ts | 66 +++++++ src/api/logs/types.ts | 60 ++++++ src/config/mock/eventOperationLogs.ts | 35 +++- src/config/mock/operationLogs.ts | 33 +++- src/pages/events/logs/index.module.less | 36 ++++ src/pages/events/logs/index.tsx | 210 +++++++++++++++++++++ src/pages/events/logs/model/useLogModel.ts | 154 +++++++++++++++ src/pages/system/logs/index.tsx | 118 ++++++++++++ src/pages/system/logs/model/useLogModel.ts | 146 ++++++++++++++ 10 files changed, 845 insertions(+), 19 deletions(-) create mode 100644 src/api/logs/index.ts create mode 100644 src/api/logs/types.ts create mode 100644 src/pages/events/logs/index.module.less create mode 100644 src/pages/events/logs/index.tsx create mode 100644 src/pages/events/logs/model/useLogModel.ts create mode 100644 src/pages/system/logs/index.tsx create mode 100644 src/pages/system/logs/model/useLogModel.ts diff --git a/.gitignore b/.gitignore index 715094c..2b3c593 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Logs -logs +/logs *.log npm-debug.log* yarn-debug.log* @@ -40,3 +40,7 @@ coverage .cache .temp .tmp + +# Easy LESS 误生成的编译产物(本项目为 Vue PC 端,样式源文件为 .less,由 Vite 编译) +*.wxss +*.module.css diff --git a/src/api/logs/index.ts b/src/api/logs/index.ts new file mode 100644 index 0000000..2f85c25 --- /dev/null +++ b/src/api/logs/index.ts @@ -0,0 +1,66 @@ +/** + * 操作日志 API + */ +import { get } from '@/utils/request'; +import { USE_MOCK, MOCK_DELAY } from '@/config/mock'; +import { buildMockOperationLogPage } from '@/config/mock/operationLogs'; +import { buildMockEventOperationLogPage } from '@/config/mock/eventOperationLogs'; +import type { + OperationLogQueryParams, + SysOperationLogVO, + TournamentAdminOperationPageVO, + PageData, + ApiResult, +} from './types'; + +export type { + SysOperationLogVO, + TournamentAdminOperationPageVO, + OperationLogQueryParams, + PageData, + ApiResult, +} from './types'; + +const delay = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +function pickFilters(params: OperationLogQueryParams): OperationLogQueryParams { + const { page: _page, limit: _limit, ...filters } = params; + return filters; +} + +/** GET /admin/sys/operation/page — 系统操作日志分页 */ +export async function getOperationLogList( + params: OperationLogQueryParams, +): Promise>> { + if (USE_MOCK) { + await delay(MOCK_DELAY); + const page = Number(params.page) || 1; + const limit = Number(params.limit) || 10; + return { + code: 200, + msg: 'success', + data: buildMockOperationLogPage(page, limit, pickFilters(params)), + }; + } + return get('/admin/sys/operation/page', params as Record); +} + +/** GET /admin/tournament/operation/page — 赛事操作日志分页 */ +export async function getOperationLogs( + params: OperationLogQueryParams, +): Promise>> { + if (USE_MOCK) { + await delay(MOCK_DELAY); + const page = Number(params.page) || 1; + const limit = Number(params.limit) || 10; + return { + code: 200, + msg: 'success', + data: buildMockEventOperationLogPage(page, limit, pickFilters(params)), + }; + } + return get('/admin/tournament/operation/page', params as Record); +} + +/** @deprecated 使用 getOperationLogList */ +export const getOperationLogPage = getOperationLogList; diff --git a/src/api/logs/types.ts b/src/api/logs/types.ts new file mode 100644 index 0000000..21cefd2 --- /dev/null +++ b/src/api/logs/types.ts @@ -0,0 +1,60 @@ +/** + * 操作日志 — 类型定义 + */ + +/** 系统操作日志列表项(GET /admin/sys/operation/page) */ +export interface SysOperationLogVO { + /** 操作类型:1=下架赛事、2=上架赛事、3=禁用用户、4=启用用户 */ + type: number; + /** 操作人昵称 */ + nickname: string; + /** 操作时间 */ + createDate: string; + /** 操作内容 */ + content: string; +} + +/** 赛事操作日志列表项 */ +export interface TournamentAdminOperationPageVO { + opName: string; + source: string; + nickname: string; + phone: string; + tournamentName: string; + obj: string; + content: string; + createDate: string; +} + +/** 操作日志列表查询参数 */ +export interface OperationLogQueryParams { + page?: string; + limit?: string; + /** 操作类型 */ + type?: string; + /** 系统日志:操作人昵称 */ + nickname?: string; + /** 赛事日志:操作来源 1=PC,2=小程序 */ + source?: string; + /** 赛事日志:操作人昵称 */ + sourceNickname?: string; + /** 赛事日志:操作人手机号 */ + sourcePhone?: string; + /** 赛事日志:赛事名称 */ + tournamentName?: string; + /** 开始日期 yyyy-MM-dd */ + dateBegin?: string; + /** 结束日期 yyyy-MM-dd */ + dateEnd?: string; +} + +export interface PageData { + total: number; + list: T[]; +} + +export interface ApiResult { + code: number; + msg: string; + data: T; +} diff --git a/src/config/mock/eventOperationLogs.ts b/src/config/mock/eventOperationLogs.ts index aabdc02..a068752 100644 --- a/src/config/mock/eventOperationLogs.ts +++ b/src/config/mock/eventOperationLogs.ts @@ -1,13 +1,32 @@ /** * 赛事操作日志假数据 + * + * 类型内联,避免与 @/api/logs 循环引用。 */ -import type { - OperationLogQueryParams, - PageData, - TournamentAdminOperationPageVO, -} from '@/api/logs/types'; +interface MockTournamentAdminOperationPageVO { + opName: string; + source: string; + nickname: string; + phone: string; + tournamentName: string; + obj: string; + content: string; + createDate: string; +} -const MOCK_EVENT_LOGS: TournamentAdminOperationPageVO[] = [ +interface MockEventOperationLogQueryParams { + source?: string; + sourceNickname?: string; + sourcePhone?: string; + tournamentName?: string; +} + +interface MockPageData { + total: number; + list: T[]; +} + +const MOCK_EVENT_LOGS: MockTournamentAdminOperationPageVO[] = [ { opName: '创建赛事', source: 'PC', @@ -33,8 +52,8 @@ const MOCK_EVENT_LOGS: TournamentAdminOperationPageVO[] = [ export function buildMockEventOperationLogPage( page: number, limit: number, - params: OperationLogQueryParams, -): PageData { + params: MockEventOperationLogQueryParams, +): MockPageData { let filtered = [...MOCK_EVENT_LOGS]; if (params.source) { diff --git a/src/config/mock/operationLogs.ts b/src/config/mock/operationLogs.ts index b2ff894..397132f 100644 --- a/src/config/mock/operationLogs.ts +++ b/src/config/mock/operationLogs.ts @@ -2,12 +2,28 @@ * 操作日志假数据 * 对应接口:GET /admin/sys/operation/page * - * 支持按 type、nickname、dateBegin/dateEnd 前端筛选, - * 模拟后端分页行为。 + * 类型内联,避免与 @/api/logs 循环引用。 */ -import type { SysOperationLogVO, OperationLogQueryParams, PageData } from '@/api/logs/types'; +interface MockSysOperationLogVO { + type: number; + nickname: string; + createDate: string; + content: string; +} -const MOCK_LOGS: SysOperationLogVO[] = [ +interface MockOperationLogQueryParams { + type?: string; + nickname?: string; + dateBegin?: string; + dateEnd?: string; +} + +interface MockPageData { + total: number; + list: T[]; +} + +const MOCK_LOGS: MockSysOperationLogVO[] = [ { type: 1, nickname: '张三', @@ -133,7 +149,7 @@ const MOCK_LOGS: SysOperationLogVO[] = [ /** 按日期范围过滤(dateBegin / dateEnd 格式 yyyy-MM-dd) */ function inDateRange(dateStr: string, begin?: string, end?: string): boolean { if (!begin && !end) return true; - const d = dateStr.slice(0, 10); // yyyy-MM-dd + const d = dateStr.slice(0, 10); if (begin && d < begin) return false; if (end && d > end) return false; return true; @@ -142,21 +158,18 @@ function inDateRange(dateStr: string, begin?: string, end?: string): boolean { export function buildMockOperationLogPage( page: number, limit: number, - params: OperationLogQueryParams, -): PageData { + params: MockOperationLogQueryParams, +): MockPageData { let filtered = [...MOCK_LOGS]; - // 按操作类型筛选(API 传 '1'/'2'/'3'/'4') if (params.type) { filtered = filtered.filter((item) => item.type === Number(params.type)); } - // 按操作人昵称模糊筛选 if (params.nickname) { filtered = filtered.filter((item) => item.nickname.includes(params.nickname!)); } - // 按日期范围筛选 filtered = filtered.filter((item) => inDateRange(item.createDate, params.dateBegin, params.dateEnd), ); diff --git a/src/pages/events/logs/index.module.less b/src/pages/events/logs/index.module.less new file mode 100644 index 0000000..c00070d --- /dev/null +++ b/src/pages/events/logs/index.module.less @@ -0,0 +1,36 @@ +// 操作内容单元格:文字最多 2 行省略,末尾带"查看"链接 +:global { + .log-content-cell { + display: flex; + align-items: center; + gap: 6px; + width: 100%; + cursor: default; + } + + .log-content-text { + flex: 1; + min-width: 0; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1.5; + word-break: break-all; + color: rgba(0, 0, 0, 0.88); + } + + .log-content-view { + flex-shrink: 0; + color: #1677ff; + cursor: pointer; + user-select: none; + line-height: 1.5; + white-space: nowrap; + + &:hover { + opacity: 0.85; + } + } +} diff --git a/src/pages/events/logs/index.tsx b/src/pages/events/logs/index.tsx new file mode 100644 index 0000000..f57578d --- /dev/null +++ b/src/pages/events/logs/index.tsx @@ -0,0 +1,210 @@ +import { defineComponent, ref, onMounted, onUnmounted, nextTick } from 'vue'; +import { + Button, + Input, + Table, + DatePicker, + Form, + Space, + Select, + Tooltip, + Pagination, +} from 'ant-design-vue'; +import { + useLogModel, + ACTION_TYPE_OPTIONS, + ACTION_SOURCE_OPTIONS, + ACTION_SOURCE_MAP, +} from './model/useLogModel'; +import { useState, useContainerSize } from '@/hooks'; +import pageStyles from '@/assets/styles/pageLayout.module.less'; +import './index.module.less'; + +const { RangePicker } = DatePicker; + +// ============================================================ +// LogContentCell: 操作内容单元格 +// ============================================================ +const LogContentCell = defineComponent({ + name: 'LogContentCell', + props: { text: { type: String, required: true } }, + setup(props) { + const textRef = ref(null); + const [overflow, setOverflow] = useState(false); + const checkOverflow = () => { + const el = textRef.value; + if (el) setOverflow(el.scrollHeight > el.clientHeight); + }; + let observer: ResizeObserver | null = null; + onMounted(() => { + nextTick(checkOverflow); + const el = textRef.value; + if (el) { + observer = new ResizeObserver(checkOverflow); + observer.observe(el); + } + }); + onUnmounted(() => observer?.disconnect()); + return () => { + const raw = props.text; + return ( +
+
+ {raw} +
+ {overflow.value ? ( + + 查看 + + ) : null} +
+ ); + }; + }, +}); + +// ============================================================ +// bodyCell 渲染 +// ============================================================ +function renderBodyCell({ column, text }: { column: any; text: any }) { + const value = text || '-'; + if (column.key === 'source') return {ACTION_SOURCE_MAP[text] || value}; + return {value}; +} + +export default defineComponent({ + name: 'EventLogs', + setup() { + const { + filterForm, + loading, + dataSource, + columns, + pagination, + handleSearch, + handleReset, + handlePageChange, + } = useLogModel(); + const { containerRef, height } = useContainerSize({ headerOffset: 55 }); + + onMounted(() => { + handleSearch(); + }); + + return () => ( +
+
+
+ + (filterForm.dateRange = val)} + /> + + + (filterForm.source = val || '')} + /> + + + + (filterForm.sourceNickname = val.target?.value ?? val ?? '') + } + onPressEnter={handleSearch} + /> + + + + (filterForm.sourcePhone = val.target?.value ?? val ?? '') + } + onPressEnter={handleSearch} + /> + + + + (filterForm.tournamentName = val.target?.value ?? val ?? '') + } + onPressEnter={handleSearch} + /> + + + + + + + +
+
+ +
+
+ + {{ + bodyCell: (args: any) => { + if (args.column.key === 'content') { + const raw = args.text || ''; + return raw ? : -; + } + return renderBodyCell(args); + }, + }} +
+
+
+ `共 ${total} 条`} + onChange={handlePageChange} + onShowSizeChange={handlePageChange} + /> +
+
+
+ ); + }, +}); diff --git a/src/pages/events/logs/model/useLogModel.ts b/src/pages/events/logs/model/useLogModel.ts new file mode 100644 index 0000000..efe8bb5 --- /dev/null +++ b/src/pages/events/logs/model/useLogModel.ts @@ -0,0 +1,154 @@ +import { computed, reactive, toRef, Ref } from 'vue'; +import { message } from 'ant-design-vue'; +import { useState, useDebounce, useThrottleFn } from '@/hooks'; +import { + getOperationLogs, + type TournamentAdminOperationPageVO, + type OperationLogQueryParams, +} from '@/api/logs'; + +// ============================================================ +// 常量 +// ============================================================ + +/** 操作类型选项(TODO: API type 字段待定意,暂时留空) */ +export const ACTION_TYPE_OPTIONS = [{ value: '', label: '全部' }] as const; + +/** 操作来源选项(value 对应 API source: 1=PC,2=小程序) */ +export const ACTION_SOURCE_OPTIONS = [ + { value: '', label: '全部' }, + { value: '1', label: 'PC' }, + { value: '2', label: '小程序' }, +] as const; + +/** 操作来源文案映射 */ +export const ACTION_SOURCE_MAP: Record = { + '1': 'PC', + '2': '小程序', +}; + +// ============================================================ +// Model +// ============================================================ + +export function useLogModel() { + // ===== 筛选条件(key 名对齐 API 查询参数) ===== + const filterForm = reactive({ + dateRange: null as [string, string] | null, + type: '', + source: '', + sourceNickname: '', + sourcePhone: '', + tournamentName: '', + }); + + const { debouncedValue: debouncedNickname } = useDebounce( + toRef(filterForm, 'sourceNickname') as Ref, + { delay: 300 }, + ); + const { debouncedValue: debouncedPhone } = useDebounce( + toRef(filterForm, 'sourcePhone') as Ref, + { delay: 300 }, + ); + const { debouncedValue: debouncedTournamentName } = useDebounce( + toRef(filterForm, 'tournamentName') as Ref, + { delay: 300 }, + ); + + // ===== 表格状态 ===== + const [loading, setLoading] = useState(false); + const [dataSource, setDataSource] = useState([]); + const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 }); + + // ===== 表格列配置(dataIndex 对齐 TournamentAdminOperationPageVO) ===== + const columns = [ + { title: '操作类型', dataIndex: 'opName', key: 'opName', width: 140 }, + { title: '操作来源', dataIndex: 'source', key: 'source', width: 100 }, + { title: '操作人昵称', dataIndex: 'nickname', key: 'nickname', width: 120 }, + { title: '操作人手机号', dataIndex: 'phone', key: 'phone', width: 140 }, + { title: '赛事名称', dataIndex: 'tournamentName', key: 'tournamentName', width: 200 }, + { title: '操作对象', dataIndex: 'obj', key: 'obj', width: 240 }, + { title: '操作内容', dataIndex: 'content', key: 'content', width: 360 }, + { title: '操作时间', dataIndex: 'createDate', key: 'createDate', width: 170 }, + ]; + + // ===== 构建 API 查询参数 ===== + const buildQueryParams = (): OperationLogQueryParams => { + const params: OperationLogQueryParams = { + page: String(pagination.value.current), + limit: String(pagination.value.pageSize), + }; + if (filterForm.dateRange) { + params.dateBegin = filterForm.dateRange[0]; + params.dateEnd = filterForm.dateRange[1]; + } + if (filterForm.type) params.type = filterForm.type; + if (filterForm.source) params.source = filterForm.source; + if (filterForm.sourceNickname.trim()) params.sourceNickname = filterForm.sourceNickname.trim(); + if (filterForm.sourcePhone.trim()) params.sourcePhone = filterForm.sourcePhone.trim(); + if (filterForm.tournamentName.trim()) params.tournamentName = filterForm.tournamentName.trim(); + return params; + }; + + // ===== 计算属性 ===== + const hasFilter = computed(() => { + return ( + filterForm.dateRange !== null || + filterForm.type !== '' || + filterForm.source !== '' || + debouncedNickname.value.trim() !== '' || + debouncedPhone.value.trim() !== '' || + debouncedTournamentName.value.trim() !== '' + ); + }); + + // ===== 方法 ===== + + const handleSearch = useThrottleFn(async () => { + setLoading(true); + try { + const params = buildQueryParams(); + console.log('操作日志查询参数:', params); + const res = await getOperationLogs(params); + if (res.code === 200) { + setDataSource(res.data.list); + setPagination({ ...pagination.value, total: res.data.total }); + } else { + message.error(res.msg || '查询失败'); + } + } catch (e: any) { + console.error('操作日志查询失败:', e); + } finally { + setLoading(false); + } + }, 500); + + const handleReset = useThrottleFn(() => { + filterForm.dateRange = null; + filterForm.type = ''; + filterForm.source = ''; + filterForm.sourceNickname = ''; + filterForm.sourcePhone = ''; + filterForm.tournamentName = ''; + setPagination({ current: 1, pageSize: 10, total: 0 }); + setDataSource([]); + setTimeout(() => handleSearch(), 350); + }, 500); + + const handlePageChange = (page: number, pageSize: number) => { + setPagination({ ...pagination.value, current: page, pageSize }); + handleSearch(); + }; + + return { + filterForm, + loading, + dataSource, + columns, + pagination, + hasFilter, + handleSearch, + handleReset, + handlePageChange, + }; +} diff --git a/src/pages/system/logs/index.tsx b/src/pages/system/logs/index.tsx new file mode 100644 index 0000000..e2241d8 --- /dev/null +++ b/src/pages/system/logs/index.tsx @@ -0,0 +1,118 @@ +import { defineComponent, onMounted } from 'vue'; +import { Button, Input, Table, DatePicker, Form, Space, Select, Pagination } from 'ant-design-vue'; +import { useLogModel, ACTION_TYPE_OPTIONS, ACTION_TYPE_MAP } from './model/useLogModel'; +import { useContainerSize } from '@/hooks'; +import pageStyles from '@/assets/styles/pageLayout.module.less'; + +const { RangePicker } = DatePicker; + +/** + * bodyCell 渲染 + */ +function renderBodyCell({ column, text }: { column: any; text: any }) { + if (column.key === 'type') { + return {ACTION_TYPE_MAP[text as number] || text || '-'}; + } + return {text || '-'}; +} + +/** + * 系统操作日志 + */ +export default defineComponent({ + name: 'SystemLogs', + setup() { + const { + filterForm, + loading, + dataSource, + columns, + pagination, + handleSearch, + handleReset, + handlePageChange, + } = useLogModel(); + + const { containerRef, height } = useContainerSize({ headerOffset: 55 }); + + // 首次进入自动加载 + onMounted(() => { + handleSearch(); + }); + + return () => ( +
+ {/* ===== 筛选区 ===== */} +
+
+ + (filterForm.actionTimeRange = val)} + /> + + + + + + + + + + +
+
+ + {/* ===== 表格区 ===== */} +
+
+ + {{ + bodyCell: (args: any) => renderBodyCell(args), + }} +
+
+ + {/* 独立分页 */} +
+ `共 ${total} 条`} + onChange={handlePageChange} + onShowSizeChange={handlePageChange} + /> +
+
+
+ ); + }, +}); diff --git a/src/pages/system/logs/model/useLogModel.ts b/src/pages/system/logs/model/useLogModel.ts new file mode 100644 index 0000000..394216c --- /dev/null +++ b/src/pages/system/logs/model/useLogModel.ts @@ -0,0 +1,146 @@ +import { computed, reactive, toRef, Ref } from 'vue'; +import dayjs from 'dayjs'; +import { useState, useDebounce, useThrottleFn } from '@/hooks'; +import { + getOperationLogList, + type SysOperationLogVO, + type OperationLogQueryParams, +} from '@/api/logs'; + +// ============================================================ +// 常量 +// ============================================================ + +/** 操作类型选项(筛选),value 对应 API type 字段 */ +export const ACTION_TYPE_OPTIONS = [ + { value: '', label: '全部' }, + { value: '1', label: '下架赛事' }, + { value: '2', label: '上架赛事' }, + { value: '3', label: '禁用用户' }, + { value: '4', label: '启用用户' }, +] as const; + +/** 操作类型文案映射 */ +export const ACTION_TYPE_MAP: Record = { + 1: '下架赛事', + 2: '上架赛事', + 3: '禁用用户', + 4: '启用用户', +}; + +// ============================================================ +// Model +// ============================================================ + +/** + * 系统操作日志页数据模型 + */ +export function useLogModel() { + // ===== 筛选条件 ===== + const filterForm = reactive({ + actionTimeRange: null as [string, string] | null, + actionType: '', + searchOperator: '', + }); + + // 操作人字段防抖 300ms + const { debouncedValue: debouncedOperator } = useDebounce( + toRef(filterForm, 'searchOperator') as Ref, + { delay: 300 }, + ); + + // ===== 表格状态 ===== + const [loading, setLoading] = useState(false); + const [dataSource, setDataSource] = useState([]); + const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 }); + + // ===== 表格列配置(字段名对齐 API) ===== + const columns = [ + { title: '操作类型', dataIndex: 'type', key: 'type', width: 140 }, + { title: '操作人', dataIndex: 'nickname', key: 'nickname', width: 140 }, + { title: '操作内容', dataIndex: 'content', key: 'content', minWidth: 360 }, + { title: '操作时间', dataIndex: 'createDate', key: 'createDate', width: 180 }, + ]; + + // ===== 计算属性 ===== + const hasFilter = computed(() => { + return ( + filterForm.actionTimeRange !== null || + filterForm.actionType !== '' || + debouncedOperator.value.trim() !== '' + ); + }); + + // ===== 构建 API 查询参数 ===== + const buildQueryParams = (): OperationLogQueryParams => { + const params: OperationLogQueryParams = { + page: String(pagination.value.current), + limit: String(pagination.value.pageSize), + }; + + // 时间范围 → dateBegin / dateEnd + if (filterForm.actionTimeRange) { + const [start, end] = filterForm.actionTimeRange; + if (start) params.dateBegin = dayjs(start).format('YYYY-MM-DD'); + if (end) params.dateEnd = dayjs(end).format('YYYY-MM-DD'); + } + + // 操作类型(仅非空时传参) + if (filterForm.actionType) { + params.type = filterForm.actionType; + } + + // 操作人昵称(防抖后的值) + if (debouncedOperator.value.trim()) { + params.nickname = debouncedOperator.value.trim(); + } + + return params; + }; + + // ===== 方法 ===== + + /** 查询(节流 500ms) */ + const handleSearch = useThrottleFn(async () => { + setLoading(true); + try { + const queryParams = buildQueryParams(); + const res = await getOperationLogList(queryParams); + if (res.code === 200) { + setDataSource(res.data.list); + setPagination({ ...pagination.value, total: res.data.total }); + } + } catch { + // 网络层已统一提示 + } finally { + setLoading(false); + } + }, 500); + + /** 重置(重置后自动查询) */ + const handleReset = useThrottleFn(() => { + filterForm.actionTimeRange = null; + filterForm.actionType = ''; + filterForm.searchOperator = ''; + setPagination({ current: 1, pageSize: 10, total: 0 }); + setDataSource([]); + setTimeout(() => handleSearch(), 350); + }, 500); + + const handlePageChange = (page: number, pageSize: number) => { + setPagination({ ...pagination.value, current: page, pageSize }); + handleSearch(); + }; + + return { + filterForm, + loading, + dataSource, + columns, + pagination, + hasFilter, + handleSearch, + handleReset, + handlePageChange, + }; +}