feat: 实现设备使用详情统计
This commit is contained in:
parent
87cc58be92
commit
b34646f869
129
src/pages/admin/DeviceDetailStatsModal.jsx
Normal file
129
src/pages/admin/DeviceDetailStatsModal.jsx
Normal file
@ -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 (
|
||||||
|
<Spin spinning={loading}>
|
||||||
|
<Modal
|
||||||
|
open={visible}
|
||||||
|
title={`${record?.deviceName}_${range[0].format(
|
||||||
|
"YYYY.MM.DD"
|
||||||
|
)}-${range[1].format("YYYY.MM.DD")}_使用详情`}
|
||||||
|
width={"80%"}
|
||||||
|
cancelText="返回"
|
||||||
|
onCancel={() => {
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
okText="导出Excel"
|
||||||
|
onOk={handleExport}
|
||||||
|
>
|
||||||
|
<Table
|
||||||
|
rowKey={(record) => record.deviceId}
|
||||||
|
dataSource={data}
|
||||||
|
columns={columns}
|
||||||
|
className="mt-4"
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
</Spin>
|
||||||
|
);
|
||||||
|
}
|
@ -3,6 +3,7 @@ import dayjs from "dayjs";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import axiosInstance from "../../api/axios";
|
import axiosInstance from "../../api/axios";
|
||||||
import { datePresets } from "../../config/datePresetsConfig";
|
import { datePresets } from "../../config/datePresetsConfig";
|
||||||
|
import DeviceDetailStatsModal from "./DeviceDetailStatsModal";
|
||||||
|
|
||||||
const { RangePicker } = DatePicker;
|
const { RangePicker } = DatePicker;
|
||||||
|
|
||||||
@ -15,6 +16,8 @@ export default function DeviceStats() {
|
|||||||
]);
|
]);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [visiable, setVisiable] = useState(false);
|
||||||
|
const [selectedRecord, setSelectedRecord] = useState(null);
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -107,6 +110,23 @@ export default function DeviceStats() {
|
|||||||
key: "totalUsageDays",
|
key: "totalUsageDays",
|
||||||
sorter: (a, b) => a.totalUsageDays - b.totalUsageDays,
|
sorter: (a, b) => a.totalUsageDays - b.totalUsageDays,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
key: "action",
|
||||||
|
render: (_, record) => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedRecord(record);
|
||||||
|
setVisiable(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
查看详情
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -135,6 +155,14 @@ export default function DeviceStats() {
|
|||||||
dataSource={filteredData}
|
dataSource={filteredData}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
/>
|
/>
|
||||||
|
<DeviceDetailStatsModal
|
||||||
|
visible={visiable}
|
||||||
|
record={selectedRecord}
|
||||||
|
onClose={() => {
|
||||||
|
setVisiable(false);
|
||||||
|
}}
|
||||||
|
range={range}
|
||||||
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user