From 48c1de18235020edff108339ed1d12bade8a2b90 Mon Sep 17 00:00:00 2001
From: Junjie <DELL@qq.com>
Date: 星期一, 08 十二月 2025 16:37:02 +0800
Subject: [PATCH] #
---
src/main/java/com/zy/asrs/controller/DeviceLogController.java | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 338 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/zy/asrs/controller/DeviceLogController.java b/src/main/java/com/zy/asrs/controller/DeviceLogController.java
new file mode 100644
index 0000000..d5537e9
--- /dev/null
+++ b/src/main/java/com/zy/asrs/controller/DeviceLogController.java
@@ -0,0 +1,338 @@
+package com.zy.asrs.controller;
+
+import com.core.annotations.ManagerAuth;
+import com.core.common.Cools;
+import com.core.common.R;
+import com.zy.common.web.BaseController;
+import com.zy.core.enums.SlaveType;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+@RestController
+public class DeviceLogController extends BaseController {
+
+ @Value("${deviceLogStorage.loggingPath}")
+ private String loggingPath;
+
+ private static class ProgressInfo {
+ long totalRaw;
+ long processedRaw;
+ int totalCount;
+ int processedCount;
+ boolean finished;
+ }
+
+ private static final Map<String, ProgressInfo> DOWNLOAD_PROGRESS = new ConcurrentHashMap<>();
+
+ @RequestMapping(value = "/deviceLog/dates/auth")
+ @ManagerAuth
+ public R dates() {
+ try {
+ Path baseDir = Paths.get(loggingPath);
+ if (!Files.exists(baseDir)) {
+ return R.ok(new ArrayList<>());
+ }
+ List<String> days = Files.list(baseDir)
+ .filter(Files::isDirectory)
+ .map(p -> p.getFileName().toString())
+ .filter(name -> name.length() == 8 && name.chars().allMatch(Character::isDigit))
+ .sorted()
+ .collect(Collectors.toList());
+ Map<String, Map<String, List<String>>> grouped = new LinkedHashMap<>();
+ for (String day : days) {
+ String year = day.substring(0, 4);
+ String month = day.substring(4, 6);
+ grouped.computeIfAbsent(year, k -> new LinkedHashMap<>())
+ .computeIfAbsent(month, k -> new ArrayList<>())
+ .add(day);
+ }
+ List<Map<String, Object>> tree = new ArrayList<>();
+ for (Map.Entry<String, Map<String, List<String>>> yEntry : grouped.entrySet()) {
+ Map<String, Object> yNode = new HashMap<>();
+ yNode.put("title", yEntry.getKey());
+ yNode.put("id", yEntry.getKey());
+ List<Map<String, Object>> mChildren = new ArrayList<>();
+ for (Map.Entry<String, List<String>> mEntry : yEntry.getValue().entrySet()) {
+ Map<String, Object> mNode = new HashMap<>();
+ mNode.put("title", mEntry.getKey());
+ mNode.put("id", yEntry.getKey() + "-" + mEntry.getKey());
+ List<Map<String, Object>> dChildren = new ArrayList<>();
+ for (String d : mEntry.getValue()) {
+ Map<String, Object> dNode = new HashMap<>();
+ dNode.put("title", d.substring(6, 8));
+ dNode.put("id", d);
+ dNode.put("day", d);
+ dChildren.add(dNode);
+ }
+ mNode.put("children", dChildren);
+ mChildren.add(mNode);
+ }
+ yNode.put("children", mChildren);
+ tree.add(yNode);
+ }
+ return R.ok(tree);
+ } catch (Exception e) {
+ return R.error("璇诲彇鏃ユ湡澶辫触");
+ }
+ }
+
+ @RequestMapping(value = "/deviceLog/day/{day}/devices/auth")
+ @ManagerAuth
+ public R devices(@PathVariable("day") String day) {
+ try {
+ if (day == null || day.length() != 8 || !day.chars().allMatch(Character::isDigit)) {
+ return R.error("鏃ユ湡鏍煎紡閿欒");
+ }
+ Path dayDir = Paths.get(loggingPath, day);
+ if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) {
+ return R.ok(new ArrayList<>());
+ }
+ List<Path> files = Files.list(dayDir)
+ .filter(p -> !Files.isDirectory(p) && p.getFileName().toString().endsWith(".log"))
+ .collect(Collectors.toList());
+ Map<String, Map<String, Object>> deviceMap = new HashMap<>();
+ for (Path p : files) {
+ String name = p.getFileName().toString();
+ String[] parts = name.split("_");
+ if (parts.length < 4) {
+ continue;
+ }
+ String deviceNo = parts[1];
+ String type = parts[0];
+ Map<String, Object> info = deviceMap.computeIfAbsent(deviceNo, k -> {
+ Map<String, Object> map = new HashMap<>();
+ map.put("deviceNo", deviceNo);
+ map.put("types", new HashSet<String>());
+ map.put("fileCount", 0);
+ return map;
+ });
+ ((Set<String>) info.get("types")).add(type);
+ info.put("fileCount", ((Integer) info.get("fileCount")) + 1);
+ }
+ List<Map<String, Object>> res = deviceMap.values().stream().map(m -> {
+ Map<String, Object> x = new HashMap<>();
+ x.put("deviceNo", m.get("deviceNo"));
+ x.put("types", ((Set<String>) m.get("types")).stream().collect(Collectors.toList()));
+ x.put("fileCount", m.get("fileCount"));
+ return x;
+ }).collect(Collectors.toList());
+ return R.ok(res);
+ } catch (Exception e) {
+ return R.error("璇诲彇璁惧鍒楄〃澶辫触");
+ }
+ }
+
+ @RequestMapping(value = "/deviceLog/day/{day}/download/auth")
+ @ManagerAuth
+ public void download(@PathVariable("day") String day,
+ @RequestParam("type") String type,
+ @RequestParam("deviceNo") String deviceNo,
+ @RequestParam(value = "offset", required = false) Integer offset,
+ @RequestParam(value = "limit", required = false) Integer limit,
+ @RequestParam(value = "progressId", required = false) String progressId,
+ HttpServletResponse response) {
+ try {
+ String dayClean = day == null ? null : day.replaceAll("\\D", "");
+ if (dayClean == null || dayClean.length() != 8 || !dayClean.chars().allMatch(Character::isDigit)) {
+ response.setStatus(400);
+ return;
+ }
+ if (type == null || SlaveType.findInstance(type) == null) {
+ response.setStatus(400);
+ return;
+ }
+ if (deviceNo == null || !deviceNo.chars().allMatch(Character::isDigit)) {
+ response.setStatus(400);
+ return;
+ }
+ Path dayDir = Paths.get(loggingPath, dayClean);
+ if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) {
+ response.setStatus(404);
+ return;
+ }
+ List<Path> files = Files.list(dayDir)
+ .filter(p -> {
+ String name = p.getFileName().toString();
+ String prefix = type + "_" + deviceNo + "_" + dayClean + "_";
+ return name.endsWith(".log") && name.startsWith(prefix);
+ }).collect(Collectors.toList());
+ // 鎺掑簭锛堟寜鏂囦欢涓殑绱㈠紩鍙烽�掑锛�
+ String prefix = type + "_" + deviceNo + "_" + dayClean + "_";
+ files.sort(Comparator.comparingInt(p -> {
+ String n = p.getFileName().toString();
+ try {
+ String suf = n.substring(prefix.length(), n.length() - 4);
+ return Integer.parseInt(suf);
+ } catch (Exception e) {
+ return Integer.MAX_VALUE;
+ }
+ }));
+ int from = offset == null || offset < 0 ? 0 : offset;
+ int max = limit == null || limit <= 0 ? 200 : limit;
+ int to = Math.min(files.size(), from + max);
+ if (from >= files.size()) {
+ response.setStatus(404);
+ return;
+ }
+ files = files.subList(from, to);
+ if (files.isEmpty()) {
+ response.setStatus(404);
+ return;
+ }
+ ProgressInfo info;
+ String id = progressId;
+ if (Cools.isEmpty(id)) {
+ id = UUID.randomUUID().toString();
+ }
+ List<Path> finalFiles = files;
+ info = DOWNLOAD_PROGRESS.computeIfAbsent(id, k -> {
+ ProgressInfo x = new ProgressInfo();
+ x.totalCount = finalFiles.size();
+ long sum = 0L;
+ for (Path f : finalFiles) {
+ try { sum += Files.size(f); } catch (Exception ignored) {}
+ }
+ x.totalRaw = sum;
+ x.processedRaw = 0L;
+ x.processedCount = 0;
+ x.finished = false;
+ return x;
+ });
+ response.reset();
+ response.setContentType("application/zip");
+ String filename = type + "_" + deviceNo + "_" + dayClean + ".zip";
+ response.setHeader("Content-Disposition", "attachment; filename=" + filename);
+ long totalRawSize = 0L;
+ for (Path f : files) {
+ try { totalRawSize += Files.size(f); } catch (Exception ignored) {}
+ }
+ response.setHeader("X-Total-Size", String.valueOf(totalRawSize));
+ response.setHeader("X-File-Count", String.valueOf(files.size()));
+ response.setHeader("X-Progress-Id", id);
+ try (java.util.zip.ZipOutputStream zos = new java.util.zip.ZipOutputStream(response.getOutputStream())) {
+ for (Path f : files) {
+ java.util.zip.ZipEntry entry = new java.util.zip.ZipEntry(f.getFileName().toString());
+ zos.putNextEntry(entry);
+ Files.copy(f, zos);
+ zos.closeEntry();
+ try {
+ info.processedRaw += Files.size(f);
+ } catch (Exception ignored) {}
+ info.processedCount += 1;
+ }
+ zos.finish();
+ info.finished = true;
+ }
+ } catch (Exception e) {
+ try { response.setStatus(500); } catch (Exception ignore) {}
+ }
+ }
+
+ @RequestMapping(value = "/deviceLog/download/init/auth")
+ @ManagerAuth
+ public R init(@org.springframework.web.bind.annotation.RequestBody com.alibaba.fastjson.JSONObject param) {
+ try {
+ String day = param.getString("day");
+ String type = param.getString("type");
+ String deviceNo = param.getString("deviceNo");
+ Integer offset = param.getInteger("offset");
+ Integer limit = param.getInteger("limit");
+ String dayClean = Cools.isEmpty(day) ? null : day.replaceAll("\\D", "");
+ if (Cools.isEmpty(dayClean) || dayClean.length() != 8 || !dayClean.chars().allMatch(Character::isDigit)) {
+ return R.error("鏃ユ湡鏍煎紡閿欒");
+ }
+ if (Cools.isEmpty(type) || SlaveType.findInstance(type) == null) {
+ return R.error("璁惧绫诲瀷閿欒");
+ }
+ if (Cools.isEmpty(deviceNo) || !deviceNo.chars().allMatch(Character::isDigit)) {
+ return R.error("璁惧缂栧彿閿欒");
+ }
+ Path dayDir = Paths.get(loggingPath, dayClean);
+ if (!Files.exists(dayDir) || !Files.isDirectory(dayDir)) {
+ return R.error("褰撴棩鐩綍涓嶅瓨鍦�");
+ }
+ List<Path> files = Files.list(dayDir)
+ .filter(p -> {
+ String name = p.getFileName().toString();
+ String prefix = type + "_" + deviceNo + "_" + dayClean + "_";
+ return name.endsWith(".log") && name.startsWith(prefix);
+ }).collect(Collectors.toList());
+ String prefix = type + "_" + deviceNo + "_" + dayClean + "_";
+ files.sort(Comparator.comparingInt(p -> {
+ String n = p.getFileName().toString();
+ try {
+ String suf = n.substring(prefix.length(), n.length() - 4);
+ return Integer.parseInt(suf);
+ } catch (Exception e) {
+ return Integer.MAX_VALUE;
+ }
+ }));
+ int from = offset == null || offset < 0 ? 0 : offset;
+ int max = limit == null || limit <= 0 ? 200 : limit;
+ int to = Math.min(files.size(), from + max);
+ if (from >= files.size()) {
+ return R.error("璧峰搴忓彿瓒呭嚭鑼冨洿");
+ }
+ files = files.subList(from, to);
+ String id = UUID.randomUUID().toString();
+ ProgressInfo info = new ProgressInfo();
+ info.totalCount = files.size();
+ long sum = 0L;
+ for (Path f : files) {
+ try { sum += Files.size(f); } catch (Exception ignored) {}
+ }
+ info.totalRaw = sum;
+ info.processedRaw = 0L;
+ info.processedCount = 0;
+ info.finished = false;
+ DOWNLOAD_PROGRESS.put(id, info);
+ Map<String, Object> res = new HashMap<>();
+ res.put("progressId", id);
+ res.put("totalSize", info.totalRaw);
+ res.put("fileCount", info.totalCount);
+ return R.ok(res);
+ } catch (Exception e) {
+ return R.error("鍒濆鍖栧け璐�");
+ }
+ }
+
+ @RequestMapping(value = "/deviceLog/download/progress/auth")
+ @ManagerAuth
+ public R progress(String id) {
+ ProgressInfo info = DOWNLOAD_PROGRESS.get(id);
+ if (info == null) {
+ return R.error("鏃犳晥杩涘害");
+ }
+ long total = info.totalRaw;
+ long done = info.processedRaw;
+ int percent;
+ if (info.finished) {
+ percent = 100;
+ } else if (total > 0) {
+ percent = (int) Math.min(99, (done * 100L) / total);
+ } else if (info.totalCount > 0) {
+ percent = (int) Math.min(99, (info.processedCount * 100L) / info.totalCount);
+ } else {
+ percent = 0;
+ }
+ Map<String, Object> res = new HashMap<>();
+ res.put("percent", percent);
+ res.put("processedSize", done);
+ res.put("totalSize", total);
+ res.put("processedCount", info.processedCount);
+ res.put("totalCount", info.totalCount);
+ res.put("finished", info.finished);
+ return R.ok(res);
+ }
+}
--
Gitblit v1.9.1