From b2da7d9b244c5fb2de88803512f9350b21047721 Mon Sep 17 00:00:00 2001
From: zwl <1051256694@qq.com>
Date: 星期四, 09 四月 2026 13:42:50 +0800
Subject: [PATCH] 数字孪生

---
 src/main/resources/mapper/ViewDigitalTwinMapper.xml                 |  105 +++
 src/main/java/com/zy/asrs/entity/digitaltwin/AllLocationsVo.java    |   36 +
 src/main/java/com/zy/asrs/entity/digitaltwin/DtLocVo.java           |   15 
 src/main/java/com/zy/asrs/entity/LocCount.java                      |   41 +
 src/main/java/com/zy/asrs/controller/DigitalTwinController.java     |  967 ++++++++++++++++++++++++++++
 src/main/java/com/zy/asrs/entity/digitaltwin/DtDetainMatVo.java     |   27 
 src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentDocVo.java  |   36 +
 src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentVo.java     |   35 +
 src/main/java/com/zy/asrs/entity/digitaltwin/LocPicDto.java         |   13 
 src/main/java/com/zy/asrs/service/DigitalTwinService.java           |   83 ++
 src/main/java/com/zy/asrs/entity/digitaltwin/DtLocDetailVo.java     |   30 
 src/main/java/com/zy/asrs/mapper/LocCountMapper.java                |   24 
 src/main/java/com/zy/asrs/entity/digitaltwin/DtInAndOutBoundVo.java |   17 
 src/main/java/com/zy/asrs/entity/digitaltwin/DtOrderVo.java         |   19 
 src/main/resources/mapper/LocCountMapper.xml                        |   50 +
 src/main/java/com/zy/asrs/entity/digitaltwin/DtOverviewVo.java      |   24 
 src/main/java/com/zy/asrs/service/impl/DigitalTwinServiceImpl.java  |  482 ++++++++++++++
 src/main/resources/application.yml                                  |    5 
 src/main/java/com/zy/asrs/mapper/DigitalTwinMapper.java             |   27 
 19 files changed, 2,036 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/zy/asrs/controller/DigitalTwinController.java b/src/main/java/com/zy/asrs/controller/DigitalTwinController.java
new file mode 100644
index 0000000..caa5b2f
--- /dev/null
+++ b/src/main/java/com/zy/asrs/controller/DigitalTwinController.java
@@ -0,0 +1,967 @@
+package com.zy.asrs.controller;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.core.common.R;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.zy.asrs.entity.LocChartPie;
+import com.zy.asrs.entity.LocDetl;
+import com.zy.asrs.entity.LocMast;
+import com.zy.asrs.entity.digitaltwin.*;
+import com.zy.asrs.mapper.LocDetlMapper;
+import com.zy.asrs.mapper.ReportQueryMapper;
+import com.zy.asrs.service.DigitalTwinService;
+import com.zy.common.utils.HttpHandler;
+import com.zy.common.web.BaseController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import com.fasterxml.jackson.core.type.TypeReference;
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RequestMapping("/digitalTwin")
+@RestController
+public class DigitalTwinController extends BaseController {
+
+    @Value("${digitalTwins.jgUrl}")
+    private String JG_URL;
+
+    @Value("${digitalTwins.djUrl}")
+    private String DJ_URL;
+
+    @Value("${digitalTwins.ljqUrl}")
+    private String LJQ_URL;
+
+    @Resource
+    private DigitalTwinService digitalTwinService;
+    @Autowired
+    ReportQueryMapper reportQueryMapper;
+    @Autowired
+    private LocDetlMapper locDetlMapper;
+
+    /**
+     * 鏁版嵁鎬昏
+     *
+     * @param areaId    搴撳尯缂栫爜
+     * @return
+     */
+    @RequestMapping(value = "/overview")
+//    @ManagerAuth
+    public R overview(@RequestParam(required = false) String areaId) throws IOException {
+
+        Map<String, Object> map = new HashMap<>();
+        if (areaId != null) {
+            map.put("areaId", areaId);
+        }
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/overview")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null) {
+            switch (areaId) {
+                case "A": {
+                    String resA = builder.setUri(JG_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    Map<String, Object> data = (Map<String, Object>) result.get("data");
+                    return R.ok(data);
+                }
+                case "B": {
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resB, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    Map<String, Object> data = (Map<String, Object>) result.get("data");
+                    return R.ok(data);
+                }
+                case "C": {
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resC, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    Map<String, Object> data = (Map<String, Object>) result.get("data");
+                    return R.ok(data);
+                }
+                case "D": {
+                    return R.ok(digitalTwinService.overview(areaId));
+                }
+                default:
+                    Map<String, Object> mergedResult = new HashMap<>();
+                    Map<String, Object> mergedData = new HashMap<>();
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                    if (resultA.get("data") != null) {
+                        mergedData.put("A", resultA.get("data"));
+                    }
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                    if (resultB.get("data") != null) {
+                        mergedData.put("B", resultB.get("data"));
+                    }
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+                    Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                    if (resultC.get("data") != null) {
+                        mergedData.put("C", resultC.get("data"));
+                    }
+
+                    Object resultD = digitalTwinService.overview(areaId);
+                    if (resultD != null) {
+                        mergedData.put("D", resultD);
+                    }
+
+                    return R.ok(mergedData);
+            }
+        } else {
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.overview(areaId);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+
+    /**
+     * 杩戞湡璁㈠崟锛堥粯璁�7澶╋級
+     *
+     * @param areaId    搴撳尯缂栫爜
+     * @param startDate 鏍煎紡锛歽yyyMMdd锛�20251022
+     * @param endDate   鏍煎紡锛歽yyyMMdd锛�20251027
+     * @return
+     */
+    @RequestMapping(value = "/recentOrder")
+//    @ManagerAuth
+    public R recentOrder(@RequestParam(required = false) String areaId,
+                         @RequestParam(required = false) String startDate,
+                         @RequestParam(required = false) String endDate) throws IOException {
+
+        Map<String, Object> map = new HashMap<>();
+        if (areaId != null) {
+            map.put("areaId", areaId);
+        }
+        if (startDate != null) {
+            map.put("startDate", startDate);
+        }
+        if (endDate != null) {
+            map.put("endDate", endDate);
+        }
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/recentOrder")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null) {
+            switch (areaId) {
+                case "A": {
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "B": {
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resB, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "C": {
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resC, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "D": {
+                    return R.ok(digitalTwinService.order(startDate, endDate));
+                }
+                default:
+                    Map<String, Object> mergedResult = new HashMap<>();
+                    Map<String, Object> mergedData = new HashMap<>();
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                    if (resultA.get("data") != null) {
+                        mergedData.put("A", resultA.get("data"));
+                    }
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                    if (resultB.get("data") != null) {
+                        mergedData.put("B", resultB.get("data"));
+                    }
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+                    Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                    if (resultC.get("data") != null) {
+                        mergedData.put("C", resultC.get("data"));
+                    }
+
+                    Object resultD = digitalTwinService.order(startDate, endDate);
+                    if (resultD != null) {
+                        mergedData.put("D", resultD);
+                    }
+
+                    return R.ok(mergedData);
+            }
+        } else {
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.order(startDate, endDate);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+
+    /**
+     * 杩戞湡鍓╀綑搴撲綅锛堥粯璁�7澶╋級
+     *
+     * @param areaId    搴撳尯缂栫爜
+     * @param startDate 鏍煎紡锛歽yyyMMdd锛�20251022
+     * @param endDate   鏍煎紡锛歽yyyMMdd锛�20251027
+     * @return
+     */
+    @RequestMapping(value = "/recentIdleLoc")
+//    @ManagerAuth
+    public R recentIdleLoc(@RequestParam(required = false) String areaId,
+                           @RequestParam(required = false) String startDate,
+                           @RequestParam(required = false) String endDate) throws IOException {
+
+        Map<String, Object> map = new HashMap<>();
+        if (areaId != null) {
+            map.put("areaId", areaId);
+        }
+        if (startDate != null) {
+            map.put("startDate", startDate);
+        }
+        if (endDate != null) {
+            map.put("endDate", endDate);
+        }
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/recentIdleLoc")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null) {
+            switch (areaId) {
+                case "A": {
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "B": {
+
+                    String resA = builder.setUri(DJ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "C": {
+
+                    String resA = builder.setUri(LJQ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "D": {
+                    return R.ok(digitalTwinService.recentLoc(areaId, startDate, endDate));
+                }
+                default:
+                    Map<String, Object> mergedResult = new HashMap<>();
+                    Map<String, Object> mergedData = new HashMap<>();
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                    if (resultA.get("data") != null) {
+                        mergedData.put("A", resultA.get("data"));
+                    }
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                    if (resultB.get("data") != null) {
+                        mergedData.put("B", resultB.get("data"));
+                    }
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+                    Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                    if (resultC.get("data") != null) {
+                        mergedData.put("C", resultC.get("data"));
+                    }
+
+                    Object resultD = digitalTwinService.recentLoc(areaId, startDate, endDate);
+                    if (resultD != null) {
+                        mergedData.put("D", resultD);
+                    }
+
+                    return R.ok(mergedData);
+            }
+        } else {
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.recentLoc(areaId, startDate, endDate);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+
+    /**
+     * 杩戞湡鍑哄叆搴擄紙榛樿7澶╋級
+     *
+     * @param areaId    搴撳尯缂栫爜
+     * @param startDate 鏍煎紡锛歽yyyMMdd锛�20251022
+     * @param endDate   鏍煎紡锛歽yyyMMdd锛�20251027
+     * @return
+     */
+    @RequestMapping(value = "/recentInAndOutBound")
+//    @ManagerAuth
+    public R recentInAndOutBound(@RequestParam(required = false) String areaId,
+                                 @RequestParam(required = false) String startDate,
+                                 @RequestParam(required = false) String endDate) throws ParseException, IOException {
+
+        Map<String, Object> map = new HashMap<>();
+        if (areaId != null) {
+            map.put("areaId", areaId);
+        }
+        if (startDate != null) {
+            map.put("startDate", startDate);
+        }
+        if (endDate != null) {
+            map.put("endDate", endDate);
+        }
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/recentInAndOutBound")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null) {
+            switch (areaId) {
+                case "A": {
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "B": {
+
+                    String resA = builder.setUri(DJ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "C": {
+
+                    String resA = builder.setUri(LJQ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "D": {
+                    return R.ok(digitalTwinService.inAndOutBound(areaId, startDate, endDate));
+                }
+                default:
+                    Map<String, Object> mergedResult = new HashMap<>();
+                    Map<String, Object> mergedData = new HashMap<>();
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                    if (resultA.get("data") != null) {
+                        mergedData.put("A", resultA.get("data"));
+                    }
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                    if (resultB.get("data") != null) {
+                        mergedData.put("B", resultB.get("data"));
+                    }
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+                    Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                    if (resultC.get("data") != null) {
+                        mergedData.put("C", resultC.get("data"));
+                    }
+
+                    Object resultD = digitalTwinService.inAndOutBound(areaId, startDate, endDate);
+                    if (resultD != null) {
+                        mergedData.put("D", resultD);
+                    }
+
+                    return R.ok(mergedData);
+            }
+        } else {
+            // 濡傛灉娌℃湁鎻愪緵areaId锛岄粯璁よ皟鐢ㄦ湰鍦版湇鍔�
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.inAndOutBound(areaId, startDate, endDate);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+
+    /**
+     * 杩戞湡鍛嗘粸鍝侊紙榛樿瓒�30澶╋級
+     *
+     * @param areaId    搴撳尯缂栫爜
+     * @param overDayNum 鍛嗘粸鍝佸ぉ鏁帮紝榛樿30澶�
+     * @return
+     */
+    @RequestMapping(value = "/recentDetainMat")
+//    @ManagerAuth
+    public R recentDetainMat(@RequestParam(required = false) String areaId,
+                             @RequestParam(required = false) Integer overDayNum,
+                             @RequestParam(required = false) Integer pageIndex,
+                             @RequestParam(required = false) Integer pageSize,
+                             @RequestParam(required = false) String condition) throws IOException {
+
+        Map<String, Object> map = new HashMap<>();
+        if (areaId != null) {
+            map.put("areaId", areaId);
+        }
+        if (overDayNum != null) {
+            map.put("overDayNum", overDayNum);
+        }
+        if (pageIndex != null) {
+            map.put("pageIndex", pageIndex);
+        }
+        if (pageSize != null) {
+            map.put("pageSize", pageSize);
+        }
+        if (condition != null) {
+            map.put("condition", condition);
+        }
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/recentDetainMat")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null) {
+            switch (areaId) {
+                case "A": {
+                    String resA = builder.setUri(JG_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "B": {
+                    String resA = builder.setUri(DJ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "C": {
+                    String resA = builder.setUri(LJQ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                    // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                    List data = (List) result.get("data");
+                    return R.ok(data);
+                }
+                case "D": {
+                    return R.ok(digitalTwinService.recentDetainMat(areaId, overDayNum, pageIndex, pageSize, condition));
+                }
+                default:
+                    Map<String, Object> mergedResult = new HashMap<>();
+                    Map<String, Object> mergedData = new HashMap<>();
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                    if (resultA.get("data") != null) {
+                        mergedData.put("A", resultA.get("data"));
+                    }
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                    if (resultB.get("data") != null) {
+                        mergedData.put("B", resultB.get("data"));
+                    }
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+                    Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                    if (resultC.get("data") != null) {
+                        mergedData.put("C", resultC.get("data"));
+                    }
+
+                    Object resultD = digitalTwinService.recentDetainMat(areaId, overDayNum, pageIndex, pageSize, condition);
+                    if (resultD != null) {
+                        mergedData.put("D", resultD);
+                    }
+
+                    return R.ok(mergedData);
+            }
+        } else {
+            // 濡傛灉娌℃湁鎻愪緵areaId锛岄粯璁よ皟鐢ㄦ湰鍦版湇鍔�
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.recentDetainMat(areaId, overDayNum, pageIndex, pageSize, condition);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+
+    /**
+     * 璁惧杩愯淇℃伅
+     *
+     * @param areaId
+     * @return
+     */
+    @RequestMapping(value = "/equipment")
+//    @ManagerAuth
+    public R equipment(@RequestParam(required = false) String areaId) throws IOException {
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("areaId", areaId);
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/equipment")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null){
+            switch (areaId) {
+                case "A": {
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+                    return R.ok(result.get("data"));
+                }
+                case "B": {
+                    String resA = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+                    return R.ok(result.get("data"));
+                }
+                case "C": {
+                    String resA = builder.setUri(LJQ_URL).build().doGet();
+
+                    Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+                    return R.ok(result.get("data"));
+                }
+                case "D": {
+                    return R.ok(digitalTwinService.equipment(areaId));
+                }
+                default:
+                    Map<String, Object> mergedResult = new HashMap<>();
+                    Map<String, Object> mergedData = new HashMap<>();
+
+                    String resA = builder.setUri(JG_URL).build().doGet();
+                    Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                    if (resultA.get("data") != null) {
+                        mergedData.put("A", resultA.get("data"));
+                    }
+
+                    String resB = builder.setUri(DJ_URL).build().doGet();
+                    Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                    if (resultB.get("data") != null) {
+                        mergedData.put("B", resultB.get("data"));
+                    }
+
+                    String resC = builder.setUri(LJQ_URL).build().doGet();
+                    Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                    if (resultC.get("data") != null) {
+                        mergedData.put("C", resultC.get("data"));
+                    }
+
+                    Object resultD = digitalTwinService.equipment(areaId);
+                    if (resultD != null) {
+                        mergedData.put("D", resultD);
+                    }
+
+                    return R.ok(mergedData);
+            }
+        }else {
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.equipment(areaId);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+
+    /**
+     * 搴撲綅鍜屽簱瀛樿鎯�
+     *
+     * @param areaId
+     * @return
+     */
+    @RequestMapping(value = "/warehouseDetail")
+//    @ManagerAuth
+    public R warehouseDetail(@RequestParam(required = false) String areaId) throws IOException {
+        Map<String, Object> map = new HashMap<>();
+        if (areaId != null) {
+            map.put("areaId", areaId);
+        }
+
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/warehouseDetail")
+                .setParams(map);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        if (areaId != null) {
+            switch (areaId) {
+            case "A": {
+
+                String resA = builder.setUri(JG_URL).build().doGet();
+
+                Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                List data = (List) result.get("data");
+                return R.ok(data);
+            }
+            case "B": {
+                builder.setPath("/digitalTwin/warehouseDetail");
+                String resA = builder.setUri(DJ_URL).build().doGet();
+
+                Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                List data = (List) result.get("data");
+                return R.ok(data);
+            }
+            case "C": {
+
+                String resA = builder.setUri(LJQ_URL).build().doGet();
+
+                Map<String, Object> result = objectMapper.readValue(resA, Map.class);
+
+                // 濡傛灉鍙渶瑕乨ata閮ㄥ垎
+                List data = (List) result.get("data");
+                return R.ok(data);
+            }
+            case "D": {
+                return R.ok(digitalTwinService.warehouseDetail(areaId));
+            }
+            default:
+                Map<String, Object> mergedResult = new HashMap<>();
+                Map<String, Object> mergedData = new HashMap<>();
+
+                String resA = builder.setUri(JG_URL).build().doGet();
+                Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+                if (resultA.get("data") != null) {
+                    mergedData.put("A", resultA.get("data"));
+                }
+
+                String resB = builder.setUri(DJ_URL).build().doGet();
+                Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+                if (resultB.get("data") != null) {
+                    mergedData.put("B", resultB.get("data"));
+                }
+
+                String resC = builder.setUri(LJQ_URL).build().doGet();
+                Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+                if (resultC.get("data") != null) {
+                    mergedData.put("C", resultC.get("data"));
+                }
+
+                Object resultD = digitalTwinService.warehouseDetail(areaId);
+                if (resultD != null) {
+                    mergedData.put("D", resultD);
+                }
+
+                return R.ok(mergedData);
+        }
+        } else {
+            // 濡傛灉娌℃湁鎻愪緵areaId锛岄粯璁よ皟鐢ㄦ湰鍦版湇鍔�
+            Map<String, Object> mergedResult = new HashMap<>();
+            Map<String, Object> mergedData = new HashMap<>();
+
+            String resA = builder.setUri(JG_URL).build().doGet();
+            Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+            if (resultA.get("data") != null) {
+                mergedData.put("A", resultA.get("data"));
+            }
+
+            String resB = builder.setUri(DJ_URL).build().doGet();
+            Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+            if (resultB.get("data") != null) {
+                mergedData.put("B", resultB.get("data"));
+            }
+
+            String resC = builder.setUri(LJQ_URL).build().doGet();
+            Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+            if (resultC.get("data") != null) {
+                mergedData.put("C", resultC.get("data"));
+            }
+
+            Object resultD = digitalTwinService.warehouseDetail(areaId);
+            if (resultD != null) {
+                mergedData.put("D", resultD);
+            }
+
+            return R.ok(mergedData);
+        }
+    }
+    /**
+     * 鏌ヨ鎵�鏈夊簱浣嶇姸鎬佸拰鐗╂枡-浜屾満搴婁俊鎭寲鏁板瓧瀛敓鐢�
+     */
+    @RequestMapping(value = "/getAllLocations")
+    public R getAllLocations() throws IOException {
+        Map<String, Object> mergedData = new HashMap<>();
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/getAllLocations");
+        ObjectMapper objectMapper = new ObjectMapper();
+        String resA = builder.setUri(JG_URL).build().doGet();
+        Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+        if (resultA.get("data") != null) {
+            mergedData.put("A", resultA.get("data"));
+        }
+
+        String resB = builder.setUri(DJ_URL).build().doGet();
+        Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+        if (resultB.get("data") != null) {
+            mergedData.put("B", resultB.get("data"));
+        }
+
+        String resC = builder.setUri(LJQ_URL).build().doGet();
+        Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+        if (resultC.get("data") != null) {
+            mergedData.put("C", resultC.get("data"));
+        }
+
+        mergedData.put("D",digitalTwinService.getAllLocations());
+
+        return R.ok(mergedData);
+    }
+    /**
+     * 鏌ヨ鎵�鏈夊簱鐨勫簱浣嶇姸鎬佹�绘暟閲�
+     */
+    @RequestMapping(value = "/getLocalInfo")
+    public R getLocalInfo() throws IOException {
+        Map<String, Object> mergedData = new HashMap<>();
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/getLocalInfo");
+        ObjectMapper objectMapper = new ObjectMapper();
+
+        String resA = builder.setUri(JG_URL).build().doGet();
+        Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+        mergedData.put("A", resultA);
+
+        String resB = builder.setUri(DJ_URL).build().doGet();
+        Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+        mergedData.put("B", resultB);
+
+        String resC = builder.setUri(LJQ_URL).build().doGet();
+        Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+        mergedData.put("C", resultC);
+
+        Map<String, Object> locInfo = digitalTwinService.getLocInfo();
+        mergedData.put("D", locInfo);
+
+        return R.ok(mergedData);
+    }
+    /**
+     * 鏌ヨ鎵�鏈夊簱鐨勫簱瀛樻槑缁�
+     */
+    @RequestMapping(value = "/getLocalDetal")
+    public R getLocalDetal() throws IOException {
+        Map<String, Object> mergedData = new HashMap<>();
+        HttpHandler.Builder builder = new HttpHandler.Builder()
+                .setPath("/digitalTwin/getLocalDetal");
+        ObjectMapper objectMapper = new ObjectMapper();
+
+        String resA = builder.setUri(JG_URL).build().doGet();
+        Map<String, Object> resultA = objectMapper.readValue(resA, Map.class);
+        if (resultA.get("data") != null) {
+            mergedData.put("A", resultA.get("data"));
+        }
+
+        String resB = builder.setUri(DJ_URL).build().doGet();
+        Map<String, Object> resultB = objectMapper.readValue(resB, Map.class);
+        if (resultB.get("data") != null) {
+            mergedData.put("B", resultB.get("data"));
+        }
+
+        String resC = builder.setUri(LJQ_URL).build().doGet();
+        Map<String, Object> resultC = objectMapper.readValue(resC, Map.class);
+        if (resultC.get("data") != null) {
+            mergedData.put("C", resultC.get("data"));
+        }
+
+        List<Map<String, Object>> detalList = digitalTwinService.getLocalDetal();
+        mergedData.put("D", detalList);
+
+        return R.ok(mergedData);
+    }
+
+}
diff --git a/src/main/java/com/zy/asrs/entity/LocCount.java b/src/main/java/com/zy/asrs/entity/LocCount.java
new file mode 100644
index 0000000..905c944
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/LocCount.java
@@ -0,0 +1,41 @@
+package com.zy.asrs.entity;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@TableName("asr_loc_count")
+public class LocCount {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鏃ユ湡
+     */
+    @ApiModelProperty(value= "鏃ユ湡锛屾牸寮忥細20250101")
+    @TableField("date")
+    private Integer date;
+
+    /**
+     * 搴撳尯鍙�
+     */
+    @ApiModelProperty(value= "搴撳尯鍙�")
+    @TableField("area_id")
+    private String areaId;
+
+    /**
+     * 搴撲綅鏁伴噺
+     */
+    @ApiModelProperty(value= "搴撲綅鏁伴噺")
+    @TableField("loc_num")
+    private Integer locNum;
+
+    /**
+     * 鍓╀綑搴撲綅鏁伴噺
+     */
+    @ApiModelProperty(value= "鍓╀綑搴撲綅鏁伴噺")
+    @TableField("remain_num")
+    private Integer remainNum;
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/AllLocationsVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/AllLocationsVo.java
new file mode 100644
index 0000000..3f7c2bc
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/AllLocationsVo.java
@@ -0,0 +1,36 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author pang.jiabao
+ * @description 鏌ヨ鎵�鏈夊簱浣嶇姸鎬佸拰鐗╂枡-浜屾満搴婁俊鎭寲鏁板瓧瀛敓鐢�
+ * @createDate 2026/1/26 11:13
+ */
+@Data
+public class AllLocationsVo {
+
+    // 搴撲綅鍙�
+    private String locNo;
+
+    // 搴撲綅鐘舵�侊紝O绌哄簱浣嶏紙鑻辨枃涓嶆槸鏁板瓧锛夛紱F 鍦ㄥ簱锛汥 绌烘澘锛汸 鍑哄簱涓紱R 鍑哄簱棰勭害锛汼 鍏ュ簱棰勭害锛涘叾浠� 鍏朵粬锛�
+    private String locSts;
+
+    private List<LocDetl> locDetls  = new ArrayList<>();
+
+    @Data
+    public static class LocDetl {
+
+        @ApiModelProperty(value = "鍟嗗搧缂栧彿")
+        private String matnr;
+
+        @ApiModelProperty(value = "鍟嗗搧鍚嶇О")
+        private String maktx;
+
+        private Double anfme;
+    }
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtDetainMatVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtDetainMatVo.java
new file mode 100644
index 0000000..7890539
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtDetainMatVo.java
@@ -0,0 +1,27 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.Builder;
+import lombok.Data;
+
+// 鏁板瓧瀛敓锛氬憜婊炲搧淇℃伅
+@Data
+public class DtDetainMatVo {
+
+    // 褰掑睘搴撳尯ID
+    private String belongAreaId;
+    // 褰掑睘搴撳尯鍚嶇О
+    private String belongAreaName;
+    // 鐗╂枡ID
+    private String matId;
+    // 鐗╂枡鍚嶇О
+    private String matName;
+    // 鎵�灞炲簱浣岻D
+    private String lokId;
+    // 鎵�灞炲簱浣嶅悕绉�
+    private String lokName;
+    // 鍛嗘粸鏃堕棿锛岃绠楀崟浣嶏細鍒嗛挓
+    private Integer detainTime;
+    // 鍏ュ簱鏃堕棿锛屾牸寮忥細2025-10-11T11:15:16锛岄鐣�
+    private String inBoundTime;
+
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentDocVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentDocVo.java
new file mode 100644
index 0000000..7fb6e94
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentDocVo.java
@@ -0,0 +1,36 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+// 鏁板瓧瀛敓锛氳澶囩洃鎺э紙瀵规帴鏂囨。锛�
+@Data
+public class DtEquipmentDocVo {
+
+    // 璁惧绫诲瀷锛�1 鍫嗗灈鏈猴紱2 杈撻�佺嚎
+    private Integer equipmentType;
+    // 鍫嗗灈鏈哄彿
+    private Integer crnNo;
+    // 浠诲姟鍙�
+    private String taskNo;
+    // 鍒�
+    private Integer bay1;
+    // 灞�
+    @JsonProperty("Lev1")
+    private Integer lev1;
+    // 鍨傜洿閫熷害锛屽崟浣嶏細M/min
+    private Integer verticalSpeed;
+    // 姘村钩閫熷害锛屽崟浣嶏細M/min
+    private Integer horizontalSpeed;
+    // 鐢靛帇锛屽崟浣嶏細v
+    private Integer voltage;
+    // 璁惧鐘舵�侊細1 姝e父锛�2 寰呮満锛�3 鏁呴殰锛�
+    private Integer status;
+    // 鎿嶄綔鏂瑰紡锛�1 鑷姩锛�2 鍗婅嚜鍔紱3 鎵嬪姩锛�
+    private Integer operateMethod;
+    // 杈撻�佺嚎鍙�
+    private Integer devpNo;
+    // 鏈夌墿
+    @JsonProperty("Loading")
+    private String loading;
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentVo.java
new file mode 100644
index 0000000..ca04694
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtEquipmentVo.java
@@ -0,0 +1,35 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class DtEquipmentVo {
+
+    // 璁惧ID
+    private String equipmentId;
+    // 璁惧鍚嶇О
+    private String equipmentName;
+    // 璁惧绫诲瀷锛�1 鍫嗗灈鏈猴紱2 CTU锛�3 AGV锛�
+    private Integer equipmentType;
+    // 鎵�灞炲簱ID
+    private String belongAreaId;
+    // 鎵�灞炲簱鍚�
+    private String belongAreaName;
+    // 鍨傜洿閫熷害锛屽崟浣嶏細M/min
+    private Integer verticalSpeed;
+    // 姘村钩閫熷害锛屽崟浣嶏細M/min
+    private Integer horizontalSpeed;
+    // 鐢靛帇锛屽崟浣嶏細v
+    private Integer voltage;
+    // 璁惧鐘舵�侊細1 姝e父锛�2 寰呮満锛�3 鏁呴殰锛�
+    private Integer status;
+    // 鎿嶄綔鏂瑰紡锛�1 鑷姩锛�2 鍗婅嚜鍔紱3 鎵嬪姩锛�
+    private Integer operateMethod;
+
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtInAndOutBoundVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtInAndOutBoundVo.java
new file mode 100644
index 0000000..e983dbe
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtInAndOutBoundVo.java
@@ -0,0 +1,17 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.Builder;
+import lombok.Data;
+
+// 鏁板瓧瀛敓锛氭寜澶╁嚭鍏ュ簱鏁伴噺
+@Data
+@Builder
+public class DtInAndOutBoundVo {
+
+    // 鏃ユ湡
+    private String boundDate;
+    // 鍏ュ簱鏁伴噺
+    private Integer inBoundNum;
+    // 鍑哄簱鏁伴噺
+    private Integer outBoundNum;
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtLocDetailVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtLocDetailVo.java
new file mode 100644
index 0000000..1c64747
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtLocDetailVo.java
@@ -0,0 +1,30 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import com.zy.asrs.entity.LocDetl;
+import com.zy.asrs.entity.LocMast;
+import lombok.Data;
+
+@Data
+public class DtLocDetailVo  {
+
+    // 搴撲綅鍙�
+    private String locNo;
+    // 搴撲綅鐘舵�侊紝O绌哄簱浣嶏紙鑻辨枃涓嶆槸鏁板瓧锛夛紱F 鍦ㄥ簱锛汥 绌烘澘锛汸 鍑哄簱涓紱R 鍑哄簱棰勭害锛汼 鍏ュ簱棰勭害锛涘叾浠� 鍏朵粬锛�
+    private String locSts;
+    // 搴撳尯id
+    private Long areaId;
+    // 搴撳尯鍚嶇О
+    private String areaName;
+    // 鎺�
+    private Integer row1;
+    // 鍒�
+    private Integer bay1;
+    // 灞�
+    private Integer lev1;
+
+    // 搴撲綅淇℃伅
+    private LocMast locMast;
+    // 搴撳瓨淇℃伅
+    private LocDetl locDetl;
+
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtLocVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtLocVo.java
new file mode 100644
index 0000000..cf48386
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtLocVo.java
@@ -0,0 +1,15 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.Builder;
+import lombok.Data;
+
+// 鏁板瓧瀛敓锛氭寜澶╁墿浣欏簱浣嶆暟閲�
+@Data
+@Builder
+public class DtLocVo {
+
+    // 鏃ユ湡
+    private String locDate;
+    // 搴撲綅鍓╀綑鏁伴噺
+    private Integer idleNum;
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtOrderVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtOrderVo.java
new file mode 100644
index 0000000..d3c8e47
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtOrderVo.java
@@ -0,0 +1,19 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.Date;
+
+// 鏁板瓧瀛敓锛氭寜澶╄鍗曟暟閲�
+@Data
+@Builder
+// DtOrderVo.java
+public class DtOrderVo {
+
+    private String orderDate;  // 鎴� LocalDate
+    private Integer orderNum;
+
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/DtOverviewVo.java b/src/main/java/com/zy/asrs/entity/digitaltwin/DtOverviewVo.java
new file mode 100644
index 0000000..aba1e9b
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/DtOverviewVo.java
@@ -0,0 +1,24 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.Builder;
+import lombok.Data;
+
+// 鏁板瓧瀛敓锛氭寜澶╁嚭搴撱�佸叆搴撴暟閲�
+@Data
+@Builder
+public class DtOverviewVo {
+
+    // 鎬诲簱浣�
+    private Integer totalLoc;
+    // 宸茬敤搴撲綅
+    private Integer useLoc;
+    // 鍓╀綑搴撲綅
+    private Integer idleLoc;
+    // 浠婃棩鍑哄簱
+    private Integer todayOutbound;
+    // 浠婃棩鍏ュ簱
+    private Integer todayWarehousing;
+    // 鍓╀綑搴撳瓨
+    private Integer remainingStock;
+
+}
diff --git a/src/main/java/com/zy/asrs/entity/digitaltwin/LocPicDto.java b/src/main/java/com/zy/asrs/entity/digitaltwin/LocPicDto.java
new file mode 100644
index 0000000..0281c39
--- /dev/null
+++ b/src/main/java/com/zy/asrs/entity/digitaltwin/LocPicDto.java
@@ -0,0 +1,13 @@
+package com.zy.asrs.entity.digitaltwin;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class LocPicDto {
+    private String locNo;
+
+    private List<String> pics;
+
+}
diff --git a/src/main/java/com/zy/asrs/mapper/DigitalTwinMapper.java b/src/main/java/com/zy/asrs/mapper/DigitalTwinMapper.java
new file mode 100644
index 0000000..2f56216
--- /dev/null
+++ b/src/main/java/com/zy/asrs/mapper/DigitalTwinMapper.java
@@ -0,0 +1,27 @@
+package com.zy.asrs.mapper;
+
+import com.zy.asrs.entity.digitaltwin.DtDetainMatVo;
+import com.zy.asrs.entity.digitaltwin.DtInAndOutBoundVo;
+import com.zy.asrs.entity.digitaltwin.DtOrderVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+@Mapper
+@Repository
+public interface DigitalTwinMapper {
+
+    List<Double> overview(@Param("areaId")String areaId);
+
+    List<DtOrderVo> recentOrder(@Param("startTime")Date startTime, @Param("endTime")Date endTime);
+
+    List<DtInAndOutBoundVo> recentInBound(@Param("areaId")String areaId, @Param("startTime") Date startTime, @Param("endTime")Date endTime);
+
+    List<DtInAndOutBoundVo> recentOutBound(@Param("areaId")String areaId, @Param("startTime") Date startTime, @Param("endTime")Date endTime);
+
+    List<DtDetainMatVo> recentDetainMat(@Param("areaId")String areaId, @Param("startTime")Date startTime,
+                                        @Param("pageIndex")Integer pageIndex, @Param("pageSize")Integer pageSize);
+}
diff --git a/src/main/java/com/zy/asrs/mapper/LocCountMapper.java b/src/main/java/com/zy/asrs/mapper/LocCountMapper.java
new file mode 100644
index 0000000..5456834
--- /dev/null
+++ b/src/main/java/com/zy/asrs/mapper/LocCountMapper.java
@@ -0,0 +1,24 @@
+package com.zy.asrs.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.zy.asrs.entity.LocCount;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Mapper
+@Repository
+public interface LocCountMapper extends BaseMapper<LocCount> {
+
+    List<LocCount> getByAreaAndDate(@Param("areaId")String areaId, @Param("startDate")int startDate, @Param("endDate")int endDate);
+
+    List<LocCount> getByDate(@Param("startDate")int startDate, @Param("endDate")int endDate);
+
+    Integer insertOrUpdate(@Param("model")LocCount model);
+
+    List<LocCount> totalLoc();
+
+    List<LocCount> useLoc();
+}
diff --git a/src/main/java/com/zy/asrs/service/DigitalTwinService.java b/src/main/java/com/zy/asrs/service/DigitalTwinService.java
new file mode 100644
index 0000000..15a9849
--- /dev/null
+++ b/src/main/java/com/zy/asrs/service/DigitalTwinService.java
@@ -0,0 +1,83 @@
+package com.zy.asrs.service;
+
+import com.zy.asrs.entity.digitaltwin.*;
+
+import java.util.List;
+import java.util.Map;
+
+public interface DigitalTwinService {
+
+    /**
+     * 鎬昏锛氭�诲簱浣嶃�佸凡鐢ㄥ簱浣嶃�佸墿浣欏簱浣嶃�佷粖鏃ュ嚭搴撱�佷粖鏃ュ叆搴撱�佸墿浣欏簱浣�
+     *
+     * @param areaId
+     * @return
+     */
+    DtOverviewVo overview(String areaId);
+
+    /**
+     * 杩戞湡璁㈠崟锛岄粯璁�7澶�
+     *
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    List<DtOrderVo> order(String startDate, String endDate);
+
+    /**
+     * 杩戞湡鍑哄簱銆佸叆搴撴暟閲忥紝榛樿7澶�
+     *
+     * @param areaId
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    List<DtInAndOutBoundVo> inAndOutBound(String areaId, String startDate, String endDate);
+
+    /**
+     * 杩戞湡杩戞湡鍛嗘粸鍝佷俊鎭紝榛樿瓒呰繃30澶╀负鍛嗘粸鍝�
+     *
+     * @param areaId
+     * @param overDayNum
+     * @param pageIndex
+     * @param pageSize
+     * @param condition 鎼滅储鏉′欢
+     * @return
+     */
+    List<DtDetainMatVo> recentDetainMat(String areaId, Integer overDayNum, Integer pageIndex, Integer pageSize, String condition);
+
+    /**
+     * 鏌ヨ搴撳瓨鍜屽簱浣嶈缁嗕俊鎭�
+     *
+     * @param areaId
+     * @return
+     */
+    List<DtLocDetailVo> warehouseDetail(String areaId);
+
+    /**
+     * 杩戞湡鍓╀綑搴撲綅鏁伴噺锛岄粯璁�7澶�
+     *
+     * @param areaId
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    List<DtLocVo> recentLoc(String areaId, String startDate, String endDate);
+
+    /**
+     * 瀹氭湡缁熻鍓╀綑搴撳瓨
+     *
+     */
+    void locNumCount();
+
+    List<DtEquipmentDocVo> equipment(String areaId);
+
+    /**
+     * 鏌ヨ鎵�鏈夊簱浣嶇姸鎬佸拰鐗╂枡-浜屾満搴婁俊鎭寲鏁板瓧瀛敓鐢�
+     */
+    List<AllLocationsVo> getAllLocations();
+
+    List<Map<String, Object>> getLocalDetal();
+
+    Map<String, Object> getLocInfo();
+}
diff --git a/src/main/java/com/zy/asrs/service/impl/DigitalTwinServiceImpl.java b/src/main/java/com/zy/asrs/service/impl/DigitalTwinServiceImpl.java
new file mode 100644
index 0000000..6f2db40
--- /dev/null
+++ b/src/main/java/com/zy/asrs/service/impl/DigitalTwinServiceImpl.java
@@ -0,0 +1,482 @@
+package com.zy.asrs.service.impl;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.core.common.Cools;
+import com.zy.asrs.entity.BasCrnp;
+import com.zy.asrs.entity.BasDevp;
+import com.zy.asrs.entity.LocCount;
+import com.zy.asrs.entity.LocDetl;
+import com.zy.asrs.entity.LocMast;
+import com.zy.asrs.entity.digitaltwin.*;
+import com.zy.asrs.mapper.DigitalTwinMapper;
+import com.zy.asrs.mapper.LocCountMapper;
+import com.zy.asrs.mapper.LocDetlMapper;
+import com.zy.asrs.mapper.LocMastMapper;
+import com.zy.asrs.service.BasCrnpService;
+import com.zy.asrs.service.BasDevpService;
+import com.zy.asrs.service.DigitalTwinService;
+import com.zy.asrs.service.LocDetlService;
+import com.zy.asrs.service.LocMastService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class DigitalTwinServiceImpl implements DigitalTwinService {
+
+    @Resource
+    private DigitalTwinMapper digitalTwinMapper;
+    @Resource
+    private LocCountMapper locCountMapper;
+    @Resource
+    private LocMastMapper locMastMapper;
+    @Resource
+    private LocDetlMapper locDetlMapper;
+    @Resource
+    private LocMastService locMastService;
+
+    /**
+     * 鎬昏锛氭�诲簱浣嶃�佸凡鐢ㄥ簱浣嶃�佸墿浣欏簱浣嶃�佷粖鏃ュ嚭搴撱�佷粖鏃ュ叆搴撱�佸墿浣欏簱浣�
+     *
+     * @param areaId
+     * @return
+     */
+    public DtOverviewVo overview(String areaId) {
+
+        List<Double> dbOverview = digitalTwinMapper.overview(areaId);
+        if (dbOverview != null && !dbOverview.isEmpty()){
+            DtOverviewVo dtOverviewVo = DtOverviewVo.builder()
+                .totalLoc((int)Math.round(dbOverview.get(0)))
+                    .useLoc((int)Math.round(dbOverview.get(1)))
+                    .remainingStock((int)Math.round(dbOverview.get(2)))
+                    .todayWarehousing((int)Math.round(dbOverview.get(3)))
+                    .todayOutbound((int)Math.round(dbOverview.get(4)))
+                    .build();
+            dtOverviewVo.setIdleLoc(dtOverviewVo.getTotalLoc() - dtOverviewVo.getUseLoc());
+            return dtOverviewVo;
+        }
+        return DtOverviewVo.builder().build();
+    }
+
+    /**
+     * 杩戞湡璁㈠崟锛岄粯璁�7澶�
+     *
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    public List<DtOrderVo> order(String startDate, String endDate) {
+
+        Date startTime = new Date();
+        Date endTime = new Date();
+        if (startDate == null || endDate == null || startDate.isEmpty() || endDate.isEmpty()){
+            Date now = new Date();
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(now);
+            calendar.add(Calendar.DAY_OF_MONTH, -7);
+            startTime = calendar.getTime();
+            endTime = now;
+
+        } else {
+            SimpleDateFormat sdf;
+            try {
+                // 灏濊瘯瑙f瀽yyyyMMdd鏍煎紡
+                if (startDate.length() == 8 && endDate.length() == 8) {
+                    sdf = new SimpleDateFormat("yyyyMMdd");
+                    startTime = sdf.parse(startDate);
+                    endTime = sdf.parse(endDate);
+                    // 璁剧疆缁撴潫鏃堕棿涓哄綋澶╃殑23:59:59.999
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.setTime(endTime);
+                    calendar.set(Calendar.HOUR_OF_DAY, 23);
+                    calendar.set(Calendar.MINUTE, 59);
+                    calendar.set(Calendar.SECOND, 59);
+                    calendar.set(Calendar.MILLISECOND, 999);
+                    endTime = calendar.getTime();
+                } else {
+                    // 灏濊瘯瑙f瀽yyyy-MM-dd HH:mm:ss.SSS鏍煎紡
+                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+                    startTime = sdf.parse(startDate);
+                    endTime = sdf.parse(endDate);
+                }
+            } catch (ParseException e) {
+                e.printStackTrace();
+                // 瑙f瀽澶辫触鏃朵娇鐢ㄩ粯璁ょ殑7澶╂椂闂磋寖鍥�
+                Date now = new Date();
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(now);
+                calendar.add(Calendar.DAY_OF_MONTH, -7);
+                startTime = calendar.getTime();
+                endTime = now;
+            }
+        }
+        List<DtOrderVo> dbOrder = digitalTwinMapper.recentOrder(startTime, endTime);
+        // 绌烘棩鏈熻ˉ鍏�
+        for (DtOrderVo dtOrderVo : dbOrder) {
+            dtOrderVo.setOrderDate(dtOrderVo.getOrderDate());
+        }
+
+        return dbOrder;
+    }
+
+    /**
+     * 杩戞湡鍑哄簱銆佸叆搴撴暟閲忥紝榛樿7澶�
+     *
+     * @param areaId
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    public List<DtInAndOutBoundVo> inAndOutBound(String areaId, String startDate, String endDate) {
+
+        Date startTime = new Date();
+        Date endTime = new Date();
+        if (startDate == null || endDate == null || startDate.isEmpty() || endDate.isEmpty()){
+            Date now = new Date();
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(now);
+            calendar.add(Calendar.DAY_OF_MONTH, -7);
+            startTime = calendar.getTime();
+            endTime = now;
+
+        } else {
+            SimpleDateFormat sdf;
+            try {
+                // 灏濊瘯瑙f瀽yyyyMMdd鏍煎紡
+                if (startDate.length() == 8 && endDate.length() == 8) {
+                    sdf = new SimpleDateFormat("yyyyMMdd");
+                    startTime = sdf.parse(startDate);
+                    endTime = sdf.parse(endDate);
+                    // 璁剧疆缁撴潫鏃堕棿涓哄綋澶╃殑23:59:59.999
+                    Calendar calendar = Calendar.getInstance();
+                    calendar.setTime(endTime);
+                    calendar.set(Calendar.HOUR_OF_DAY, 23);
+                    calendar.set(Calendar.MINUTE, 59);
+                    calendar.set(Calendar.SECOND, 59);
+                    calendar.set(Calendar.MILLISECOND, 999);
+                    endTime = calendar.getTime();
+                } else {
+                    // 灏濊瘯瑙f瀽yyyy-MM-dd HH:mm:ss.SSS鏍煎紡
+                    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+                    startTime = sdf.parse(startDate);
+                    endTime = sdf.parse(endDate);
+                }
+            } catch (ParseException e) {
+                e.printStackTrace();
+                // 瑙f瀽澶辫触鏃朵娇鐢ㄩ粯璁ょ殑7澶╂椂闂磋寖鍥�
+                Date now = new Date();
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(now);
+                calendar.add(Calendar.DAY_OF_MONTH, -7);
+                startTime = calendar.getTime();
+                endTime = now;
+            }
+        }
+
+        List<DtInAndOutBoundVo> dtInBoundVos = digitalTwinMapper.recentInBound(areaId, startTime, endTime);
+        List<DtInAndOutBoundVo> dtOutBoundVos = digitalTwinMapper.recentOutBound(areaId, startTime, endTime);
+
+        // 鏍煎紡鏁寸悊
+        List<DtInAndOutBoundVo> dtInAndOutBoundVos = new ArrayList<>(dtInBoundVos);
+        dtInAndOutBoundVos.addAll(dtOutBoundVos);
+
+        return dtInAndOutBoundVos;
+    }
+    /**
+     * 杩戞湡杩戞湡鍛嗘粸鍝佷俊鎭紝榛樿瓒呰繃30澶╀负鍛嗘粸鍝�
+     *
+     * @param areaId
+     * @param overDayNum
+     * @param pageIndex
+     * @param pageSize
+     * @param condition 鎼滅储鏉′欢
+     * @return
+     */
+    public List<DtDetainMatVo> recentDetainMat(String areaId, Integer overDayNum, Integer pageIndex, Integer pageSize, String condition) {
+
+        overDayNum = overDayNum == null ? 30 : overDayNum;
+        pageIndex = pageIndex == null ? 1 : pageIndex;
+        pageSize = pageSize == null ? 1000000 : pageSize;
+
+        Date now = new Date();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(now);
+        calendar.add(Calendar.DAY_OF_MONTH, -overDayNum);
+        Date start = calendar.getTime();
+    /*    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String startTime = sdf.format(start);*/
+
+        List<DtDetainMatVo> dbDetainMats = digitalTwinMapper.recentDetainMat(areaId, start, pageIndex, pageSize);
+
+        return dbDetainMats;
+    }
+
+    /**
+     * 鏌ヨ搴撳瓨鍜屽簱浣嶈缁嗕俊鎭�
+     *
+     * @param areaId
+     * @return
+     */
+    public List<DtLocDetailVo> warehouseDetail(String areaId) {
+
+        List<LocMast> locMastList = locMastService.selectList(new EntityWrapper<>());
+        return locMastList.stream()
+                .map(loc -> {
+                    DtLocDetailVo vo = new DtLocDetailVo();
+                    BeanUtils.copyProperties(loc, vo);
+                    vo.setLocMast(loc);
+                    LocDetl query = new LocDetl();
+                    query.setLocNo(loc.getLocNo());
+                    LocDetl locDetl = locDetlMapper.selectOne(query);
+                    vo.setLocDetl(locDetl);
+                    return vo;
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 杩戞湡鍓╀綑搴撲綅鏁伴噺锛岄粯璁�7澶�
+     *
+     * @param areaId
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    public List<DtLocVo> recentLoc(String areaId, String startDate, String endDate) {
+
+        List<DtLocVo> locVos = new ArrayList<>();
+
+        if (startDate == null || endDate == null || startDate.isEmpty() || endDate.isEmpty()){
+            Date now = new Date();
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(now);
+            calendar.add(Calendar.DAY_OF_MONTH, -7);
+            Date start = calendar.getTime();
+
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+            endDate = sdf.format(now);
+            startDate = sdf.format(start);
+        }
+        List<LocCount> locCounts;
+        if (areaId != null && !areaId.isEmpty()) {
+            locCounts = locCountMapper.getByAreaAndDate(areaId, Integer.parseInt(startDate), Integer.parseInt(endDate));
+        } else {
+            locCounts = locCountMapper.getByDate(Integer.parseInt(startDate), Integer.parseInt(endDate));
+        }
+
+
+        for (LocCount locCount : locCounts) {
+            String date = locCount.getDate().toString();
+            String locDate = date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8);
+            DtLocVo dtLocVo = DtLocVo.builder()
+                    .locDate(locDate)
+                    .idleNum(locCount.getRemainNum())
+                    .build();
+            locVos.add(dtLocVo);
+        }
+
+        return locVos;
+    }
+
+    /**
+     * 瀹氭湡缁熻鍓╀綑搴撳瓨
+     *
+     */
+    @Transactional
+    public void locNumCount() {
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+        String date = sdf.format(new Date());
+
+        List<LocCount> totalLoc = locCountMapper.totalLoc();
+        List<LocCount> useLoc = locCountMapper.useLoc();
+
+        LocCount locCount1 = new LocCount();
+        locCount1.setDate(Integer.valueOf(date));
+        locCount1.setLocNum(totalLoc.get(0).getLocNum());
+        locCount1.setRemainNum(locCount1.getLocNum() - useLoc.get(0).getLocNum());
+
+        locCountMapper.insertOrUpdate(locCount1);
+    }
+
+
+    @Resource
+    private BasCrnpService basCrnpService;
+    @Resource
+    private BasDevpService basDevpService;
+    @Override
+    public List<DtEquipmentDocVo> equipment(String areaId) {
+        List<DtEquipmentDocVo> equipmentVos = new ArrayList<>();
+
+        List<BasCrnp> crnps = basCrnpService.selectList(new EntityWrapper<>());
+        for (BasCrnp crnp : crnps) {
+            DtEquipmentDocVo vo = new DtEquipmentDocVo();
+            vo.setEquipmentType(1);
+            vo.setCrnNo(crnp.getCrnNo());
+            Integer wrkNo = crnp.getWrkNo();
+            vo.setTaskNo(wrkNo == null ? null : String.valueOf(wrkNo));
+            String locNo = !Cools.isEmpty(crnp.getToLocno()) ? crnp.getToLocno() : crnp.getFrmLocno();
+            if (!Cools.isEmpty(locNo)) {
+                LocMast locMast = locMastService.selectById(locNo);
+                if (locMast != null) {
+                    vo.setBay1(locMast.getBay1());
+                    vo.setLev1(locMast.getLev1());
+                }
+            }
+            vo.setVerticalSpeed(parseInteger(crnp.getCtlHp()));
+            vo.setHorizontalSpeed(parseInteger(crnp.getCtlRest()));
+            vo.setVoltage(220);
+            vo.setStatus(crnp.getCrnErr() != null && crnp.getCrnErr() == 0 ? 1 : 3);
+            vo.setOperateMethod(crnp.getCrnSts() != null && crnp.getCrnSts() == 3 ? 1 : 3);
+            equipmentVos.add(vo);
+        }
+
+        List<BasDevp> devps = basDevpService.selectList(new EntityWrapper<>());
+        for (BasDevp devp : devps) {
+            DtEquipmentDocVo vo = new DtEquipmentDocVo();
+            vo.setEquipmentType(2);
+            vo.setDevpNo(devp.getDevNo());
+            Integer wrkNo = devp.getWrkNo();
+            Integer wrkNo1 = devp.getWrkNo1();
+            Integer task = wrkNo != null ? wrkNo : wrkNo1;
+            vo.setTaskNo(task == null ? null : String.valueOf(task));
+            vo.setLoading(devp.getLoading());
+            equipmentVos.add(vo);
+        }
+
+        return equipmentVos;
+    }
+
+    private Integer parseInteger(String value) {
+        if (Cools.isEmpty(value)) {
+            return 0;
+        }
+        try {
+            return Integer.valueOf(value);
+        } catch (NumberFormatException ex) {
+            return 0;
+        }
+    }
+
+
+    // region 鏁板瓧瀛敓
+
+    // 鏁板瓧瀛敓鏁村悎
+
+    // 鏈哄櫒鐘舵�佹暣鍚�
+
+    // endregion
+
+
+
+    // region 绔嬪簱璋冨害
+
+    // 鍫嗗灈鏈哄瓨鍙�
+
+    // 杈撻�佺嚎鎷嶇収銆佺О閲�
+
+    // endregion
+    @Resource
+    private LocDetlService locDetlService;
+
+    @Override
+    public List<AllLocationsVo> getAllLocations() {
+        List<AllLocationsVo> allLocationsVos = new ArrayList<>();
+        List<LocMast> locMastList = locMastService.selectList(new EntityWrapper<>());
+        locMastList.forEach(locMast -> {
+            AllLocationsVo allLocationsVo = new AllLocationsVo();
+            allLocationsVo.setLocNo(locMast.getLocNo());
+            String locSts = locMast.getLocSts();
+            allLocationsVo.setLocSts(locSts);
+            // 鏈夊簱瀛�
+            if (locSts.equals("F") || locSts.equals("P") || locSts.equals("Q") || locSts.equals("R")) {
+                List<LocDetl> locDetls = locDetlService.selectList(new EntityWrapper<LocDetl>().eq("loc_no", locMast.getLocNo()));
+                if (!locDetls.isEmpty()) {
+                    List<AllLocationsVo.LocDetl> locDetlList = locDetls.stream().map(locDetl -> {
+                                AllLocationsVo.LocDetl locDetl1 = new AllLocationsVo.LocDetl();
+                                BeanUtils.copyProperties(locDetl, locDetl1);
+                                return locDetl1;
+                            }
+                    ).collect(Collectors.toList());
+                    allLocationsVo.setLocDetls(locDetlList);
+                }
+            }
+            allLocationsVos.add(allLocationsVo);
+        });
+        return allLocationsVos;
+    }
+
+    public List<Map<String, Object>> getLocalDetal() {
+        List<LocDetl> locDetls = locDetlMapper.selectList(new EntityWrapper<>());
+        List<Map<String, Object>> result = new ArrayList<>();
+
+        for (LocDetl locDetl : locDetls) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("zpallet", locDetl.getZpallet());
+            item.put("anfme", locDetl.getAnfme());
+            item.put("matnr", locDetl.getMatnr());
+            item.put("maktx", locDetl.getMaktx());
+            result.add(item);
+        }
+
+        return result;
+    }
+    public Map<String, Object> getLocInfo() {
+        List<LocMast> LocMasts = locMastMapper.selectList(new EntityWrapper<>());
+        Map<String, Object> result = new HashMap<>();
+
+        // 鍒濆鍖栬鏁板櫒
+        int emptyLocCount = 0;
+        int fullZpalletCount = 0;
+        int emptyZpalletCount = 0;
+        int pickOutCount = 0;
+        int pickInCount = 0;
+        int outboundCount = 0;
+        int inboundCount = 0;
+        int disableCount = 0;
+        int mergeCount = 0;
+
+        // 缁熻姣忕鐘舵�佺殑搴撲綅鏁伴噺
+        for (LocMast locMast : LocMasts) {
+            String locSts = locMast.getLocSts();
+            if (locSts.equals("O")) {
+                emptyLocCount++;
+            } else if (locSts.equals("F")) {
+                fullZpalletCount++;
+            } else if (locSts.equals("D")) {
+                emptyZpalletCount++;
+            } else if (locSts.equals("P")) {
+                pickOutCount++;
+            } else if (locSts.equals("Q")) {
+                pickInCount++;
+            } else if (locSts.equals("R")) {
+                outboundCount++;
+            } else if (locSts.equals("S")) {
+                inboundCount++;
+            } else if (locSts.equals("X")) {
+                disableCount++;
+            } else if (locSts.equals("Y")) {
+                mergeCount++;
+            }
+        }
+
+        // 灏嗙粺璁$粨鏋滄斁鍏ap涓�
+        result.put("EmptyLoc", emptyLocCount);
+        result.put("FullZpallet", fullZpalletCount);
+        result.put("EmptyZpallet", emptyZpalletCount);
+        result.put("PickOut", pickOutCount);
+        result.put("PickIn", pickInCount);
+        result.put("Outbound", outboundCount);
+        result.put("Inbound", inboundCount);
+        result.put("Disable", disableCount);
+        result.put("Merge", mergeCount);
+
+        return result;
+    }
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 9c0b543..536f1de 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -53,6 +53,11 @@
   api-key: app-mP0O6aY5WpbfaHs7BNnjVkli
   model: deepseek-ai/DeepSeek-V3.2
 
+digitalTwins:
+  jgUrl: http://172.26.11.88:8089/jgwms
+  djUrl: http://172.26.11.88:8088/djwms
+  ljqUrl: http://172.26.11.80:8083/ljqwms
+
 # 涓嬩綅鏈洪厤缃�
 wcs-slave:
   # 鍙屾繁
diff --git a/src/main/resources/mapper/LocCountMapper.xml b/src/main/resources/mapper/LocCountMapper.xml
new file mode 100644
index 0000000..85a85ef
--- /dev/null
+++ b/src/main/resources/mapper/LocCountMapper.xml
@@ -0,0 +1,50 @@
+<?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="com.zy.asrs.mapper.LocCountMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.zy.asrs.entity.LocCount">
+        <result column="date" property="date" />
+        <result column="area_id" property="areaId" />
+        <result column="loc_num" property="locNum" />
+        <result column="remain_num" property="remainNum" />
+    </resultMap>
+
+    <select id="getByAreaAndDate" resultType="com.zy.asrs.entity.LocCount">
+        SELECT * FROM asr_loc_count
+        WHERE area_id = #{areaId} AND date BETWEEN #{startDate} AND #{endDate}
+    </select>
+
+    <select id="getByDate" resultType="com.zy.asrs.entity.LocCount">
+        SELECT date, SUM(ISNULL(loc_num, 0)) AS loc_num, SUM(ISNULL(remain_num, 0)) AS remain_num
+        FROM asr_loc_count
+        WHERE date BETWEEN #{startDate} AND #{endDate}
+        GROUP BY date
+    </select>
+
+    <insert id="insertOrUpdate" parameterType="com.zy.asrs.entity.LocCount">
+        IF EXISTS (SELECT 1 FROM asr_loc_count WHERE date = #{model.date})
+            BEGIN
+                UPDATE asr_loc_count
+                SET loc_num = #{model.locNum},
+                    remain_num = #{model.remainNum}
+                WHERE date = #{model.date}
+            END
+        ELSE
+            BEGIN
+                INSERT INTO asr_loc_count(date, area_id, loc_num, remain_num)
+                VALUES (#{model.date}, #{model.areaId}, #{model.locNum}, #{model.remainNum})
+            END
+    </insert>
+
+    <select id="totalLoc" resultType="com.zy.asrs.entity.LocCount">
+        SELECT area_id, COUNT(*) AS loc_num FROM asr_loc_mast WHERE loc_sts != 'Z' GROUP BY area_id
+    </select>
+
+    <select id="useLoc" resultType="com.zy.asrs.entity.LocCount">
+        SELECT area_id, COUNT(*) AS loc_num FROM asr_loc_mast
+        WHERE loc_sts = 'F' or loc_sts = 'P' or loc_sts = 'Q' or loc_sts = 'R' or loc_sts = 'S' or loc_sts = 'X'
+        GROUP BY area_id
+    </select>
+
+</mapper>
diff --git a/src/main/resources/mapper/ViewDigitalTwinMapper.xml b/src/main/resources/mapper/ViewDigitalTwinMapper.xml
new file mode 100644
index 0000000..c02e427
--- /dev/null
+++ b/src/main/resources/mapper/ViewDigitalTwinMapper.xml
@@ -0,0 +1,105 @@
+<?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="com.zy.asrs.mapper.DigitalTwinMapper">
+
+    <resultMap id="dtOrderMap" type="com.zy.asrs.entity.digitaltwin.DtOrderVo">
+        <constructor>
+            <arg column="orderDate" javaType="java.util.Date"/>
+            <arg column="orderNum" javaType="java.lang.Integer"/>
+        </constructor>
+    </resultMap>
+
+    <!--鎬昏锛氭�诲簱浣嶃�佸凡鐢ㄥ簱浣嶃�佷粖鏃ュ簱瀛樸�佷粖鏃ュ嚭搴撱�佷粖鏃ュ叆搴�-->
+    <select id="overview" resultType="Double">
+        SELECT COUNT(*) FROM asr_loc_mast WHERE loc_sts != 'Z'
+<!--            <if test="areaId != null">-->
+<!--                and area_id = #{areaId}-->
+<!--            </if>-->
+        UNION ALL
+        SELECT COUNT(*) FROM asr_loc_mast WHERE loc_sts = 'F' or loc_sts = 'P' or loc_sts = 'Q' or loc_sts = 'R' or loc_sts = 'S' or loc_sts = 'X'
+<!--        <if test="areaId != null">-->
+<!--            and area_id = #{areaId}-->
+<!--        </if>-->
+        UNION ALL
+        SELECT ISNULL(SUM(anfme), 0) FROM asr_loc_detl
+<!--        <if test="areaId != null">-->
+<!--            WHERE area_id = #{areaId}-->
+<!--        </if>-->
+        UNION ALL
+        SELECT ISNULL(SUM(anfme), 0) FROM asr_wrkin_view WHERE CONVERT(VARCHAR, io_time, 23) = CONVERT(VARCHAR, GETDATE(), 23)
+<!--        <if test="areaId != null">-->
+<!--            and area_id = #{areaId}-->
+<!--        </if>-->
+        UNION ALL
+        SELECT ISNULL(SUM(anfme), 0) FROM asr_wrkout_view WHERE CONVERT(VARCHAR, io_time, 23) = CONVERT(VARCHAR, GETDATE(), 23)
+<!--        <if test="areaId != null">-->
+<!--            and area_id = #{areaId}-->
+<!--        </if>-->
+    </select>
+
+    <select id="recentOrder" resultType="com.zy.asrs.entity.digitaltwin.DtOrderVo">
+
+        SELECT
+        FORMAT(orderDate, 'yyyy-MM-dd') as orderDate,
+        COUNT(*) as orderNum
+        FROM (
+        SELECT
+        CAST(order_time AS DATE) as orderDate
+        FROM man_order_pakin
+        WHERE order_time BETWEEN #{startTime} AND #{endTime}
+
+        UNION ALL
+
+        SELECT
+        CAST(order_time AS DATE) as orderDate
+        FROM man_order_pakout
+        WHERE order_time BETWEEN #{startTime} AND #{endTime}
+        ) combined
+        GROUP BY orderDate
+        ORDER BY orderDate
+
+    </select>
+
+    <select id="recentInBound" resultType="com.zy.asrs.entity.digitaltwin.DtInAndOutBoundVo">
+        SELECT CONVERT(VARCHAR, io_time, 23) AS boundDate, SUM(anfme) AS inBoundNum
+        FROM asr_wrkin_view
+        WHERE io_time BETWEEN #{startTime} AND #{endTime}
+<!--        <if test="areaId != null">-->
+<!--            and area_id = #{areaId}-->
+<!--        </if>-->
+        GROUP BY CONVERT(VARCHAR, io_time, 23)
+    </select>
+
+    <select id="recentOutBound" resultType="com.zy.asrs.entity.digitaltwin.DtInAndOutBoundVo">
+        SELECT CONVERT(VARCHAR, io_time, 23) AS boundDate, SUM(anfme) AS outBoundNum
+        FROM asr_wrkout_view
+        WHERE io_time BETWEEN #{startTime} AND #{endTime}
+<!--        <if test="areaId != null">-->
+<!--            and area_id = #{areaId}-->
+<!--        </if>-->
+        GROUP BY CONVERT(VARCHAR, io_time, 23)
+    </select>
+
+    <select id="recentDetainMat" resultType="com.zy.asrs.entity.digitaltwin.DtDetainMatVo">
+        SELECT *
+        FROM (
+                 SELECT
+                     ROW_NUMBER() OVER(ORDER BY t.inBoundTime DESC) AS rownum,
+                     t.*
+                 FROM (
+                          SELECT
+                              matnr AS matId,
+                              maktx AS matName,
+                              loc_no AS lokId,
+                              '' AS lokName,
+                              DATEDIFF(MINUTE, appe_time, GETDATE()) AS detainTime,
+                              CONVERT(VARCHAR, appe_time, 126) AS inBoundTime
+                          FROM asr_loc_detl
+                          WHERE appe_time &lt;= #{startTime}
+                      ) t
+             ) a
+        WHERE a.rownum BETWEEN ((#{pageIndex}-1)*#{pageSize}+1) AND (#{pageIndex}*#{pageSize})
+    </select>
+
+</mapper>

--
Gitblit v1.9.1