From b34646f8697916b79cc2561b7bcc6cc7ccbd9c62 Mon Sep 17 00:00:00 2001 From: BenjaminNH <1249376374@qq.com> Date: Thu, 17 Jul 2025 19:04:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E8=AF=A6=E6=83=85=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/admin/DeviceDetailStatsModal.jsx | 129 +++++++++++++++++++++ src/pages/admin/DeviceStats.jsx | 28 +++++ 2 files changed, 157 insertions(+) create mode 100644 src/pages/admin/DeviceDetailStatsModal.jsx diff --git a/src/pages/admin/DeviceDetailStatsModal.jsx b/src/pages/admin/DeviceDetailStatsModal.jsx new file mode 100644 index 0000000..984e897 --- /dev/null +++ b/src/pages/admin/DeviceDetailStatsModal.jsx @@ -0,0 +1,129 @@ +import { message, Modal, Space, Spin, Table } from "antd"; +import { useEffect, useState } from "react"; +import axiosInstance from "../../api/axios"; + +export default function DeviceDetailStatsModal({ + visible, + record, + range, + onClose, +}) { + const [loading, setLoading] = useState(false); + const [data, setData] = useState([]); + + const fetchData = async () => { + setLoading(true); + try { + const res = await axiosInstance.get("/device/detail-stats", { + params: { + deviceId: record.deviceId, + start: range[0].format("YYYY-MM-DD"), + end: range[1].format("YYYY-MM-DD"), + }, + }); + setData(res); + } catch (e) { + message.error("获取数据失败"); + } finally { + setLoading(false); + } + }; + + const handleExport = async () => { + setLoading(true); + try { + const response = await axiosInstance.get("/device/detail-stats/export", { + params: { + deviceId: record.deviceId, + start: range[0].format("YYYY-MM-DD"), + end: range[1].format("YYYY-MM-DD"), + }, + responseType: "blob", // 二进制流 + skipInterceptor: true, + }); + + // 从响应头获取文件名,兼容后端返回 + const fileName = `${record?.deviceName}_${range[0].format( + "YYYY.MM.DD" + )}-${range[1].format("YYYY.MM.DD")}_使用详情.xlsx`; + + // 创建blob对象和下载链接 + const blob = new Blob([response.data], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = fileName; + document.body.appendChild(a); + a.click(); + a.remove(); + window.URL.revokeObjectURL(url); + + message.success("导出成功"); + } catch (error) { + message.error("导出失败,请稍后重试"); + console.error(error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + if (visible) { + fetchData(); + } + }, [visible, record]); + + const columns = [ + { + title: "使用人", + dataIndex: "applicantName", + key: "applicantName", + sorter: (a, b) => a.applicantName.localeCompare(b.applicantName), + }, + { + title: "所属团队", + dataIndex: "applicantTeam", + key: "applicantTeam", + sorter: (a, b) => a.applicantTeam.localeCompare(b.applicantTeam), + }, + { + title: "开始日期", + dataIndex: "startDay", + key: "startDay", + sorter: (a, b) => a.startDay.localeCompare(b.startDay), + }, + { + title: "结束日期", + dataIndex: "endDay", + key: "endDay", + sorter: (a, b) => a.endDay.localeCompare(b.endDay), + }, + ]; + + return ( + + { + onClose(); + }} + okText="导出Excel" + onOk={handleExport} + > + record.deviceId} + dataSource={data} + columns={columns} + className="mt-4" + /> + + + ); +} diff --git a/src/pages/admin/DeviceStats.jsx b/src/pages/admin/DeviceStats.jsx index b1ada2b..d9a5560 100644 --- a/src/pages/admin/DeviceStats.jsx +++ b/src/pages/admin/DeviceStats.jsx @@ -3,6 +3,7 @@ import dayjs from "dayjs"; import { useEffect, useState } from "react"; import axiosInstance from "../../api/axios"; import { datePresets } from "../../config/datePresetsConfig"; +import DeviceDetailStatsModal from "./DeviceDetailStatsModal"; const { RangePicker } = DatePicker; @@ -15,6 +16,8 @@ export default function DeviceStats() { ]); const [search, setSearch] = useState(""); const [loading, setLoading] = useState(false); + const [visiable, setVisiable] = useState(false); + const [selectedRecord, setSelectedRecord] = useState(null); const fetchData = async () => { setLoading(true); @@ -107,6 +110,23 @@ export default function DeviceStats() { key: "totalUsageDays", sorter: (a, b) => a.totalUsageDays - b.totalUsageDays, }, + { + title: "操作", + key: "action", + render: (_, record) => { + return ( + + ); + }, + }, ]; return ( @@ -135,6 +155,14 @@ export default function DeviceStats() { dataSource={filteredData} columns={columns} /> + { + setVisiable(false); + }} + range={range} + /> ); }