feat: 实现管理员设备统计数据计算及导出

This commit is contained in:
BenjaminNH 2025-07-02 22:06:15 +08:00
parent 0f9c143d46
commit b350e933d3
8 changed files with 113 additions and 8 deletions

View File

@ -61,6 +61,11 @@
<version>0.12.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -1,19 +1,28 @@
package github.benjamin.equipreservebackend.controller;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import github.benjamin.equipreservebackend.entity.Device;
import github.benjamin.equipreservebackend.response.ResponseResult;
import github.benjamin.equipreservebackend.service.DeviceService;
import github.benjamin.equipreservebackend.service.ReservationService;
import github.benjamin.equipreservebackend.vo.DeviceAdminVO;
import github.benjamin.equipreservebackend.vo.DeviceStatsVO;
import github.benjamin.equipreservebackend.vo.DeviceUserVO;
import github.benjamin.equipreservebackend.vo.TimeRangeVO;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
@RestController
@ -45,7 +54,7 @@ public class DeviceController {
@PreAuthorize("hasRole('DEVICE_ADMIN')")
@PostMapping("/{userId}")
public ResponseResult<Device> addDevice(@PathVariable("userId") Long userId,
@RequestBody Device device) {
@RequestBody Device device) {
deviceService.addDevice(userId, device);
return ResponseResult.success(device);
}
@ -69,9 +78,9 @@ public class DeviceController {
@PreAuthorize("hasRole('DEVICE_ADMIN')")
@GetMapping("/{userId}")
public ResponseResult<Page<DeviceAdminVO>> getAdminDevice(@PathVariable("userId") Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String name) {
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@RequestParam(required = false) String name) {
Page<Device> pageRequest = new Page<>(page, size);
return ResponseResult.success(deviceService.getAdminDevice(pageRequest, userId, name));
@ -84,4 +93,31 @@ public class DeviceController {
String imagePath = deviceService.saveImage(id, image);
return ResponseResult.success(imagePath);
}
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/usage-stats")
public ResponseResult<List<DeviceStatsVO>> getDeviceUsageStats(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate start,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
return ResponseResult.success(deviceService.getDeviceUsageStats(start, end));
}
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/usage-stats/export")
public void exportDeviceUsageStats(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate start,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end,
HttpServletResponse response) throws IOException {
String fileName = String.format("设备使用统计_%s-%s.xlsx", start.format(DateTimeFormatter.ISO_DATE), end.format(DateTimeFormatter.ISO_DATE));
String encodedName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;filename=" + encodedName);
// 查询数据
List<DeviceStatsVO> data = deviceService.getDeviceUsageStats(start, end);
// 使用EasyExcel写入response流
EasyExcel.write(response.getOutputStream(), DeviceStatsVO.class)
.sheet("设备使用统计")
.doWrite(data);
}
}

View File

@ -2,8 +2,13 @@ package github.benjamin.equipreservebackend.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import github.benjamin.equipreservebackend.entity.Device;
import github.benjamin.equipreservebackend.vo.DeviceStatsVO;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.util.List;
@Repository
public interface DeviceMapper extends BaseMapper<Device> {
List<DeviceStatsVO> getDeviceUsageStats(LocalDate start, LocalDate end);
}

View File

@ -3,10 +3,13 @@ package github.benjamin.equipreservebackend.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import github.benjamin.equipreservebackend.entity.Device;
import github.benjamin.equipreservebackend.vo.DeviceAdminVO;
import github.benjamin.equipreservebackend.vo.DeviceStatsVO;
import github.benjamin.equipreservebackend.vo.DeviceUserVO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
public interface DeviceService {
Page<DeviceUserVO> getUserDevices(Page<Device> pageRequest, String name);
@ -27,4 +30,6 @@ public interface DeviceService {
* @return 分页后的设备列表
*/
Page<DeviceAdminVO> getAdminDevice(Page<Device> pageRequest, Long userId, String name);
List<DeviceStatsVO> getDeviceUsageStats(LocalDate start, LocalDate end);
}

View File

@ -17,6 +17,7 @@ import github.benjamin.equipreservebackend.service.ReservationService;
import github.benjamin.equipreservebackend.utils.FileUtil;
import github.benjamin.equipreservebackend.utils.PageUtil;
import github.benjamin.equipreservebackend.vo.DeviceAdminVO;
import github.benjamin.equipreservebackend.vo.DeviceStatsVO;
import github.benjamin.equipreservebackend.vo.DeviceUserVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -29,6 +30,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -149,6 +151,11 @@ public class DeviceServiceImpl implements DeviceService {
return res;
}
@Override
public List<DeviceStatsVO> getDeviceUsageStats(LocalDate start, LocalDate end) {
return deviceMapper.getDeviceUsageStats(start, end);
}
private DeviceUserVO buildDeviceVO(Device device, List<Reservation> reservations) {
DeviceUserVO vo = new DeviceUserVO(device);
// TODO 显示设备状态逻辑根据客户需求修改

View File

@ -56,12 +56,8 @@ public class ReservationServiceImpl implements ReservationService {
@Override
public void addReservation(Reservation reservation) {
User user = userMapper.selectById(reservation.getUserId());
Team team = teamMapper.selectById(user.getTeamId());
Device device = deviceMapper.selectById(reservation.getDeviceId());
reservation.setApplicantName(user.getName());
reservation.setApplicantTeam(team.getName());
reservation.setApplicantContact(user.getPhone());
reservation.setDeviceAdminId(device.getDeviceAdminId());
reservation.setStatus(String.valueOf(ReservationStatus.PENDING_LEADER));
reservationMapper.insert(reservation);

View File

@ -0,0 +1,29 @@
package github.benjamin.equipreservebackend.vo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
@Data
public class DeviceStatsVO {
@JsonSerialize(using = ToStringSerializer.class)
@ExcelIgnore
private Long deviceId;
@ColumnWidth(15)
@ExcelProperty("设备名称")
private String deviceName;
@ColumnWidth(15)
@ExcelProperty("使用次数")
private Integer usageCount;
@ColumnWidth(20)
@ExcelProperty("使用时长(天)")
private Integer totalUsageDays;
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="github.benjamin.equipreservebackend.mapper.DeviceMapper">
<select id="getDeviceUsageStats" resultType="github.benjamin.equipreservebackend.vo.DeviceStatsVO">
SELECT
d.id AS deviceId,
d.name AS deviceName,
COUNT(*) AS usageCount,
SUM(TIMESTAMPDIFF(DAY, r.start_time, r.end_time)) AS totalUsageDays
FROM reservations r
JOIN devices d ON r.device_id = d.id
WHERE r.status IN ('APPROVED', 'APPROVED_ASSIST')
AND r.start_time >= #{start}
AND r.end_time &lt; #{end}
GROUP BY d.id
ORDER BY totalUsageDays DESC
</select>
</mapper>