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);
|
}
|
}
|