From a49888587f480bf2e1eb5248086804bbc60436f6 Mon Sep 17 00:00:00 2001 From: chenhao Date: Mon, 11 May 2026 20:14:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E5=92=8C=E6=90=9C=E7=B4=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 `ListTable` 和 `AppPagination` 组件 - 添加分页状态和处理函数 - 更新搜索逻辑以重置分页 - 重构表格列定义和数据加载逻辑 --- frontend/src/pages/devices/index.tsx | 267 +++++++++++++++------------ 1 file changed, 148 insertions(+), 119 deletions(-) diff --git a/frontend/src/pages/devices/index.tsx b/frontend/src/pages/devices/index.tsx index ef49adc..35f64e4 100644 --- a/frontend/src/pages/devices/index.tsx +++ b/frontend/src/pages/devices/index.tsx @@ -1,14 +1,15 @@ -import { Button, Card, Col, Drawer, Form, Input, Popconfirm, Row, Select, Space, Table, Tag, Typography, message } from "antd"; +import { Button, Card, Col, Drawer, Form, Input, Popconfirm, Row, Select, Space, Tag, Typography, message } from "antd"; import { CheckCircleOutlined, DesktopOutlined, DisconnectOutlined, EditOutlined, ReloadOutlined, SearchOutlined, ThunderboltOutlined, UserOutlined } from "@ant-design/icons"; import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { kickManagedDevice, listManagedDevices, updateManagedDevice } from "@/api"; import PageHeader from "@/components/shared/PageHeader"; import PageContainer from "@/components/shared/PageContainer"; +import ListTable from "@/components/shared/ListTable/ListTable"; +import AppPagination from "@/components/shared/AppPagination"; import { useDict } from "@/hooks/useDict"; import { usePermission } from "@/hooks/usePermission"; import type { DeviceInfo } from "@/types"; -import { getStandardPagination } from "@/utils/pagination"; import "./index.less"; const { Text } = Typography; @@ -29,6 +30,7 @@ export default function Devices() { const [open, setOpen] = useState(false); const [editing, setEditing] = useState(null); const [form] = Form.useForm(); + const [pagination, setPagination] = useState({ current: 1, pageSize: 20 }); const loadData = async () => { setLoading(true); @@ -63,6 +65,12 @@ export default function Devices() { }); }, [devices, searchText]); + const pagedData = useMemo(() => { + const start = (pagination.current - 1) * pagination.pageSize; + const end = start + pagination.pageSize; + return filteredData.slice(start, end); + }, [filteredData, pagination]); + const stats = useMemo(() => { const total = devices.length; const online = devices.filter((device) => device.online).length; @@ -104,6 +112,125 @@ export default function Devices() { await loadData(); }; + const handlePageChange = (page: number, pageSize: number) => { + setPagination({ current: page, pageSize }); + }; + + const handleSearchChange = (value: string) => { + setSearchText(value); + setPagination((prev) => ({ ...prev, current: 1 })); + }; + + const columns = [ + { + title: t("devicesExt.device"), + key: "device", + width: 280, + render: (_value: unknown, record: DeviceInfo) => ( + +
+
+
+
{record.deviceName || t("devicesExt.unnamedDevice")}
+
{record.deviceCode}
+
+
+ ) + }, + { + title: t("devices.owner"), + key: "user", + width: 220, + render: (_value: unknown, record: DeviceInfo) => { + if (!record.userId) { + return {t("devicesExt.unboundAccount")}; + } + return ( + + + ); + } + }, + { + title: t("devicesExt.terminalType"), + dataIndex: "terminalType", + width: 140, + render: (text: string) => {text || "-"} + }, + { + title: t("devicesExt.terminalVersion"), + dataIndex: "terminalVersion", + width: 160, + render: (text: string) => {text || "-"} + }, + { + title: t("devicesExt.onlineStatus"), + dataIndex: "online", + width: 120, + render: (online: boolean) => ( + {online ? t("devicesExt.online") : t("devicesExt.offline")} + ) + }, + { + title: t("devicesExt.lastOnlineAt"), + dataIndex: "lastOnlineAt", + width: 180, + render: (text: string) => ( + + {text ? text.replace("T", " ").substring(0, 19) : "-"} + + ) + }, + { + title: t("common.status"), + dataIndex: "status", + width: 100, + render: (status: number) => { + const item = statusDict.find((dictItem) => dictItem.itemValue === String(status)); + return {item?.itemLabel || (status === 1 ? t("devicesExt.enabled") : t("devicesExt.disabled"))}; + } + }, + { + title: t("devices.updateTime"), + dataIndex: "updatedAt", + width: 180, + render: (text: string) => ( + + {text?.replace("T", " ").substring(0, 19)} + + ) + }, + { + title: t("common.action"), + key: "action", + width: 140, + fixed: "right" as const, + render: (_value: unknown, record: DeviceInfo) => ( + + {can("device:update") ? ( +