Compare commits
8 Commits
5e82c0bc03
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 474a7d0a68 | |||
| c47e2059a1 | |||
| 3b5f168b45 | |||
| e0330b604d | |||
| c9076d2db7 | |||
| 4fef962e6c | |||
| a490e7fba6 | |||
| 5f2e77de96 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ hs_err_pid*
|
|||||||
**/target/
|
**/target/
|
||||||
|
|
||||||
/log/
|
/log/
|
||||||
|
/.trae/
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
I will implement collision avoidance logic in `BaseSRgvThread.java` to handle scenarios where a path is blocked by another SRGV.
|
||||||
|
|
||||||
|
**Implementation Plan:**
|
||||||
|
1. **Modify `sendPointToPointTask` method in `BaseSRgvThread.java`**:
|
||||||
|
* Locate the block where `shortestPath` is null or empty (indicating a blocked path).
|
||||||
|
* After the existing specific logic for "Floor 1", add a generic avoidance strategy.
|
||||||
|
* **Avoidance Strategy**:
|
||||||
|
1. Query `WcsSrgvMap` for all sites with `remark="cache"` (avoidance points) on the current floor.
|
||||||
|
2. Filter out sites that are currently occupied by other SRGVs.
|
||||||
|
3. Find the nearest reachable avoidance point to the current car.
|
||||||
|
4. **Task Splitting (Yielding Logic)**:
|
||||||
|
* **Create a new "Continuation" Queue**: Clone the current task but set its `StartSite` to the avoidance point and keep the original `EndSite`. Insert this as a new pending task.
|
||||||
|
* **Update Current Queue**: Change the `EndSite` of the current blocked task to the **Avoidance Point**. This effectively converts the current task into a "Yielding" task.
|
||||||
|
5. Return `false` to allow the scheduler to pick up the modified task in the next cycle.
|
||||||
|
|
||||||
|
**Technical Details:**
|
||||||
|
* Use `wcsSrgvMapService` to fetch avoidance points.
|
||||||
|
* Use `PathFinder` to verify reachability of the avoidance point.
|
||||||
|
* Use `BeanUtil` (Hutool) or manual setters to clone the queue.
|
||||||
|
* Ensure the new logic does not interfere with the existing "Floor 1" logic (put it after or as an `else` condition).
|
||||||
|
|
||||||
|
This approach ensures that when blocked, the car moves to a safe spot (Yielding Queue) and then resumes its original journey (Continuation Queue).
|
||||||
47
.trae/documents/实现“调度阻挡车避让”的优化方案.md
Normal file
47
.trae/documents/实现“调度阻挡车避让”的优化方案.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 优化避让策略:优先调度阻挡车避让
|
||||||
|
|
||||||
|
针对您提出的 "让B小车(障碍物)避让" 的合理建议,我设计了如下优化后的调度逻辑。新逻辑将优先尝试移开挡路车,只有在无法移开时才让当前车自己避让。
|
||||||
|
|
||||||
|
## 核心逻辑流程
|
||||||
|
|
||||||
|
当小车 A (当前调度车辆) 路径规划失败时,按以下步骤处理:
|
||||||
|
|
||||||
|
1. **识别阻挡者 (Find Blocker)**
|
||||||
|
* 构建一张**纯净的静态地图** (忽略所有小车位置)。
|
||||||
|
* 在静态地图上为 A 规划一条**理想路径**。
|
||||||
|
* 沿着理想路径检查,找到第一辆占据路径的小车 **B**。
|
||||||
|
|
||||||
|
2. **判断阻挡者状态 (Check Blocker Status)**
|
||||||
|
* **如果 B 正在执行任务 (Busy)**:
|
||||||
|
* 说明 B 只是暂时路过或正在工作。
|
||||||
|
* **策略**:A 小车暂时等待 (本次不生成指令),等待 B 自行移开。
|
||||||
|
* **如果 B 空闲 (Idle)**:
|
||||||
|
* 说明 B 停在路上挡住了 A。
|
||||||
|
* **策略**:调度 B 去避让。
|
||||||
|
|
||||||
|
3. **执行避让调度 (Execute Avoidance)**
|
||||||
|
* **场景 1:调度 B 避让 (优先)**
|
||||||
|
* 为 B 寻找一个最近的**避让点** (Cache Point)。
|
||||||
|
* *关键条件*:避让点不能在 A 的理想路径上 (防止 B 躲到 A 的下一步去)。
|
||||||
|
* 生成一条给 B 的**移动任务** (点到点移动)。
|
||||||
|
* A 小车保持等待,直到 B 移开。
|
||||||
|
* **场景 2:A 自己避让 (兜底)**
|
||||||
|
* 如果 B 无法移动 (例如 B 也被堵死,或找不到合适的避让点),则回退到原有的逻辑:**A 自己去避让点**,并在之后生成后续任务回来。
|
||||||
|
|
||||||
|
## 代码实现计划
|
||||||
|
|
||||||
|
将在 `BaseSRgvThread.java` 中现有的避让逻辑前插入新的判断块:
|
||||||
|
|
||||||
|
1. **新增 helper 方法**:
|
||||||
|
* `getStaticMap()`: 获取不含动态障碍物的地图。
|
||||||
|
* `isAgvIdle(String agvCode)`: 检查某小车是否空闲。
|
||||||
|
2. **修改 `sendPointToPointTask`**:
|
||||||
|
* 在路径规划失败后,先执行 "寻找阻挡车并调度其避让" 的逻辑。
|
||||||
|
* 如果成功调度了 B,则 `return false` (结束本次 A 的调度)。
|
||||||
|
* 如果未成功,则继续执行原有的 "A 去避让" 逻辑。
|
||||||
|
|
||||||
|
## 预期效果
|
||||||
|
|
||||||
|
* **更智能**:不再傻傻地让正在干活的车去绕路,而是把闲置的挡路车移开。
|
||||||
|
* **防止死锁**:通过主动疏通路径,减少多车拥堵的概率。
|
||||||
|
* **兼容性**:保留了原有的 A 避让逻辑作为兜底方案,确保任何情况下都有路可走。
|
||||||
@@ -23,6 +23,8 @@ public interface RoadCacheService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
int[][] handleMap(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv);
|
int[][] handleMap(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv);
|
||||||
|
|
||||||
|
int[][] handleMap1(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv);
|
||||||
/**
|
/**
|
||||||
* 根据x y z 获取指定位置的缓存
|
* 根据x y z 获取指定位置的缓存
|
||||||
* @param x
|
* @param x
|
||||||
|
|||||||
@@ -61,7 +61,25 @@ public class RoadCacheServiceImpl implements RoadCacheService {
|
|||||||
//3.锁定离线小车当前位置
|
//3.锁定离线小车当前位置
|
||||||
lockedOfflineCarCurrSite(maps, deviceSrgv);
|
lockedOfflineCarCurrSite(maps, deviceSrgv);
|
||||||
|
|
||||||
int[][] mapsInt = new int[29][15];
|
int[][] mapsInt = new int[29][16];
|
||||||
|
for (String site : maps.keySet()) {
|
||||||
|
WcsSrgvMap wcsSrgvMap = maps.get(site);
|
||||||
|
mapsInt[wcsSrgvMap.getX()][wcsSrgvMap.getY()] = wcsSrgvMap.getValue();
|
||||||
|
}
|
||||||
|
return mapsInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[][] handleMap1(Map<String, WcsSrgvMap> maps, DeviceSrgv deviceSrgv) {
|
||||||
|
|
||||||
|
// //1.锁定其他车任务路径
|
||||||
|
// lockedOtherCarQueuePath(maps, deviceSrgv);
|
||||||
|
// //2.锁定无任务小车当前位置
|
||||||
|
// lockedOtherCarCurrSite(maps, deviceSrgv);
|
||||||
|
//3.锁定离线小车当前位置
|
||||||
|
// lockedOfflineCarCurrSite(maps, deviceSrgv);
|
||||||
|
|
||||||
|
int[][] mapsInt = new int[29][16];
|
||||||
for (String site : maps.keySet()) {
|
for (String site : maps.keySet()) {
|
||||||
WcsSrgvMap wcsSrgvMap = maps.get(site);
|
WcsSrgvMap wcsSrgvMap = maps.get(site);
|
||||||
mapsInt[wcsSrgvMap.getX()][wcsSrgvMap.getY()] = wcsSrgvMap.getValue();
|
mapsInt[wcsSrgvMap.getX()][wcsSrgvMap.getY()] = wcsSrgvMap.getValue();
|
||||||
@@ -141,7 +159,9 @@ public class RoadCacheServiceImpl implements RoadCacheService {
|
|||||||
//添加其他小车路径列表
|
//添加其他小车路径列表
|
||||||
HashSet<String> otherCarSiteList = new HashSet<>();
|
HashSet<String> otherCarSiteList = new HashSet<>();
|
||||||
for (WcsSrgvQueue wcsSrgvQueue : otherCarQueue) {
|
for (WcsSrgvQueue wcsSrgvQueue : otherCarQueue) {
|
||||||
otherCarSiteList.addAll(Arrays.asList(wcsSrgvQueue.getPathInfo().split(",")));
|
if (wcsSrgvQueue.getPathInfo()!=null) {
|
||||||
|
otherCarSiteList.addAll(Arrays.asList(wcsSrgvQueue.getPathInfo().split(",")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//锁定其他小车路径
|
//锁定其他小车路径
|
||||||
if (CollUtil.isNotEmpty(otherCarSiteList)) {
|
if (CollUtil.isNotEmpty(otherCarSiteList)) {
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public class DeviceCarController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 查询设备信息列表
|
* 查询设备信息列表
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('device:DeviceCar:list')")
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(DeviceCar deviceCar)
|
public TableDataInfo list(DeviceCar deviceCar)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public class DeviceSrgvController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 查询四向小车设备表列表
|
* 查询四向小车设备表列表
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('device:srgv:list')")
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(DeviceSrgv deviceSrgv)
|
public TableDataInfo list(DeviceSrgv deviceSrgv)
|
||||||
{
|
{
|
||||||
@@ -80,7 +79,7 @@ public class DeviceSrgvController extends BaseController
|
|||||||
return toAjax(deviceSrgvService.insertDeviceSrgv(deviceSrgv));
|
return toAjax(deviceSrgvService.insertDeviceSrgv(deviceSrgv));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改四向小车设备表
|
* 修改四向小车设备表
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('device:srgv:edit')")
|
@PreAuthorize("@ss.hasPermi('device:srgv:edit')")
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public class DeviceSsjController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 查询输送机列表
|
* 查询输送机列表
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('device:ssj:list')")
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(DeviceSsj deviceSsj)
|
public TableDataInfo list(DeviceSsj deviceSsj)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ public class DeviceTsjController extends BaseController
|
|||||||
/**
|
/**
|
||||||
* 查询提升机设备列表
|
* 查询提升机设备列表
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('device:tsj:list')")
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(DeviceTsj deviceTsj)
|
public TableDataInfo list(DeviceTsj deviceTsj)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -250,7 +250,6 @@ public class IndexController extends BaseController {
|
|||||||
statusCount.put("SRGV", new HashMap<>());
|
statusCount.put("SRGV", new HashMap<>());
|
||||||
statusCount.put("TSJ", new HashMap<>());
|
statusCount.put("TSJ", new HashMap<>());
|
||||||
statusCount.put("SSJ", new HashMap<>());
|
statusCount.put("SSJ", new HashMap<>());
|
||||||
|
|
||||||
// 查询DeviceCar数据(AGV)
|
// 查询DeviceCar数据(AGV)
|
||||||
DeviceSrgv deviceSrgv = new DeviceSrgv();
|
DeviceSrgv deviceSrgv = new DeviceSrgv();
|
||||||
List<DeviceSrgv> deviceSrgvs = deviceSrgvService.selectDeviceSrgvList(deviceSrgv);
|
List<DeviceSrgv> deviceSrgvs = deviceSrgvService.selectDeviceSrgvList(deviceSrgv);
|
||||||
@@ -274,19 +273,15 @@ public class IndexController extends BaseController {
|
|||||||
for (DeviceSsj ssj : ssjList) {
|
for (DeviceSsj ssj : ssjList) {
|
||||||
int taskNo = ssj.getTaskNo();
|
int taskNo = ssj.getTaskNo();
|
||||||
String status = "其他";
|
String status = "其他";
|
||||||
|
|
||||||
// 根据taskNo判断状态:不等于空或0时为运行状态
|
// 根据taskNo判断状态:不等于空或0时为运行状态
|
||||||
if (taskNo != 0) {
|
if (taskNo != 0) {
|
||||||
status = "运行";
|
status = "运行";
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Integer> typeStatusCount = statusCount.get("SSJ");
|
Map<String, Integer> typeStatusCount = statusCount.get("SSJ");
|
||||||
typeStatusCount.put(status, typeStatusCount.getOrDefault(status, 0) + 1);
|
typeStatusCount.put(status, typeStatusCount.getOrDefault(status, 0) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceTsj deviceTsj = new DeviceTsj();
|
DeviceTsj deviceTsj = new DeviceTsj();
|
||||||
List<DeviceTsj> TsjList = deviceTsjService.selectDeviceTsjList(deviceTsj);
|
List<DeviceTsj> TsjList = deviceTsjService.selectDeviceTsjList(deviceTsj);
|
||||||
|
|
||||||
for (DeviceTsj tsj : TsjList){
|
for (DeviceTsj tsj : TsjList){
|
||||||
Long taskNo = tsj.getRwh();
|
Long taskNo = tsj.getRwh();
|
||||||
String status = "其他";
|
String status = "其他";
|
||||||
@@ -296,7 +291,6 @@ public class IndexController extends BaseController {
|
|||||||
Map<String,Integer> typeStatusCount = statusCount.get("TSJ");
|
Map<String,Integer> typeStatusCount = statusCount.get("TSJ");
|
||||||
typeStatusCount.put(status,typeStatusCount.getOrDefault(status,0) + 1);
|
typeStatusCount.put(status,typeStatusCount.getOrDefault(status,0) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AjaxResult.success(statusCount);
|
return AjaxResult.success(statusCount);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return AjaxResult.error("获取设备状态分布数据失败");
|
return AjaxResult.error("获取设备状态分布数据失败");
|
||||||
|
|||||||
@@ -85,4 +85,7 @@ public interface MydoJobMapper
|
|||||||
void selectMydoJobOutside(HashMap<String, Object> map);
|
void selectMydoJobOutside(HashMap<String, Object> map);
|
||||||
|
|
||||||
List<MydoJob> selectOutJobList(@Param("theFloor") String floor);
|
List<MydoJob> selectOutJobList(@Param("theFloor") String floor);
|
||||||
|
|
||||||
|
List<MydoJob> selectInJobList(@Param("theFloor") String floor);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,4 +88,6 @@ public interface IMydoJobService
|
|||||||
|
|
||||||
|
|
||||||
List<MydoJob> selectOutJobList(String floor);
|
List<MydoJob> selectOutJobList(String floor);
|
||||||
|
|
||||||
|
List<MydoJob> selectInJobList(String floor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.ruoyi.job.service.impl;
|
package com.ruoyi.job.service.impl;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -188,4 +189,9 @@ public class MydoJobServiceImpl implements IMydoJobService
|
|||||||
public List<MydoJob> selectOutJobList(String floor) {
|
public List<MydoJob> selectOutJobList(String floor) {
|
||||||
return mydoJobMapper.selectOutJobList(floor);
|
return mydoJobMapper.selectOutJobList(floor);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public List<MydoJob> selectInJobList(String floor) {
|
||||||
|
return mydoJobMapper.selectInJobList(floor);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,14 +29,22 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ScheduleThread {
|
public class ScheduleThread {
|
||||||
|
|
||||||
|
public Map<String, CustomThread<?>> threadMap = new ConcurrentHashMap<>();
|
||||||
|
public Map<String, String> threadDescMap = new ConcurrentHashMap<>();
|
||||||
|
public Map<String, String> threadTypeMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public CustomThread<PlcSsjRead> plcSsjReadCustomThread;
|
public CustomThread<PlcSsjRead> plcSsjReadCustomThread;
|
||||||
public CustomThread<PlcCdzRead> plcCdzjReadCustomThread;
|
public CustomThread<PlcCdzRead> plcCdzjReadCustomThread;
|
||||||
public CustomThread<PlcTsjRead> plcTsjReadCustomThread;
|
public CustomThread<PlcTsjRead> plcTsjReadCustomThread;
|
||||||
@@ -49,12 +57,7 @@ public class ScheduleThread {
|
|||||||
public CustomThread<SRgv1Thread> sRgvThreadCustomThread;
|
public CustomThread<SRgv1Thread> sRgvThreadCustomThread;
|
||||||
public CustomThread<TsjThread> tsjThreadCustomThread;
|
public CustomThread<TsjThread> tsjThreadCustomThread;
|
||||||
public CustomThread<CdzThread> cdzThreadCustomThread;
|
public CustomThread<CdzThread> cdzThreadCustomThread;
|
||||||
// public CustomThread<Ddj1Thread> ddj1CustomThread;
|
|
||||||
/*public CustomThread<Ddj2Thread> ddj2CustomThread;
|
|
||||||
public CustomThread<Ddj3Thread> ddj3CustomThread;
|
|
||||||
public CustomThread<Ddj4Thread> ddj4CustomThread;
|
|
||||||
public CustomThread<Ddj5Thread> ddj5CustomThread;
|
|
||||||
public CustomThread<Ddj6Thread> ddj6CustomThread;*/
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IDeviceSsjService deviceSsjService;
|
private IDeviceSsjService deviceSsjService;
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -85,23 +88,51 @@ public class ScheduleThread {
|
|||||||
|
|
||||||
log.info("调度服务执行成功");
|
log.info("调度服务执行成功");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
try {
|
||||||
|
for (String key : threadMap.keySet()) {
|
||||||
|
CustomThread<?> ct = threadMap.get(key);
|
||||||
|
if (ct != null && ct.getRunnable() != null) {
|
||||||
|
setRunnableIsRun(ct.getRunnable(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String key : threadMap.keySet()) {
|
||||||
|
CustomThread<?> ct = threadMap.get(key);
|
||||||
|
if (ct != null && ct.getThread() != null) {
|
||||||
|
try {
|
||||||
|
ct.getThread().join(2000);
|
||||||
|
} catch (InterruptedException ignored) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("调度服务销毁时停止线程异常", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调度初始化
|
* 调度初始化
|
||||||
*/
|
*/
|
||||||
private void scheduleInit() {
|
private void scheduleInit() {
|
||||||
//输送机线程
|
//输送机线程
|
||||||
SsjThread ssjThread=new SsjThread();
|
SsjThread ssjThread = new SsjThread();
|
||||||
ssjThreadCustomThread=new CustomThread<SsjThread>(new Thread(ssjThread),ssjThread);
|
ssjThreadCustomThread = new CustomThread<SsjThread>(new Thread(ssjThread, "ssjThreadCustomThread"), ssjThread);
|
||||||
// //四向车线程
|
//四向车线程
|
||||||
SRgv1Thread srgvThread=new SRgv1Thread();
|
SRgv1Thread srgvThread = new SRgv1Thread();
|
||||||
sRgvThreadCustomThread=new CustomThread<>(new Thread(srgvThread),srgvThread);
|
sRgvThreadCustomThread = new CustomThread<>(new Thread(srgvThread, "sRgvThreadCustomThread"), srgvThread);
|
||||||
//提升机线程
|
//提升机线程
|
||||||
TsjThread tsjThread=new TsjThread();
|
TsjThread tsjThread = new TsjThread();
|
||||||
tsjThreadCustomThread=new CustomThread<>(new Thread(tsjThread),tsjThread);
|
tsjThreadCustomThread = new CustomThread<>(new Thread(tsjThread, "tsjThreadCustomThread"), tsjThread);
|
||||||
//充电线程
|
//充电线程
|
||||||
CdzThread cdzThread = new CdzThread();
|
CdzThread cdzThread = new CdzThread();
|
||||||
cdzThreadCustomThread=new CustomThread<>(new Thread(cdzThread),cdzThread);
|
cdzThreadCustomThread = new CustomThread<>(new Thread(cdzThread, "cdzThreadCustomThread"), cdzThread);
|
||||||
|
|
||||||
|
refreshThreadMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* plc读取初始化
|
* plc读取初始化
|
||||||
*/
|
*/
|
||||||
@@ -113,18 +144,18 @@ public class ScheduleThread {
|
|||||||
for (DeviceSsj deviceSsj : deviceSsjs) {
|
for (DeviceSsj deviceSsj : deviceSsjs) {
|
||||||
ssjList.put(deviceSsj.getDeviceCode(), deviceSsj);
|
ssjList.put(deviceSsj.getDeviceCode(), deviceSsj);
|
||||||
}
|
}
|
||||||
PlcSsjRead plcSsjRead = new PlcSsjRead(ssjList, new PlcConnectInfo("127.0.0.1", 1502));
|
PlcSsjRead plcSsjRead = new PlcSsjRead(ssjList, new PlcConnectInfo("192.168.10.100", 502));
|
||||||
Thread plcSsjReadThread = new Thread(plcSsjRead);
|
Thread plcSsjReadThread = new Thread(plcSsjRead, "plcSsjReadCustomThread");
|
||||||
plcSsjReadCustomThread = new CustomThread<PlcSsjRead>(plcSsjReadThread, plcSsjRead);
|
plcSsjReadCustomThread = new CustomThread<PlcSsjRead>(plcSsjReadThread, plcSsjRead);
|
||||||
|
|
||||||
//plc充电桩读取线程
|
//plc充电桩读取线程
|
||||||
ConcurrentHashMap<String, DeviceCdz> cdzList = new ConcurrentHashMap<>();
|
ConcurrentHashMap<String, DeviceCdz> cdzList = new ConcurrentHashMap<>();
|
||||||
List<DeviceCdz> deviceCdzList =deviceCdzService.selectDeviceCdzList(new DeviceCdz());
|
List<DeviceCdz> deviceCdzList = deviceCdzService.selectDeviceCdzList(new DeviceCdz());
|
||||||
for (DeviceCdz deviceCdz : deviceCdzList) {
|
for (DeviceCdz deviceCdz : deviceCdzList) {
|
||||||
cdzList.put(String.valueOf(deviceCdz.getId()),deviceCdz);
|
cdzList.put(String.valueOf(deviceCdz.getId()), deviceCdz);
|
||||||
}
|
}
|
||||||
PlcCdzRead plcCdzRead = new PlcCdzRead(cdzList, new PlcConnectInfo("127.0.0.1", 1502));
|
PlcCdzRead plcCdzRead = new PlcCdzRead(cdzList, new PlcConnectInfo("192.168.10.100", 502));
|
||||||
Thread plcCdzReadThread = new Thread(plcCdzRead);
|
Thread plcCdzReadThread = new Thread(plcCdzRead, "plcCdzjReadCustomThread");
|
||||||
plcCdzjReadCustomThread = new CustomThread<PlcCdzRead>(plcCdzReadThread, plcCdzRead);
|
plcCdzjReadCustomThread = new CustomThread<PlcCdzRead>(plcCdzReadThread, plcCdzRead);
|
||||||
|
|
||||||
|
|
||||||
@@ -135,84 +166,101 @@ public class ScheduleThread {
|
|||||||
tsjList.put(t.getName(), t);
|
tsjList.put(t.getName(), t);
|
||||||
}
|
}
|
||||||
//plc提升机读取线程
|
//plc提升机读取线程
|
||||||
PlcTsjRead plcTsjRead = new PlcTsjRead(tsjList, new PlcConnectInfo("127.0.0.1", 1502));
|
PlcTsjRead plcTsjRead = new PlcTsjRead(tsjList, new PlcConnectInfo("192.168.10.100", 502));
|
||||||
Thread plcTsjReadThread = new Thread(plcTsjRead);
|
Thread plcTsjReadThread = new Thread(plcTsjRead, "plcTsjReadCustomThread");
|
||||||
plcTsjReadCustomThread = new CustomThread<PlcTsjRead>(plcTsjReadThread, plcTsjRead);
|
plcTsjReadCustomThread = new CustomThread<PlcTsjRead>(plcTsjReadThread, plcTsjRead);
|
||||||
|
|
||||||
ConcurrentHashMap<String, DeviceSrgv> srgvList = new ConcurrentHashMap<>();
|
ConcurrentHashMap<String, DeviceSrgv> srgvList = new ConcurrentHashMap<>();
|
||||||
List<DeviceSrgv> srgvs=deviceSrgvService.selectDeviceSrgvList(new DeviceSrgv());
|
List<DeviceSrgv> srgvs = deviceSrgvService.selectDeviceSrgvList(new DeviceSrgv());
|
||||||
for(DeviceSrgv srgv:srgvs){
|
for (DeviceSrgv srgv : srgvs) {
|
||||||
srgvList.put(srgv.getDeviceId().toString(),srgv);
|
switch (srgv.getDeviceId()) {
|
||||||
switch (srgv.getDeviceId()){
|
|
||||||
case 1:
|
case 1:
|
||||||
PlcSrgvRead plcSrgvRead1=new PlcSrgvRead(srgv,new PlcConnectInfo(srgv.getIp(),srgv.getPort()));
|
PlcSrgvRead plcSrgvRead1 = new PlcSrgvRead(srgv, new PlcConnectInfo(srgv.getIp(), srgv.getPort()));
|
||||||
Thread plcSrgvReadThread1 = new Thread((plcSrgvRead1));
|
Thread plcSrgvReadThread1 = new Thread(plcSrgvRead1, "plcSrgvReadCustomThread1");
|
||||||
plcSrgvReadCustomThread1=new CustomThread<PlcSrgvRead>(plcSrgvReadThread1,plcSrgvRead1);
|
plcSrgvReadCustomThread1 = new CustomThread<PlcSrgvRead>(plcSrgvReadThread1, plcSrgvRead1);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
PlcSrgvRead plcSrgvRead2=new PlcSrgvRead(srgv,new PlcConnectInfo(srgv.getIp(),srgv.getPort()));
|
PlcSrgvRead plcSrgvRead2 = new PlcSrgvRead(srgv, new PlcConnectInfo(srgv.getIp(), srgv.getPort()));
|
||||||
Thread plcSrgvReadThread2 = new Thread((plcSrgvRead2));
|
Thread plcSrgvReadThread2 = new Thread(plcSrgvRead2, "plcSrgvReadCustomThread2");
|
||||||
plcSrgvReadCustomThread2=new CustomThread<PlcSrgvRead>(plcSrgvReadThread2,plcSrgvRead2);
|
plcSrgvReadCustomThread2 = new CustomThread<PlcSrgvRead>(plcSrgvReadThread2, plcSrgvRead2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
srgvList.put(srgv.getDeviceId().toString(), srgv);
|
||||||
}
|
}
|
||||||
PlcSrgvRead.deviceSrgvMap=srgvList;
|
PlcSrgvRead.deviceSrgvMap = srgvList;
|
||||||
//监控线程
|
//监控线程
|
||||||
MonitoringThread monitoringThread = new MonitoringThread();
|
MonitoringThread monitoringThread = new MonitoringThread();
|
||||||
monitoringCustomThread = new CustomThread<MonitoringThread>(new Thread(monitoringThread), monitoringThread);
|
monitoringCustomThread = new CustomThread<MonitoringThread>(new Thread(monitoringThread, "monitoringCustomThread"), monitoringThread);
|
||||||
|
|
||||||
|
refreshThreadMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshThreadMap() {
|
||||||
|
registerThread("plcSsjReadCustomThread", plcSsjReadCustomThread, "PLC输送机读取线程", "read");
|
||||||
|
registerThread("plcCdzjReadCustomThread", plcCdzjReadCustomThread, "PLC充电桩读取线程", "read");
|
||||||
|
registerThread("plcTsjReadCustomThread", plcTsjReadCustomThread, "PLC提升机读取线程", "read");
|
||||||
|
registerThread("plcSrgvReadCustomThread1", plcSrgvReadCustomThread1, "PLC四向车1读取线程", "read");
|
||||||
|
registerThread("plcSrgvReadCustomThread2", plcSrgvReadCustomThread2, "PLC四向车2读取线程", "read");
|
||||||
|
registerThread("monitoringCustomThread", monitoringCustomThread, "监控线程", "monitor");
|
||||||
|
registerThread("ssjThreadCustomThread", ssjThreadCustomThread, "输送机调度线程", "schedule");
|
||||||
|
registerThread("sRgvThreadCustomThread", sRgvThreadCustomThread, "四向车调度线程", "schedule");
|
||||||
|
registerThread("tsjThreadCustomThread", tsjThreadCustomThread, "提升机调度线程", "schedule");
|
||||||
|
registerThread("cdzThreadCustomThread", cdzThreadCustomThread, "充电调度线程", "schedule");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerThread(String key, CustomThread<?> thread, String desc, String type) {
|
||||||
|
if (thread != null) {
|
||||||
|
threadMap.put(key, thread);
|
||||||
|
threadDescMap.put(key, desc);
|
||||||
|
threadTypeMap.put(key, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始线程
|
* 开始线程 读取
|
||||||
*/
|
*/
|
||||||
public void startAllThread() {
|
public void startAllThread() {
|
||||||
plcSsjReadCustomThread.getThread().start();
|
plcSsjReadCustomThread.getThread().start();
|
||||||
plcSrgvReadCustomThread1.getThread().start();
|
plcSrgvReadCustomThread1.getThread().start();
|
||||||
// plcSrgvReadCustomThread2.getThread().start();
|
plcSrgvReadCustomThread2.getThread().start();
|
||||||
plcTsjReadCustomThread.getThread().start();
|
plcTsjReadCustomThread.getThread().start();
|
||||||
monitoringCustomThread.getThread().start();
|
monitoringCustomThread.getThread().start();
|
||||||
//充电桩读取线程
|
//充电桩读取线程
|
||||||
// plcCdzjReadCustomThread.getThread().start();
|
plcCdzjReadCustomThread.getThread().start();
|
||||||
isRun = true;
|
isRun = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开启线程2
|
* 开启线程2 调度
|
||||||
*/
|
*/
|
||||||
public void startAllThread2() {
|
public void startAllThread2() {
|
||||||
ssjThreadCustomThread.thread.start();
|
ssjThreadCustomThread.thread.start();
|
||||||
tsjThreadCustomThread.thread.start();
|
tsjThreadCustomThread.thread.start();
|
||||||
sRgvThreadCustomThread.thread.start();
|
sRgvThreadCustomThread.thread.start();
|
||||||
// cdzThreadCustomThread.thread.start();
|
cdzThreadCustomThread.thread.start();
|
||||||
isRun2 = true;
|
isRun2 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止线程
|
* 停止线程读取
|
||||||
*/
|
*/
|
||||||
public void stopAllThread() {
|
public void stopAllThread() {
|
||||||
plcSsjReadCustomThread.runnable.isRun = false;
|
plcSsjReadCustomThread.runnable.isRun = false;
|
||||||
// plcDdj1ReadCustomThread.runnable.isRun = false;
|
plcSrgvReadCustomThread1.runnable.isRun = false;
|
||||||
/* plcDdj2ReadCustomThread.runnable.isRun = false;
|
plcSrgvReadCustomThread2.runnable.isRun = false;
|
||||||
plcDdj3ReadCustomThread.runnable.isRun = false;
|
plcTsjReadCustomThread.runnable.isRun = false;
|
||||||
plcDdj4ReadCustomThread.runnable.isRun = false;
|
monitoringCustomThread.runnable.isRun = false;
|
||||||
plcDdj5ReadCustomThread.runnable.isRun = false;
|
|
||||||
plcDdj6ReadCustomThread.runnable.isRun = false;*/
|
|
||||||
plcReadInit();
|
plcReadInit();
|
||||||
isRun = false;
|
isRun = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 停止线程2
|
* 停止线程调度
|
||||||
*/
|
*/
|
||||||
public void stopAllThread2() {
|
public void stopAllThread2() {
|
||||||
monitoringCustomThread.runnable.isRun = false;
|
ssjThreadCustomThread.runnable.isRun = false;
|
||||||
// ddj1CustomThread.runnable.isRun = false;
|
tsjThreadCustomThread.runnable.isRun = false;
|
||||||
/*ddj2CustomThread.runnable.isRun = false;
|
sRgvThreadCustomThread.runnable.isRun = false;
|
||||||
ddj3CustomThread.runnable.isRun = false;
|
|
||||||
ddj4CustomThread.runnable.isRun = false;
|
|
||||||
ddj5CustomThread.runnable.isRun = false;
|
|
||||||
ddj6CustomThread.runnable.isRun = false;*/
|
|
||||||
scheduleInit();
|
scheduleInit();
|
||||||
isRun2 = false;
|
isRun2 = false;
|
||||||
}
|
}
|
||||||
@@ -220,11 +268,91 @@ public class ScheduleThread {
|
|||||||
/**
|
/**
|
||||||
* 获取调度状态
|
* 获取调度状态
|
||||||
*/
|
*/
|
||||||
public HashMap<String,Boolean> getScheduleStatus() {
|
public HashMap<String, Boolean> getScheduleStatus() {
|
||||||
HashMap<String,Boolean> map = new HashMap<>();
|
HashMap<String, Boolean> map = new HashMap<>();
|
||||||
map.put("isRun",isRun);
|
map.put("isRun", isRun);
|
||||||
map.put("isRun2",isRun2);
|
map.put("isRun2", isRun2);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有受管线程状态
|
||||||
|
*/
|
||||||
|
public List<Map<String, Object>> getAllThreadStatus() {
|
||||||
|
List<Map<String, Object>> list = new ArrayList<>();
|
||||||
|
for (String key : threadDescMap.keySet()) {
|
||||||
|
CustomThread<?> ct = threadMap.get(key);
|
||||||
|
Map<String, Object> info = new HashMap<>();
|
||||||
|
info.put("key", key);
|
||||||
|
info.put("name", threadDescMap.get(key));
|
||||||
|
info.put("type", threadTypeMap.get(key));
|
||||||
|
boolean alive = false;
|
||||||
|
boolean isRun = false;
|
||||||
|
if (ct != null && ct.getRunnable() != null) {
|
||||||
|
try {
|
||||||
|
Field field = ct.getRunnable().getClass().getField("isRun");
|
||||||
|
isRun = field.getBoolean(ct.getRunnable());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取线程[{}]isRun状态异常", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.put("isRun", isRun);
|
||||||
|
if (ct != null && ct.getThread() != null) {
|
||||||
|
alive = ct.getThread().isAlive();
|
||||||
|
}
|
||||||
|
info.put("alive", alive);
|
||||||
|
list.add(info);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动指定线程
|
||||||
|
*/
|
||||||
|
public synchronized void startThread(String key) {
|
||||||
|
CustomThread<?> ct = threadMap.get(key);
|
||||||
|
if (ct == null) {
|
||||||
|
throw new RuntimeException("未知线程: " + key);
|
||||||
|
}
|
||||||
|
if (ct.getThread() != null && ct.getThread().isAlive()) {
|
||||||
|
log.info("线程 {} 已经在运行中", key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置Runnable isRun = true
|
||||||
|
setRunnableIsRun(ct.getRunnable(), true);
|
||||||
|
|
||||||
|
// 创建新线程
|
||||||
|
Thread newThread = new Thread((Runnable) ct.getRunnable(), key);
|
||||||
|
ct.setThread(newThread);
|
||||||
|
newThread.start();
|
||||||
|
log.info("线程 {} 已启动", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止指定线程
|
||||||
|
*/
|
||||||
|
public synchronized void stopThread(String key) {
|
||||||
|
CustomThread<?> ct = threadMap.get(key);
|
||||||
|
if (ct == null) {
|
||||||
|
throw new RuntimeException("未知线程: " + key);
|
||||||
|
}
|
||||||
|
// 设置Runnable isRun = false
|
||||||
|
setRunnableIsRun(ct.getRunnable(), false);
|
||||||
|
log.info("线程 {} 停止指令已下发", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRunnableIsRun(Object runnable, boolean isRun) {
|
||||||
|
try {
|
||||||
|
Field field = runnable.getClass().getField("isRun"); // 使用getField获取public字段
|
||||||
|
field.setBoolean(runnable, isRun);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
// 尝试查找父类或非public字段? 目前都是public
|
||||||
|
log.error("无法找到isRun字段: {}", runnable.getClass().getName());
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
log.error("无法访问isRun字段: {}", runnable.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,8 +90,11 @@ public class PlcCdzRead implements Runnable {
|
|||||||
if (read1.IsSuccess) {
|
if (read1.IsSuccess) {
|
||||||
cdzDevice.setModel(Convert.toInt(byteTransform.TransInt16(read1.Content, 0)));
|
cdzDevice.setModel(Convert.toInt(byteTransform.TransInt16(read1.Content, 0)));
|
||||||
cdzDevice.setStatus(Convert.toInt(byteTransform.TransInt16(read1.Content, 2)));
|
cdzDevice.setStatus(Convert.toInt(byteTransform.TransInt16(read1.Content, 2)));
|
||||||
|
if (cdzDevice.getStatus()==0){
|
||||||
|
cdzDevice.setSpare1("0");
|
||||||
|
}
|
||||||
log.info("=====读取到充电桩充电模式:{}======", Convert.toInt(byteTransform.TransInt16(read1.Content, 0)));
|
log.info("=====读取到充电桩充电模式:{}======", Convert.toInt(byteTransform.TransInt16(read1.Content, 0)));
|
||||||
log.info("=====读取到充电桩充电状态:{}======", Convert.toInt(byteTransform.TransInt16(read1.Content, 0)));
|
log.info("=====读取到充电桩充电状态:{}======", Convert.toInt(byteTransform.TransInt16(read1.Content, 2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
public class PlcSrgvRead implements Runnable {
|
public class PlcSrgvRead implements Runnable {
|
||||||
|
|
||||||
public static ConcurrentHashMap<String, DeviceSrgv> deviceSrgvMap;
|
public static ConcurrentHashMap<String, DeviceSrgv> deviceSrgvMap;
|
||||||
private static ModbusTcpNet modbusTcpNet;
|
private ModbusTcpNet modbusTcpNet;
|
||||||
public static IReadWriteNet readWriteNet = null;
|
public IReadWriteNet readWriteNet = null;
|
||||||
public volatile boolean isRun = true;
|
public volatile boolean isRun = true;
|
||||||
private final String ip;
|
private final String ip;
|
||||||
private final int port;
|
private final int port;
|
||||||
@@ -39,14 +39,14 @@ public class PlcSrgvRead implements Runnable {
|
|||||||
this.station = (byte) 1;
|
this.station = (byte) 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean Write(String address, int[] value) {
|
public synchronized boolean write(String address, int[] value) {
|
||||||
|
|
||||||
OperateResult write = modbusTcpNet.Write(address, value);
|
OperateResult write = modbusTcpNet.Write(address, value);
|
||||||
return write.IsSuccess;
|
return write.IsSuccess;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean Write(String address, short[] value) {
|
public synchronized boolean write(String address, short[] value) {
|
||||||
|
|
||||||
OperateResult write = modbusTcpNet.Write(address, value);
|
OperateResult write = modbusTcpNet.Write(address, value);
|
||||||
return write.IsSuccess;
|
return write.IsSuccess;
|
||||||
@@ -58,9 +58,11 @@ public class PlcSrgvRead implements Runnable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
while (isRun) {
|
while (isRun) {
|
||||||
try {
|
try {
|
||||||
if (IsConnect()) {
|
if (
|
||||||
|
IsConnect()) {
|
||||||
if (deviceSrgv != null) {
|
if (deviceSrgv != null) {
|
||||||
readSrgvPlc(deviceSrgv);
|
readSrgvPlc(deviceSrgv);
|
||||||
|
log.info("=====读取小车开始====IP{}",this.ip);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reConnect();
|
reConnect();
|
||||||
@@ -158,6 +160,7 @@ public class PlcSrgvRead implements Runnable {
|
|||||||
|
|
||||||
public void ConnectServer() {
|
public void ConnectServer() {
|
||||||
modbusTcpNet = new ModbusTcpNet();//创建一个Modbus对象
|
modbusTcpNet = new ModbusTcpNet();//创建一个Modbus对象
|
||||||
|
log.info("创建连接对象,IP{}",this.ip);
|
||||||
try {
|
try {
|
||||||
modbusTcpNet.setIpAddress(this.ip);
|
modbusTcpNet.setIpAddress(this.ip);
|
||||||
modbusTcpNet.setPort(this.port);
|
modbusTcpNet.setPort(this.port);
|
||||||
@@ -200,7 +203,7 @@ public class PlcSrgvRead implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getSite(String siteId){
|
public String getSite(String siteId){
|
||||||
if (siteId.equals("030502")||siteId.equals("030501")||siteId.equals("030503")){
|
if (siteId.equals("030602")||siteId.equals("030601")||siteId.equals("030603")){
|
||||||
return "tsj";
|
return "tsj";
|
||||||
}else {
|
}else {
|
||||||
return siteId;
|
return siteId;
|
||||||
|
|||||||
@@ -118,9 +118,16 @@ public class PlcSsjRead implements Runnable {
|
|||||||
OperateResultExOne<byte[]> read4 = modbusTcpNet.Read("1115", (short) 16);//1115 条码
|
OperateResultExOne<byte[]> read4 = modbusTcpNet.Read("1115", (short) 16);//1115 条码
|
||||||
if (read4.IsSuccess) {
|
if (read4.IsSuccess) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (byte b : read4.Content) {
|
for (int i = 0; i < read4.Content.length; i += 2) {
|
||||||
int code = b & 0xFF;
|
if (i + 1 < read4.Content.length) {
|
||||||
if (code >= 32 && code <= 126) sb.append((char) code);
|
int hi = read4.Content[i + 1] & 0xFF;
|
||||||
|
int lo = read4.Content[i] & 0xFF;
|
||||||
|
if (hi >= 32 && hi <= 126) sb.append((char) hi);
|
||||||
|
if (lo >= 32 && lo <= 126) sb.append((char) lo);
|
||||||
|
} else {
|
||||||
|
int single = read4.Content[i] & 0xFF;
|
||||||
|
if (single >= 32 && single <= 126) sb.append((char) single);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String barcode = sb.toString();
|
String barcode = sb.toString();
|
||||||
ssjDevice.setTrayCode(barcode);
|
ssjDevice.setTrayCode(barcode);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class CdzThread implements Runnable {
|
|||||||
|
|
||||||
public boolean isRun = true;
|
public boolean isRun = true;
|
||||||
|
|
||||||
private final Integer LITTLE_BETTERY = 30;
|
private final Integer LITTLE_BETTERY = 60;
|
||||||
private final Integer MIDDLE_BETTERY = 70;
|
private final Integer MIDDLE_BETTERY = 70;
|
||||||
|
|
||||||
private ISrgvChargingJobService chargingJobService;
|
private ISrgvChargingJobService chargingJobService;
|
||||||
@@ -61,7 +61,7 @@ public class CdzThread implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
void dispatch() {
|
void dispatch() {
|
||||||
|
SrgvChargingJob srgvChargingJobParam = new SrgvChargingJob();
|
||||||
//获取低电量小车
|
//获取低电量小车
|
||||||
List<DeviceSrgv> littleBatterySRgv = new ArrayList<>();
|
List<DeviceSrgv> littleBatterySRgv = new ArrayList<>();
|
||||||
//获取中电量小车
|
//获取中电量小车
|
||||||
@@ -98,7 +98,6 @@ public class CdzThread implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
//充电任务下发
|
//充电任务下发
|
||||||
SrgvChargingJob srgvChargingJobParam = new SrgvChargingJob();
|
|
||||||
srgvChargingJobParam.setChargingStatus("1");
|
srgvChargingJobParam.setChargingStatus("1");
|
||||||
srgvChargingJobParam.setJobType("1");
|
srgvChargingJobParam.setJobType("1");
|
||||||
srgvChargingJobParam.setJobStatus("4");
|
srgvChargingJobParam.setJobStatus("4");
|
||||||
@@ -106,12 +105,12 @@ public class CdzThread implements Runnable {
|
|||||||
if (CollUtil.isNotEmpty(srgvChargingJobs)) {
|
if (CollUtil.isNotEmpty(srgvChargingJobs)) {
|
||||||
for (SrgvChargingJob srgvChargingJob : srgvChargingJobs) {
|
for (SrgvChargingJob srgvChargingJob : srgvChargingJobs) {
|
||||||
if ("1".equals(srgvChargingJob.getChargingStatus())) {
|
if ("1".equals(srgvChargingJob.getChargingStatus())) {
|
||||||
int i = PlcCdzRead.writeToCdz("1");
|
// int i = PlcCdzRead.writeToCdz("1");
|
||||||
if (i == 1) {
|
// if (i == 1) {
|
||||||
srgvChargingJob.setChargingStatus("2");
|
srgvChargingJob.setChargingStatus("2");
|
||||||
srgvChargingJob.setChargingDate(DateUtil.formatDateTime(DateUtil.date()));
|
srgvChargingJob.setChargingDate(DateUtil.formatDateTime(DateUtil.date()));
|
||||||
chargingJobService.updateSrgvChargingJob(srgvChargingJob);
|
chargingJobService.updateSrgvChargingJob(srgvChargingJob);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,6 +144,24 @@ public class CdzThread implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//充电桩关闭 完成充电任务
|
||||||
|
DeviceCdz deviceCdz = deviceCdzService.selectDeviceCdzById(1L);
|
||||||
|
if (deviceCdz.getStatus()==0){
|
||||||
|
SrgvChargingJob srgvChargingJobDdParam = new SrgvChargingJob();
|
||||||
|
srgvChargingJobDdParam.setChargingStatus("2");
|
||||||
|
srgvChargingJobDdParam.setJobStatus("4");
|
||||||
|
List<SrgvChargingJob> srgvChargingJobDds = chargingJobService.selectSrgvChargingJobList(srgvChargingJobDdParam);
|
||||||
|
if (CollUtil.isNotEmpty(srgvChargingJobDds)) {
|
||||||
|
for (SrgvChargingJob job :srgvChargingJobDds){
|
||||||
|
job.setChargingStatus("1");
|
||||||
|
job.setChargingDate(DateUtil.formatDateTime(DateUtil.date()));
|
||||||
|
chargingJobService.updateSrgvChargingJob(job);
|
||||||
|
//插入历史
|
||||||
|
chargingJobService.insertHistory(job.getGuid());
|
||||||
|
chargingJobService.deleteSrgvChargingJobByGuid(job.getGuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//断电任务下发
|
//断电任务下发
|
||||||
@@ -156,8 +173,8 @@ public class CdzThread implements Runnable {
|
|||||||
|
|
||||||
for (SrgvChargingJob srgvChargingJob : srgvChargingJobs) {
|
for (SrgvChargingJob srgvChargingJob : srgvChargingJobs) {
|
||||||
if ("0".equals(srgvChargingJob.getChargingStatus())) {
|
if ("0".equals(srgvChargingJob.getChargingStatus())) {
|
||||||
int i = PlcCdzRead.writeToCdz("2");
|
// int i = PlcCdzRead.writeToCdz("2");
|
||||||
if (i == 1) {
|
// if (i == 1) {
|
||||||
srgvChargingJob.setChargingStatus("1");
|
srgvChargingJob.setChargingStatus("1");
|
||||||
srgvChargingJob.setChargingDate(DateUtil.formatDateTime(DateUtil.date()));
|
srgvChargingJob.setChargingDate(DateUtil.formatDateTime(DateUtil.date()));
|
||||||
chargingJobService.updateSrgvChargingJob(srgvChargingJob);
|
chargingJobService.updateSrgvChargingJob(srgvChargingJob);
|
||||||
@@ -165,7 +182,7 @@ public class CdzThread implements Runnable {
|
|||||||
//插入历史
|
//插入历史
|
||||||
chargingJobService.insertHistory(srgvChargingJob.getGuid());
|
chargingJobService.insertHistory(srgvChargingJob.getGuid());
|
||||||
chargingJobService.deleteSrgvChargingJobByGuid(srgvChargingJob.getGuid());
|
chargingJobService.deleteSrgvChargingJobByGuid(srgvChargingJob.getGuid());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -191,19 +208,19 @@ public class CdzThread implements Runnable {
|
|||||||
if (CollUtil.isNotEmpty(cdzList)) {
|
if (CollUtil.isNotEmpty(cdzList)) {
|
||||||
//寻找最接近的充电桩
|
//寻找最接近的充电桩
|
||||||
Integer floor = deviceSrgv.getCurrFloor();
|
Integer floor = deviceSrgv.getCurrFloor();
|
||||||
DeviceCdz cdz = null;
|
DeviceCdz cdz = cdzList.get(0);
|
||||||
Optional<DeviceCdz> min = cdzList.stream().filter(c -> c.getSzcs().equals(floor)).min((o1, o2) -> {
|
// Optional<DeviceCdz> min = cdzList.stream().filter(c -> c.getSzcs().equals(floor)).min((o1, o2) -> {
|
||||||
Integer distance1 = Math.abs(o1.getSzcs());
|
// Integer distance1 = Math.abs(o1.getSzcs());
|
||||||
Integer distance2 = Math.abs(o2.getSzcs());
|
// Integer distance2 = Math.abs(o2.getSzcs());
|
||||||
return distance1 - distance2;
|
// return distance1 - distance2;
|
||||||
});
|
// });
|
||||||
if (min.isPresent()) {
|
// if (min.isPresent()) {
|
||||||
cdz = min.get();
|
// cdz = min.get();
|
||||||
}
|
// }
|
||||||
if (ObjUtil.isNotNull(cdz)) {
|
if (ObjUtil.isNotNull(cdz)) {
|
||||||
//生成充电任务
|
//生成充电任务
|
||||||
SrgvChargingJob srgvChargingJobParam = new SrgvChargingJob();
|
SrgvChargingJob srgvChargingJobParam = new SrgvChargingJob();
|
||||||
srgvChargingJobParam.setAgvId(deviceSrgv.getDeviceId().toString());
|
// srgvChargingJobParam.setAgvId(deviceSrgv.getDeviceId().toString());
|
||||||
srgvChargingJobParam.setChargingSite(cdz.getSiteId());
|
srgvChargingJobParam.setChargingSite(cdz.getSiteId());
|
||||||
srgvChargingJobParam.setChargingId(cdz.getId().toString());
|
srgvChargingJobParam.setChargingId(cdz.getId().toString());
|
||||||
List<SrgvChargingJob> wcsChargingJobs = chargingJobService.selectSrgvChargingJobList(srgvChargingJobParam);
|
List<SrgvChargingJob> wcsChargingJobs = chargingJobService.selectSrgvChargingJobList(srgvChargingJobParam);
|
||||||
@@ -231,7 +248,7 @@ public class CdzThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建充电任务
|
* 创建断电任务
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void createChargingOutJob(DeviceSrgv deviceSrgv, DeviceCdz cdz) {
|
private void createChargingOutJob(DeviceSrgv deviceSrgv, DeviceCdz cdz) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.ruoyi.schedule.scheduleTask.srgv;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.ruoyi.bas.port.service.IWcsPortService;
|
import com.ruoyi.bas.port.service.IWcsPortService;
|
||||||
@@ -32,6 +33,8 @@ import com.ruoyi.schedule.plcRead.cdz.PlcCdzRead;
|
|||||||
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
|
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
|
||||||
import com.ruoyi.schedule.plcRead.srgv.roadUtil.PathFinder;
|
import com.ruoyi.schedule.plcRead.srgv.roadUtil.PathFinder;
|
||||||
import com.ruoyi.schedule.plcRead.tsj.PlcTsjRead;
|
import com.ruoyi.schedule.plcRead.tsj.PlcTsjRead;
|
||||||
|
import com.ruoyi.schedule.ScheduleThread;
|
||||||
|
import com.ruoyi.common.domain.CustomThread;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@@ -70,12 +73,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
|
|
||||||
public JobCallBackServiceImpl jobCallBackService;
|
public JobCallBackServiceImpl jobCallBackService;
|
||||||
|
|
||||||
|
private int taskCache = 450001;
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
sRgvCodeList = new HashMap<>();
|
sRgvCodeList = new HashMap<>();
|
||||||
ArrayList<String> sRgvCodes = new ArrayList<>();
|
ArrayList<String> sRgvCodes = new ArrayList<>();
|
||||||
sRgvCodes.add("1");
|
sRgvCodes.add("1");
|
||||||
// sRgvCodes.add("2");
|
sRgvCodes.add("2");
|
||||||
sRgvCodeList.put("srgv", sRgvCodes);
|
sRgvCodeList.put("srgv", sRgvCodes);
|
||||||
|
|
||||||
wcsSagvQueueMapper = SpringUtils.getBean(IWcsSrgvQueueService.class);
|
wcsSagvQueueMapper = SpringUtils.getBean(IWcsSrgvQueueService.class);
|
||||||
@@ -99,16 +103,17 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
for (String code : sRgvCodeList.get("srgv")) {
|
for (String code : sRgvCodeList.get("srgv")) {
|
||||||
if (PlcSrgvRead.deviceSrgvMap.containsKey(code)) {
|
if (PlcSrgvRead.deviceSrgvMap.containsKey(code)) {
|
||||||
if (ObjUtil.isNotNull(PlcSrgvRead.deviceSrgvMap.get(code))) {
|
if (ObjUtil.isNotNull(PlcSrgvRead.deviceSrgvMap.get(code))) {
|
||||||
|
log.info("小车处理开始");
|
||||||
DeviceSrgv deviceSrgv = PlcSrgvRead.deviceSrgvMap.get(code);
|
DeviceSrgv deviceSrgv = PlcSrgvRead.deviceSrgvMap.get(code);
|
||||||
|
|
||||||
sRgvTask(deviceSrgv);
|
sRgvTask(deviceSrgv);
|
||||||
|
//小车创建队列
|
||||||
createCarQueue(deviceSrgv);
|
createCarQueue(deviceSrgv);
|
||||||
|
|
||||||
inCharging(deviceSrgv);
|
inCharging(deviceSrgv);
|
||||||
|
|
||||||
outCharging(deviceSrgv);
|
outCharging(deviceSrgv);
|
||||||
|
log.info("小车处理结束");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.error("小车设备为空");
|
log.error("小车设备为空");
|
||||||
@@ -144,11 +149,11 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
DeviceCdz deviceCdz = PlcCdzRead.deviceCdzMap.get(chargingId);
|
DeviceCdz deviceCdz = PlcCdzRead.deviceCdzMap.get(chargingId);
|
||||||
if (ObjUtil.isNotNull(deviceCdz)) {
|
if (ObjUtil.isNotNull(deviceCdz)) {
|
||||||
//下发断电任务
|
//下发断电任务
|
||||||
int i = PlcCdzRead.writeToCdz("2");
|
// int i = PlcCdzRead.writeToCdz("2");
|
||||||
if (i == 1) {
|
// if (i == 1) {
|
||||||
srgvChargingJobMapper.insertHistory(srgvChargingJob.getGuid());
|
srgvChargingJobMapper.insertHistory(srgvChargingJob.getGuid());
|
||||||
srgvChargingJobMapper.deleteSrgvChargingJobByGuid(srgvChargingJob.getGuid());
|
srgvChargingJobMapper.deleteSrgvChargingJobByGuid(srgvChargingJob.getGuid());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,8 +179,8 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
String agvId = srgvChargingJob.getAgvId();
|
String agvId = srgvChargingJob.getAgvId();
|
||||||
String chargingId = srgvChargingJob.getChargingId();
|
String chargingId = srgvChargingJob.getChargingId();
|
||||||
DeviceSrgv srgv = PlcSrgvRead.deviceSrgvMap.get(agvId);
|
DeviceSrgv srgv = PlcSrgvRead.deviceSrgvMap.get(agvId);
|
||||||
DeviceCdz cdz = PlcCdzRead.deviceCdzMap.get(chargingId);
|
// DeviceCdz cdz = PlcCdzRead.deviceCdzMap.get(chargingId);
|
||||||
if (srgv.getCurrFloor().equals(cdz.getSzcs())) {
|
if (srgv.getCurrFloor()==1) {
|
||||||
//生成四向小车充电队列
|
//生成四向小车充电队列
|
||||||
String chargingSite = srgvChargingJob.getChargingSite();//充电桩站点
|
String chargingSite = srgvChargingJob.getChargingSite();//充电桩站点
|
||||||
WcsSrgvQueue wcsSrgvQueueParam = new WcsSrgvQueue();
|
WcsSrgvQueue wcsSrgvQueueParam = new WcsSrgvQueue();
|
||||||
@@ -209,7 +214,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
WcsSrgvQueue wcsSrgvQueue = new WcsSrgvQueue();
|
WcsSrgvQueue wcsSrgvQueue = new WcsSrgvQueue();
|
||||||
wcsSrgvQueue.setGuid(UUID.randomUUID().toString());
|
wcsSrgvQueue.setGuid(UUID.randomUUID().toString());
|
||||||
wcsSrgvQueue.setTaskNo(taskNo);
|
wcsSrgvQueue.setTaskNo(taskNo);
|
||||||
wcsSrgvQueue.setTaskType("3");
|
wcsSrgvQueue.setTaskType(type);
|
||||||
wcsSrgvQueue.setPriority(Long.parseLong("2"));
|
wcsSrgvQueue.setPriority(Long.parseLong("2"));
|
||||||
wcsSrgvQueue.setCargo("0");
|
wcsSrgvQueue.setCargo("0");
|
||||||
wcsSrgvQueue.setIssued("0");
|
wcsSrgvQueue.setIssued("0");
|
||||||
@@ -220,14 +225,15 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
WcsSrgvMap wcsSrgvMap = wcsSrgvMapService.selectWcsSrgvMapBySiteId(chargingSite);
|
WcsSrgvMap wcsSrgvMap = wcsSrgvMapService.selectWcsSrgvMapBySiteId(chargingSite);
|
||||||
if ("8".equals(type)) {
|
if ("8".equals(type)) {
|
||||||
wcsSrgvQueue.setEndSite("tsj");
|
wcsSrgvQueue.setEndSite("tsj");
|
||||||
|
wcsSrgvQueue.setDefault03("040601");
|
||||||
} else if ("3".equals(type)) {
|
} else if ("3".equals(type)) {
|
||||||
wcsSrgvQueue.setEndSite(chargingSite);
|
wcsSrgvQueue.setEndSite(chargingSite);
|
||||||
|
wcsSrgvQueue.setDefault03(wcsSrgvQueue.getStartSite());
|
||||||
}
|
}
|
||||||
wcsSrgvQueue.setTheFloor(deviceSrgv.getCurrFloor().toString());
|
wcsSrgvQueue.setTheFloor(deviceSrgv.getCurrFloor().toString());
|
||||||
wcsSrgvQueue.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
wcsSrgvQueue.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
||||||
wcsSrgvQueue.setAgvId(deviceSrgv.getDeviceId().toString());
|
wcsSrgvQueue.setAgvId(deviceSrgv.getDeviceId().toString());
|
||||||
wcsSrgvQueue.setDefault02("3");
|
wcsSrgvQueue.setDefault02("3");
|
||||||
wcsSrgvQueue.setDefault03(wcsSrgvQueue.getStartSite());
|
|
||||||
wcsSrgvQueue.setDefault07(Convert.toStr(wcsSrgvMap.getZ()));
|
wcsSrgvQueue.setDefault07(Convert.toStr(wcsSrgvMap.getZ()));
|
||||||
wcsSagvQueueMapper.insertWcsSrgvQueue(wcsSrgvQueue);
|
wcsSagvQueueMapper.insertWcsSrgvQueue(wcsSrgvQueue);
|
||||||
}
|
}
|
||||||
@@ -252,61 +258,52 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
* 生成入库小车队列
|
* 生成入库小车队列
|
||||||
*/
|
*/
|
||||||
private void createCarQueue(DeviceSrgv deviceSrgv) {
|
private void createCarQueue(DeviceSrgv deviceSrgv) {
|
||||||
|
//充电队列处理
|
||||||
if (deviceSrgv.getWorkMode() == 5 && deviceSrgv.getStatus() == 1) {
|
if (deviceSrgv.getWorkMode() == 5 && deviceSrgv.getStatus() == 1) {
|
||||||
WcsSrgvQueue wcsSrgvQueue = wcsSagvQueueMapper.selectWcsSrgvQueueByAgvId(deviceSrgv.getDeviceId().toString());
|
WcsSrgvQueue wcsSrgvQueue = wcsSagvQueueMapper.selectWcsSrgvQueueByAgvId(deviceSrgv.getDeviceId().toString());
|
||||||
if (wcsSrgvQueue == null) {
|
if (wcsSrgvQueue == null) {
|
||||||
//找小车当前层作业,生成队列
|
List<MydoJob> inMydoJobs = mydoJobService.selectInJobList(deviceSrgv.getCurrFloor().toString());
|
||||||
//如果没有当前层作业,就找最近层换层作业,生成队列
|
//找小车当前层入库作业,生成队列
|
||||||
MydoJob mydoJob1 = new MydoJob();
|
if (!inMydoJobs.isEmpty()) {
|
||||||
mydoJob1.setTheFloor(deviceSrgv.getCurrFloor().toString());
|
//生成了从小车现在位置到提升机接货的队列 更新作业执行阶段为小车搬运
|
||||||
mydoJob1.setInOrOut("1");//货物入库
|
createCarQueue(inMydoJobs.get(0), deviceSrgv, "4", "0");
|
||||||
mydoJob1.setStatus("3");
|
|
||||||
// todo 定提升机到达阶段
|
|
||||||
mydoJob1.setExecutionPhase("3");
|
|
||||||
List<MydoJob> mydoJobs = mydoJobService.selectMydoJobList(mydoJob1);
|
|
||||||
if (mydoJobs.isEmpty()) {
|
|
||||||
mydoJob1.setInOrOut("3");//空托盘入库
|
|
||||||
mydoJobs = mydoJobService.selectMydoJobList(mydoJob1);
|
|
||||||
}
|
|
||||||
if (!mydoJobs.isEmpty()) {
|
|
||||||
//生成了从小车现在位置到提升机接货的队列
|
|
||||||
createCarQueue(mydoJobs.get(0), deviceSrgv, "4", "0");
|
|
||||||
} else {
|
} else {
|
||||||
List<MydoJob> mydoJobs1 = mydoJobService.selectOutJobList(deviceSrgv.getCurrFloor().toString());
|
//找小车当前层出库作业,生成队列
|
||||||
|
List<MydoJob> outMydoJobs = mydoJobService.selectOutJobList(deviceSrgv.getCurrFloor().toString());
|
||||||
//当前层出库作业
|
//当前层出库作业
|
||||||
if (!mydoJobs1.isEmpty()) {
|
if (!outMydoJobs.isEmpty()) {
|
||||||
//找最外层作业存储过程
|
//找最外层作业存储过程
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
map.put("v_layer", deviceSrgv.getCurrFloor());
|
map.put("v_layer", deviceSrgv.getCurrFloor());
|
||||||
mydoJobService.selectMydoJobOutside(map);
|
mydoJobService.selectMydoJobOutside(map);
|
||||||
String jobId = map.get("v_job_ids").toString();
|
String jobId = map.get("v_job_ids").toString();
|
||||||
MydoJob mydoJob2 = mydoJobService.selectMydoJobByJobId(jobId);
|
MydoJob mydoJob = mydoJobService.selectMydoJobByJobId(jobId);
|
||||||
//判断小车当前点是否是出库作业货位点,如果不是,就生成队列{},如果是生成已下发队列
|
//判断小车当前点是否是出库作业货位点,如果不是,就生成队列{},如果是生成已下发队列
|
||||||
WcsSrgvMap wcsSrgvMap = new WcsSrgvMap();
|
WcsSrgvMap wcsSrgvMap = new WcsSrgvMap();
|
||||||
wcsSrgvMap.setCargoSpaceId(mydoJob2.getCargoSpaceId());
|
wcsSrgvMap.setCargoSpaceId(mydoJob.getCargoSpaceId());
|
||||||
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap);
|
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap);
|
||||||
if (!deviceSrgv.getCurrSite().equals(wcsSrgvMaps.get(0).getSiteId())) {
|
if (!deviceSrgv.getCurrSite().equals(wcsSrgvMaps.get(0).getSiteId())) {
|
||||||
createCarQueue(mydoJob2, deviceSrgv, "4", "0");
|
createCarQueue(mydoJob, deviceSrgv, "4", "0");
|
||||||
} else {
|
} else {
|
||||||
createCarQueue(mydoJob2, deviceSrgv, "4", "1");
|
createCarQueue(mydoJob, deviceSrgv, "4", "1");
|
||||||
}
|
}
|
||||||
mydoJob2.setStatus("3");
|
mydoJob.setStatus("3");//更新小车出库作业状态为正执行
|
||||||
mydoJobService.updateMydoJob(mydoJob2);
|
mydoJobService.updateMydoJob(mydoJob);
|
||||||
} else {
|
} else {
|
||||||
//别的层的出库作业和入库作业
|
//别的层的出库作业和入库作业
|
||||||
MydoJob job = null;
|
MydoJob job = null;
|
||||||
MydoJob mydoJob3 = new MydoJob();
|
MydoJob mydoJob3 = new MydoJob();
|
||||||
mydoJob3.setStatus("3");
|
|
||||||
mydoJob3.setInOut("1");
|
mydoJob3.setInOut("1");
|
||||||
|
mydoJob3.setStatus("3");
|
||||||
//todo 输送机阶段
|
//todo 输送机阶段
|
||||||
|
|
||||||
mydoJob3.setExecutionPhase("1");
|
mydoJob3.setExecutionPhase("1");
|
||||||
List<MydoJob> mydoJobs4 = mydoJobService.selectMydoJobList(mydoJob3);
|
List<MydoJob> mydoJobs4 = mydoJobService.selectMydoJobList(mydoJob3);
|
||||||
if (!mydoJobs4.isEmpty()) {
|
if (!mydoJobs4.isEmpty()) {
|
||||||
job = mydoJobs4.get(0);
|
job = mydoJobs4.get(0);
|
||||||
} else {
|
} else {
|
||||||
MydoJob mydoJob2 = new MydoJob();
|
MydoJob mydoJob2 = new MydoJob();
|
||||||
mydoJob2.setInOut("2");
|
mydoJob3.setInOut("2");
|
||||||
mydoJob2.setStatus("1");
|
mydoJob2.setStatus("1");
|
||||||
List<MydoJob> mydoJobs3 = mydoJobService.selectMydoJobList(mydoJob2);
|
List<MydoJob> mydoJobs3 = mydoJobService.selectMydoJobList(mydoJob2);
|
||||||
if (!mydoJobs3.isEmpty()) {
|
if (!mydoJobs3.isEmpty()) {
|
||||||
@@ -337,6 +334,12 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
if ("1".equals(wcsSrgvQueue.getIssued())) {
|
if ("1".equals(wcsSrgvQueue.getIssued())) {
|
||||||
|
if (wcsSrgvQueue.getDefault08()!=null&&wcsSrgvQueue.getDefault08().equals("1")){
|
||||||
|
if (deviceSrgv.getCurrSite().equals(wcsSrgvQueue.getEndSite()) && "4".equals(wcsSrgvQueue.getTaskType())){
|
||||||
|
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
||||||
|
wcsSagvQueueMapper.deleteWcsSrgvQueueByGuid(wcsSrgvQueue.getGuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
MydoJob mydoJob = mydoJobService.selectMydoJobByTaskNo(Convert.toLong(wcsSrgvQueue.getTaskNo()));
|
MydoJob mydoJob = mydoJobService.selectMydoJobByTaskNo(Convert.toLong(wcsSrgvQueue.getTaskNo()));
|
||||||
if (mydoJob != null) {
|
if (mydoJob != null) {
|
||||||
if (deviceSrgv.getCurrSite().equals(wcsSrgvQueue.getEndSite()) && "1".equals(wcsSrgvQueue.getTaskType())) {
|
if (deviceSrgv.getCurrSite().equals(wcsSrgvQueue.getEndSite()) && "1".equals(wcsSrgvQueue.getTaskType())) {
|
||||||
@@ -366,14 +369,14 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
//根据任务类型 ,生成队列
|
//根据任务类型 ,生成队列
|
||||||
if (Convert.toInt(mydoJob.getInOrOut()) < 20) {
|
if (Convert.toInt(mydoJob.getInOrOut()) < 20) {
|
||||||
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
||||||
wcsSagvQueueMapper.deleteWcsSrgvQueueByGuid(wcsSrgvQueue.getGuid());
|
|
||||||
createCarQueue(mydoJob, deviceSrgv, "1", "0");
|
createCarQueue(mydoJob, deviceSrgv, "1", "0");
|
||||||
|
wcsSagvQueueMapper.deleteWcsSrgvQueueByGuid(wcsSrgvQueue.getGuid());
|
||||||
} else {
|
} else {
|
||||||
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
||||||
|
createCarQueue(mydoJob, deviceSrgv, "2", "0");
|
||||||
wcsSagvQueueMapper.deleteWcsSrgvQueueByGuid(wcsSrgvQueue.getGuid());
|
wcsSagvQueueMapper.deleteWcsSrgvQueueByGuid(wcsSrgvQueue.getGuid());
|
||||||
mydoJob.setStatus("3");//作业修改为正执行
|
mydoJob.setStatus("3");//作业修改为正执行
|
||||||
mydoJobService.updateMydoJob(mydoJob);
|
mydoJobService.updateMydoJob(mydoJob);
|
||||||
createCarQueue(mydoJob, deviceSrgv, "2", "0");
|
|
||||||
}
|
}
|
||||||
} else if (deviceSrgv.getCurrSite().equals(wcsSrgvQueue.getDefault03()) && "8".equals(wcsSrgvQueue.getTaskType())) {
|
} else if (deviceSrgv.getCurrSite().equals(wcsSrgvQueue.getDefault03()) && "8".equals(wcsSrgvQueue.getTaskType())) {
|
||||||
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
||||||
@@ -401,6 +404,25 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
deviceCdzService.updateDeviceCdz(deviceCdz1);
|
deviceCdzService.updateDeviceCdz(deviceCdz1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
srgvChargingJob.setAgvId(String.valueOf(wcsSrgvQueue.getAgvId()));
|
||||||
|
srgvChargingJob.setTaskNo(wcsSrgvQueue.getTaskNo());
|
||||||
|
srgvChargingJob.setJobStatus("1");
|
||||||
|
srgvChargingJob.setJobType("1");
|
||||||
|
List<SrgvChargingJob> srgvChargingJobs1 = srgvChargingJobMapper.selectSrgvChargingJobList(srgvChargingJob);
|
||||||
|
if (!srgvChargingJobs1.isEmpty()) {
|
||||||
|
SrgvChargingJob srgvChargingJob1 = srgvChargingJobs1.get(0);
|
||||||
|
if (deviceSrgv.getCurrSite().equals(wcsSrgvQueue.getDefault03()) && "8".equals(wcsSrgvQueue.getTaskType())) {
|
||||||
|
wcsSagvQueueMapper.insertHistory(wcsSrgvQueue.getTaskNo());
|
||||||
|
wcsSagvQueueMapper.deleteWcsSrgvQueueByGuid(wcsSrgvQueue.getGuid());
|
||||||
|
// srgvChargingJob1.setJobStatus("4");
|
||||||
|
// srgvChargingJobMapper.updateSrgvChargingJob(srgvChargingJob1);
|
||||||
|
// DeviceCdz deviceCdz = new DeviceCdz();
|
||||||
|
// DeviceCdz deviceCdz1 = deviceCdzService.selectDeviceCdzById(1L);
|
||||||
|
// deviceCdz1.setSpare1(String.valueOf(deviceSrgv.getDeviceId()));
|
||||||
|
// deviceCdzService.updateDeviceCdz(deviceCdz1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,18 +440,19 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
WcsSrgvMap wcsSrgvMap1 = new WcsSrgvMap();
|
WcsSrgvMap wcsSrgvMap1 = new WcsSrgvMap();
|
||||||
//TODO 小车取货之后会不会退出来,会退出来是4 不会退出来是3
|
//TODO 小车取货之后会不会退出来,会退出来是4 不会退出来是3
|
||||||
wcsSrgvMap1.setTheRow(4);
|
wcsSrgvMap1.setTheRow(4);
|
||||||
wcsSrgvMap1.setTheColumn(5);
|
wcsSrgvMap1.setTheColumn(6);
|
||||||
wcsSrgvMap1.setTheLayer(Convert.toInt(mydoJob1.getTheFloor()));
|
wcsSrgvMap1.setTheLayer(Convert.toInt(mydoJob1.getTheFloor()));
|
||||||
List<WcsSrgvMap> wcsSrgvMaps1 = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap1);
|
List<WcsSrgvMap> wcsSrgvMaps1 = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap1);
|
||||||
//点到点任务
|
//点到点任务
|
||||||
if (Integer.parseInt(mydoJob1.getInOrOut()) < 20 && "4".equals(taskType)) {
|
if (Integer.parseInt(mydoJob1.getInOrOut()) < 20 && "4".equals(taskType)) {
|
||||||
wcsSrgvQueue.setStartSite(deviceSrgv.getCurrSite());
|
wcsSrgvQueue.setStartSite(deviceSrgv.getCurrSite());
|
||||||
wcsSrgvQueue.setEndSite("tsj");
|
wcsSrgvQueue.setEndSite("tsj");
|
||||||
//入库的点到点直接进入提升机 不选停靠点 default03 是0305
|
//入库的点到点直接进入提升机 不选停靠点 default03 是0306
|
||||||
wcsSrgvMap1.setTheRow(3);
|
wcsSrgvMap1.setTheRow(3);
|
||||||
wcsSrgvMap1.setTheColumn(5);
|
wcsSrgvMap1.setTheColumn(6);
|
||||||
wcsSrgvMap1.setTheLayer(Convert.toInt(mydoJob1.getTheFloor()));
|
wcsSrgvMap1.setTheLayer(Convert.toInt(mydoJob1.getTheFloor()));
|
||||||
wcsSrgvMaps1 = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap1);
|
wcsSrgvMaps1 = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap1);
|
||||||
|
wcsSrgvQueue.setCargoPickSite("tsj");
|
||||||
wcsSrgvQueue.setDefault03(wcsSrgvMaps1.get(0).getSiteId());
|
wcsSrgvQueue.setDefault03(wcsSrgvMaps1.get(0).getSiteId());
|
||||||
} else if (Integer.parseInt(mydoJob1.getInOrOut()) < 20 && "1".equals(taskType)) {
|
} else if (Integer.parseInt(mydoJob1.getInOrOut()) < 20 && "1".equals(taskType)) {
|
||||||
wcsSrgvQueue.setStartSite("tsj");
|
wcsSrgvQueue.setStartSite("tsj");
|
||||||
@@ -437,9 +460,9 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
wcsSrgvMap.setCargoSpaceId(mydoJob1.getCargoSpaceId());
|
wcsSrgvMap.setCargoSpaceId(mydoJob1.getCargoSpaceId());
|
||||||
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap);
|
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap);
|
||||||
wcsSrgvQueue.setEndSite(wcsSrgvMaps.get(0).getSiteId());
|
wcsSrgvQueue.setEndSite(wcsSrgvMaps.get(0).getSiteId());
|
||||||
//入库的点到点从030501 到目标货位
|
//入库的点到点从030601 到目标货位
|
||||||
wcsSrgvMap1.setTheRow(3);
|
wcsSrgvMap1.setTheRow(3);
|
||||||
wcsSrgvMap1.setTheColumn(5);
|
wcsSrgvMap1.setTheColumn(6);
|
||||||
wcsSrgvMap1.setTheLayer(Convert.toInt(mydoJob1.getTheFloor()));
|
wcsSrgvMap1.setTheLayer(Convert.toInt(mydoJob1.getTheFloor()));
|
||||||
wcsSrgvMaps1 = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap1);
|
wcsSrgvMaps1 = wcsSrgvMapService.selectWcsSrgvMapList(wcsSrgvMap1);
|
||||||
wcsSrgvQueue.setDefault03(wcsSrgvMaps1.get(0).getSiteId());
|
wcsSrgvQueue.setDefault03(wcsSrgvMaps1.get(0).getSiteId());
|
||||||
@@ -494,7 +517,6 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
&& deviceSrgv.getAllowSend() == 1 //允许下发
|
&& deviceSrgv.getAllowSend() == 1 //允许下发
|
||||||
) {
|
) {
|
||||||
//处理tsj站点 换层去提升机前 入库去提升机里 出库去提升机里
|
//处理tsj站点 换层去提升机前 入库去提升机里 出库去提升机里
|
||||||
|
|
||||||
String startSite = getSite(wcsSrgvQueue.getStartSite(), wcsSrgvQueue.getTheFloor(), wcsSrgvQueue.getTaskType());
|
String startSite = getSite(wcsSrgvQueue.getStartSite(), wcsSrgvQueue.getTheFloor(), wcsSrgvQueue.getTaskType());
|
||||||
String endSite = getSite(wcsSrgvQueue.getEndSite(), wcsSrgvQueue.getTheFloor(), wcsSrgvQueue.getTaskType());
|
String endSite = getSite(wcsSrgvQueue.getEndSite(), wcsSrgvQueue.getTheFloor(), wcsSrgvQueue.getTaskType());
|
||||||
String currSite = deviceSrgv.getCurrSite();
|
String currSite = deviceSrgv.getCurrSite();
|
||||||
@@ -511,7 +533,6 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -530,6 +551,460 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
|
|
||||||
//判断是否能规划出最短路径
|
//判断是否能规划出最短路径
|
||||||
if (shortestPath == null || shortestPath.isEmpty()) {
|
if (shortestPath == null || shortestPath.isEmpty()) {
|
||||||
|
// =========================================================
|
||||||
|
// 特殊优先策略:若目标点被其他小车占用,直接调度占用车到缓存点
|
||||||
|
// 场景示例:1号车目标为 040701,但 2号车正停在 040701
|
||||||
|
// 处理思路:不等待、不绕行,直接把占用目标点的小车移开
|
||||||
|
// =========================================================
|
||||||
|
try {
|
||||||
|
// 查找占用目标点的阻挡车(排除当前车)
|
||||||
|
String endBlockAgv = null;
|
||||||
|
DeviceSrgv endBlockDevice = null;
|
||||||
|
for (Map.Entry<String, DeviceSrgv> entry : PlcSrgvRead.deviceSrgvMap.entrySet()) {
|
||||||
|
DeviceSrgv other = entry.getValue();
|
||||||
|
if (other == null) continue;
|
||||||
|
if (Objects.equals(other.getCurrSite(), endSite)
|
||||||
|
&& !Objects.equals(Convert.toStr(deviceSrgv.getDeviceId()), entry.getKey())) {
|
||||||
|
endBlockAgv = entry.getKey();
|
||||||
|
endBlockDevice = other;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WcsSrgvQueue wcsSrgvQueue1 =new WcsSrgvQueue();
|
||||||
|
wcsSrgvQueue1.setAgvId(endBlockAgv);
|
||||||
|
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(wcsSrgvQueue1);
|
||||||
|
if (endBlockDevice != null&&wcsSrgvQueues.isEmpty()) {
|
||||||
|
// 选择当前层最近且可达的缓存点(避让点)
|
||||||
|
WcsSrgvMap cacheParam = new WcsSrgvMap();
|
||||||
|
cacheParam.setRemark("cache");
|
||||||
|
cacheParam.setTheLayer(floor);
|
||||||
|
List<WcsSrgvMap> cacheMaps = wcsSrgvMapService.selectWcsSrgvMapList(cacheParam);
|
||||||
|
// 生成阻挡车的避让任务(点到点,高优先级,未下发)
|
||||||
|
WcsSrgvQueue taskB = new WcsSrgvQueue();
|
||||||
|
taskB.setGuid(UUID.randomUUID().toString());
|
||||||
|
// 生成纯数字任务号(PLC要求),9 + HHmmss
|
||||||
|
taskB.setTaskNo(String.valueOf(taskCache));
|
||||||
|
taskB.setAgvId(endBlockAgv);
|
||||||
|
taskB.setTaskType("4"); // 点到点移动
|
||||||
|
taskB.setDefault02("4"); // 业务类型标识为点到点
|
||||||
|
taskB.setPriority(9L); // 高优先级,尽快避让
|
||||||
|
taskB.setIssued("0"); // 未下发
|
||||||
|
taskB.setExecutionStatus("1");// 初始状态
|
||||||
|
taskB.setStartSite(endBlockDevice.getCurrSite());
|
||||||
|
taskB.setEndSite("050501");
|
||||||
|
taskB.setTheFloor(floor.toString());
|
||||||
|
taskB.setDefault03(endBlockDevice.getCurrSite());
|
||||||
|
taskB.setDefault07(floor.toString());
|
||||||
|
taskB.setDefault08("1");//避让任务,直接完成
|
||||||
|
taskB.setCreateDate(DateUtil.now());
|
||||||
|
wcsSagvQueueMapper.insertWcsSrgvQueue(taskB);
|
||||||
|
taskCache++;
|
||||||
|
log.info("目标点 {} 被小车 {} 占用,已调度其前往避让点 {}", endSite, endBlockAgv, "050501");
|
||||||
|
// 当前车等待下一轮调度(待阻挡车移开后自然可达)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
log.warn("目标点 {} 被小车 {} 占用,但无可用避让点", endSite, endBlockAgv);
|
||||||
|
// 无法直接移开阻挡车,后续进入常规策略(寻找阻挡者或自身避让)
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("终点占用直接避让策略执行异常", e);
|
||||||
|
}
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// 策略1:尝试调度阻挡车避让 (新增逻辑)
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
try {
|
||||||
|
// 1. 获取纯净静态地图 (不含动态障碍物)
|
||||||
|
int[][] staticMap = new int[29][16];
|
||||||
|
for (WcsSrgvMap site : arrByRoadSite.values()) {
|
||||||
|
if (site.getX() != null && site.getY() != null) {
|
||||||
|
staticMap[site.getX()][site.getY()] = site.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. 规划理想路径 (忽略其他小车)
|
||||||
|
int sx = arrByRoadSite.get(startSite).getX();
|
||||||
|
int sy = arrByRoadSite.get(startSite).getY();
|
||||||
|
int ex = arrByRoadSite.get(endSite).getX();
|
||||||
|
int ey = arrByRoadSite.get(endSite).getY();
|
||||||
|
staticMap[sx][sy] = 2;
|
||||||
|
staticMap[ex][ey] = 2;
|
||||||
|
List<int[]> idealPath = PathFinder.findShortestPath(
|
||||||
|
staticMap,
|
||||||
|
sx, sy,
|
||||||
|
ex, ey
|
||||||
|
);
|
||||||
|
// 3. 寻找阻挡车
|
||||||
|
String blockingAgv = null;
|
||||||
|
if (idealPath == null || idealPath.isEmpty()) {
|
||||||
|
log.warn("理想路径为空,sx={},sy={},ex={},ey={},startVal={},endVal={}",
|
||||||
|
sx, sy, ex, ey, staticMap[sx][sy], staticMap[ex][ey]);
|
||||||
|
}
|
||||||
|
if (idealPath != null && !idealPath.isEmpty()) {
|
||||||
|
for (int[] point : idealPath) {
|
||||||
|
// 通过坐标反查站点 (简单遍历)
|
||||||
|
// 注意:这里假设同一层坐标唯一
|
||||||
|
String pointSiteId = null;
|
||||||
|
for (Map.Entry<String, WcsSrgvMap> entry : arrByRoadSite.entrySet()) {
|
||||||
|
WcsSrgvMap s = entry.getValue();
|
||||||
|
if (s.getX() == point[0] && s.getY() == point[1]) {
|
||||||
|
pointSiteId = s.getSiteId();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointSiteId != null) {
|
||||||
|
// 检查是否有其他车在这个点
|
||||||
|
for (Map.Entry<String, DeviceSrgv> entry : PlcSrgvRead.deviceSrgvMap.entrySet()) {
|
||||||
|
String otherAgvCode = entry.getKey();
|
||||||
|
DeviceSrgv otherAgv = entry.getValue();
|
||||||
|
|
||||||
|
if (!otherAgvCode.equals(wcsSrgvQueue.getAgvId()) && // 不是自己
|
||||||
|
pointSiteId.equals(otherAgv.getCurrSite())) { // 是别人
|
||||||
|
|
||||||
|
blockingAgv = otherAgvCode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blockingAgv != null) break; // 找到第一个阻挡者即可
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 调度阻挡车
|
||||||
|
if (blockingAgv != null) {
|
||||||
|
log.info("发现阻挡车: {}, 尝试调度避让", blockingAgv);
|
||||||
|
|
||||||
|
// 检查 B 是否忙碌 (是否有未完成任务)
|
||||||
|
WcsSrgvQueue blockingParam = new WcsSrgvQueue();
|
||||||
|
blockingParam.setAgvId(blockingAgv); // 注意:这里用 AgvId 还是 SrgvCode 需要确认,假设是一致的
|
||||||
|
// 通常数据库存的是 ID,这里 blockingAgv 来自 deviceSrgvMap 的 key,通常是 code
|
||||||
|
// 如果 code != id,需要转换。假设 code 就是 id。
|
||||||
|
|
||||||
|
List<WcsSrgvQueue> tasks = wcsSagvQueueMapper.selectWcsSrgvQueueList(blockingParam);
|
||||||
|
boolean isBusy = CollUtil.isNotEmpty(tasks);
|
||||||
|
// 这里简化判断:只要有队列记录就算忙。更精细的判断可以看 status。
|
||||||
|
|
||||||
|
if (isBusy) {
|
||||||
|
log.info("阻挡车 {} 正在执行任务,当前车 {} 等待", blockingAgv, wcsSrgvQueue.getAgvId());
|
||||||
|
return false; // B 忙,A 等待 (不做任何操作,下一轮循环再试)
|
||||||
|
} else {
|
||||||
|
// B 空闲,寻找避让点
|
||||||
|
// 获取当前层所有避让点
|
||||||
|
WcsSrgvMap cacheParam = new WcsSrgvMap();
|
||||||
|
cacheParam.setRemark("cache");
|
||||||
|
cacheParam.setTheLayer(floor);
|
||||||
|
List<WcsSrgvMap> cacheMaps = wcsSrgvMapService.selectWcsSrgvMapList(cacheParam);
|
||||||
|
|
||||||
|
// 获取所有小车位置 (用于避让点占用检查)
|
||||||
|
Set<String> occupiedSites = new HashSet<>();
|
||||||
|
for (DeviceSrgv d : PlcSrgvRead.deviceSrgvMap.values()) {
|
||||||
|
occupiedSites.add(d.getCurrSite());
|
||||||
|
}
|
||||||
|
|
||||||
|
String bestCacheForB = null;
|
||||||
|
int minLenForB = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
DeviceSrgv deviceB = PlcSrgvRead.deviceSrgvMap.get(blockingAgv);
|
||||||
|
if (deviceB != null) {
|
||||||
|
WcsSrgvMap startNodeB = arrByRoadSite.get(deviceB.getCurrSite());
|
||||||
|
|
||||||
|
for (WcsSrgvMap cache : cacheMaps) {
|
||||||
|
String siteId = cache.getSiteId();
|
||||||
|
if (occupiedSites.contains(siteId)) continue; // 已被占
|
||||||
|
|
||||||
|
// 关键:避让点不能在 A 的理想路径上
|
||||||
|
boolean onIdealPath = false;
|
||||||
|
for (int[] p : idealPath) {
|
||||||
|
if (p[0] == cache.getX() && p[1] == cache.getY()) {
|
||||||
|
onIdealPath = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (onIdealPath) continue;
|
||||||
|
|
||||||
|
// 检查 B 到避让点的可达性 (在静态地图上即可,因为其他车可能就是 A)
|
||||||
|
// 此时 A 还没动,所以 B 应该能动。
|
||||||
|
// 为了安全,还是用 emptyMap (含 A) 检查 B 的路径?
|
||||||
|
// 不,用 emptyMap 检查 B 的路径,因为 A 还在原位。
|
||||||
|
if (startNodeB != null && cache.getX() != null && cache.getY() != null) {
|
||||||
|
List<int[]> pathB = PathFinder.findShortestPath(emptyMap,
|
||||||
|
startNodeB.getX(), startNodeB.getY(),
|
||||||
|
cache.getX(), cache.getY());
|
||||||
|
|
||||||
|
if (pathB != null && !pathB.isEmpty() && pathB.size() < minLenForB) {
|
||||||
|
minLenForB = pathB.size();
|
||||||
|
bestCacheForB = siteId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestCacheForB != null) {
|
||||||
|
// 生成 B 的避让任务
|
||||||
|
WcsSrgvQueue taskB = new WcsSrgvQueue();
|
||||||
|
taskB.setGuid(UUID.randomUUID().toString());
|
||||||
|
// 生成纯数字任务号,避免 PLC 解析错误
|
||||||
|
// 格式:9 + HHmmss + 随机位 (防止重复)
|
||||||
|
String timeStr = DateUtil.format(new Date(), "HHmmss");
|
||||||
|
taskB.setTaskNo(String.valueOf(taskCache));
|
||||||
|
taskB.setAgvId(blockingAgv);
|
||||||
|
taskB.setTaskType("4"); // 点到点
|
||||||
|
taskB.setPriority(9L); // 高优先级
|
||||||
|
taskB.setIssued("0");
|
||||||
|
taskB.setExecutionStatus("1");
|
||||||
|
taskB.setStartSite(deviceB.getCurrSite());
|
||||||
|
taskB.setEndSite(bestCacheForB);
|
||||||
|
taskB.setTheFloor(floor.toString());
|
||||||
|
taskB.setCreateDate(DateUtil.now());
|
||||||
|
taskB.setDefault02("4");
|
||||||
|
taskB.setDefault03(deviceB.getCurrSite()); // 默认值填充
|
||||||
|
taskB.setDefault07(floor.toString());
|
||||||
|
taskB.setDefault08("1");
|
||||||
|
wcsSagvQueueMapper.insertWcsSrgvQueue(taskB);
|
||||||
|
taskCache++;
|
||||||
|
log.info("成功调度阻挡车 {} 前往避让点 {}", blockingAgv, bestCacheForB);
|
||||||
|
return false; // A 等待
|
||||||
|
} else {
|
||||||
|
log.warn("阻挡车 {} 无可用避让点", blockingAgv);
|
||||||
|
// Fallback to Strategy 2 (A moves)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("调度阻挡车避让逻辑异常", e);
|
||||||
|
// Fallback to Strategy 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// 策略2:自己避让 (原有逻辑)
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// =========================================================
|
||||||
|
// 特殊优先策略:若目标点被其他小车占用,直接调度占用车到缓存点
|
||||||
|
// 场景示例:1号车目标为 040701,但 2号车正停在 040701
|
||||||
|
// 处理思路:不等待、不绕行,直接把占用目标点的小车移开
|
||||||
|
// =========================================================
|
||||||
|
try {
|
||||||
|
// 查找占用目标点的阻挡车(排除当前车)
|
||||||
|
String endBlockAgv = null;
|
||||||
|
DeviceSrgv endBlockDevice = null;
|
||||||
|
for (Map.Entry<String, DeviceSrgv> entry : PlcSrgvRead.deviceSrgvMap.entrySet()) {
|
||||||
|
DeviceSrgv other = entry.getValue();
|
||||||
|
if (other == null) continue;
|
||||||
|
if (Objects.equals(other.getCurrSite(), endSite)
|
||||||
|
&& !Objects.equals(Convert.toStr(deviceSrgv.getDeviceId()), entry.getKey())) {
|
||||||
|
endBlockAgv = entry.getKey();
|
||||||
|
endBlockDevice = other;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WcsSrgvQueue wcsSrgvQueue1 =new WcsSrgvQueue();
|
||||||
|
wcsSrgvQueue1.setAgvId(endBlockAgv);
|
||||||
|
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(wcsSrgvQueue1);
|
||||||
|
if (endBlockDevice != null&&wcsSrgvQueues.isEmpty()) {
|
||||||
|
// 选择当前层最近且可达的缓存点(避让点)
|
||||||
|
WcsSrgvMap cacheParam = new WcsSrgvMap();
|
||||||
|
cacheParam.setRemark("cache");
|
||||||
|
cacheParam.setTheLayer(floor);
|
||||||
|
List<WcsSrgvMap> cacheMaps = wcsSrgvMapService.selectWcsSrgvMapList(cacheParam);
|
||||||
|
// 生成阻挡车的避让任务(点到点,高优先级,未下发)
|
||||||
|
WcsSrgvQueue taskB = new WcsSrgvQueue();
|
||||||
|
taskB.setGuid(UUID.randomUUID().toString());
|
||||||
|
// 生成纯数字任务号(PLC要求),9 + HHmmss
|
||||||
|
taskB.setTaskNo(String.valueOf(taskCache));
|
||||||
|
taskB.setAgvId(endBlockAgv);
|
||||||
|
taskB.setTaskType("4"); // 点到点移动
|
||||||
|
taskB.setDefault02("4"); // 业务类型标识为点到点
|
||||||
|
taskB.setPriority(9L); // 高优先级,尽快避让
|
||||||
|
taskB.setIssued("0"); // 未下发
|
||||||
|
taskB.setExecutionStatus("1");// 初始状态
|
||||||
|
taskB.setStartSite(endBlockDevice.getCurrSite());
|
||||||
|
taskB.setEndSite("050501");
|
||||||
|
taskB.setTheFloor(floor.toString());
|
||||||
|
taskB.setDefault03(endBlockDevice.getCurrSite());
|
||||||
|
taskB.setDefault07(floor.toString());
|
||||||
|
taskB.setDefault08("1");//避让任务,直接完成
|
||||||
|
taskB.setCreateDate(DateUtil.now());
|
||||||
|
wcsSagvQueueMapper.insertWcsSrgvQueue(taskB);
|
||||||
|
taskCache++;
|
||||||
|
log.info("目标点 {} 被小车 {} 占用,已调度其前往避让点 {}", endSite, endBlockAgv, "050501");
|
||||||
|
// 当前车等待下一轮调度(待阻挡车移开后自然可达)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
log.warn("目标点 {} 被小车 {} 占用,但无可用避让点", endSite, endBlockAgv);
|
||||||
|
// 无法直接移开阻挡车,后续进入常规策略(寻找阻挡者或自身避让)
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("终点占用直接避让策略执行异常", e);
|
||||||
|
}
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// 策略1:尝试调度阻挡车避让 (新增逻辑)
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
try {
|
||||||
|
// 1. 获取纯净静态地图 (不含动态障碍物)
|
||||||
|
// 重新获取原始地图数据,避免受 handleMap 修改的影响
|
||||||
|
Map<String, WcsSrgvMap> cleanArrByRoadSite = roadCacheService.getArrByRoadSite(floor);
|
||||||
|
int[][] staticMap = new int[29][16];
|
||||||
|
for (WcsSrgvMap site : cleanArrByRoadSite.values()) {
|
||||||
|
if (site.getX() != null && site.getY() != null) {
|
||||||
|
staticMap[site.getX()][site.getY()] = site.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. 规划理想路径 (忽略其他小车)
|
||||||
|
int sx = cleanArrByRoadSite.get(startSite).getX();
|
||||||
|
int sy = cleanArrByRoadSite.get(startSite).getY();
|
||||||
|
int ex = cleanArrByRoadSite.get(endSite).getX();
|
||||||
|
int ey = cleanArrByRoadSite.get(endSite).getY();
|
||||||
|
staticMap[sx][sy] = 2;
|
||||||
|
staticMap[ex][ey] = 2;
|
||||||
|
List<int[]> idealPath = PathFinder.findShortestPath(
|
||||||
|
staticMap,
|
||||||
|
sx, sy,
|
||||||
|
ex, ey
|
||||||
|
);
|
||||||
|
// 3. 寻找阻挡车
|
||||||
|
String blockingAgv = null;
|
||||||
|
if (idealPath == null || idealPath.isEmpty()) {
|
||||||
|
log.warn("理想路径为空,sx={},sy={},ex={},ey={},startVal={},endVal={}",
|
||||||
|
sx, sy, ex, ey, staticMap[sx][sy], staticMap[ex][ey]);
|
||||||
|
}
|
||||||
|
if (idealPath != null && !idealPath.isEmpty()) {
|
||||||
|
for (int[] point : idealPath) {
|
||||||
|
// 通过坐标反查站点 (简单遍历)
|
||||||
|
// 注意:这里假设同一层坐标唯一
|
||||||
|
String pointSiteId = null;
|
||||||
|
for (Map.Entry<String, WcsSrgvMap> entry : arrByRoadSite.entrySet()) {
|
||||||
|
WcsSrgvMap s = entry.getValue();
|
||||||
|
if (s.getX() == point[0] && s.getY() == point[1]) {
|
||||||
|
pointSiteId = s.getSiteId();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointSiteId != null) {
|
||||||
|
// 检查是否有其他车在这个点
|
||||||
|
for (Map.Entry<String, DeviceSrgv> entry : PlcSrgvRead.deviceSrgvMap.entrySet()) {
|
||||||
|
String otherAgvCode = entry.getKey();
|
||||||
|
DeviceSrgv otherAgv = entry.getValue();
|
||||||
|
|
||||||
|
if (!otherAgvCode.equals(wcsSrgvQueue.getAgvId()) && // 不是自己
|
||||||
|
pointSiteId.equals(otherAgv.getCurrSite())) { // 是别人
|
||||||
|
|
||||||
|
blockingAgv = otherAgvCode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blockingAgv != null) break; // 找到第一个阻挡者即可
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 调度阻挡车
|
||||||
|
if (blockingAgv != null) {
|
||||||
|
log.info("发现阻挡车: {}, 尝试调度避让", blockingAgv);
|
||||||
|
|
||||||
|
// 检查 B 是否忙碌 (是否有未完成任务)
|
||||||
|
WcsSrgvQueue blockingParam = new WcsSrgvQueue();
|
||||||
|
blockingParam.setAgvId(blockingAgv); // 注意:这里用 AgvId 还是 SrgvCode 需要确认,假设是一致的
|
||||||
|
// 通常数据库存的是 ID,这里 blockingAgv 来自 deviceSrgvMap 的 key,通常是 code
|
||||||
|
// 如果 code != id,需要转换。假设 code 就是 id。
|
||||||
|
|
||||||
|
List<WcsSrgvQueue> tasks = wcsSagvQueueMapper.selectWcsSrgvQueueList(blockingParam);
|
||||||
|
boolean isBusy = CollUtil.isNotEmpty(tasks);
|
||||||
|
// 这里简化判断:只要有队列记录就算忙。更精细的判断可以看 status。
|
||||||
|
|
||||||
|
if (isBusy) {
|
||||||
|
log.info("阻挡车 {} 正在执行任务,当前车 {} 等待", blockingAgv, wcsSrgvQueue.getAgvId());
|
||||||
|
return false; // B 忙,A 等待 (不做任何操作,下一轮循环再试)
|
||||||
|
} else {
|
||||||
|
// B 空闲,寻找避让点
|
||||||
|
// 获取当前层所有避让点
|
||||||
|
WcsSrgvMap cacheParam = new WcsSrgvMap();
|
||||||
|
cacheParam.setRemark("cache");
|
||||||
|
cacheParam.setTheLayer(floor);
|
||||||
|
List<WcsSrgvMap> cacheMaps = wcsSrgvMapService.selectWcsSrgvMapList(cacheParam);
|
||||||
|
|
||||||
|
// 获取所有小车位置 (用于避让点占用检查)
|
||||||
|
Set<String> occupiedSites = new HashSet<>();
|
||||||
|
for (DeviceSrgv d : PlcSrgvRead.deviceSrgvMap.values()) {
|
||||||
|
occupiedSites.add(d.getCurrSite());
|
||||||
|
}
|
||||||
|
|
||||||
|
String bestCacheForB = null;
|
||||||
|
int minLenForB = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
DeviceSrgv deviceB = PlcSrgvRead.deviceSrgvMap.get(blockingAgv);
|
||||||
|
if (deviceB != null) {
|
||||||
|
WcsSrgvMap startNodeB = arrByRoadSite.get(deviceB.getCurrSite());
|
||||||
|
|
||||||
|
for (WcsSrgvMap cache : cacheMaps) {
|
||||||
|
String siteId = cache.getSiteId();
|
||||||
|
if (occupiedSites.contains(siteId)) continue; // 已被占
|
||||||
|
|
||||||
|
// 关键:避让点不能在 A 的理想路径上
|
||||||
|
boolean onIdealPath = false;
|
||||||
|
for (int[] p : idealPath) {
|
||||||
|
if (p[0] == cache.getX() && p[1] == cache.getY()) {
|
||||||
|
onIdealPath = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (onIdealPath) continue;
|
||||||
|
|
||||||
|
// 检查 B 到避让点的可达性 (在静态地图上即可,因为其他车可能就是 A)
|
||||||
|
// 此时 A 还没动,所以 B 应该能动。
|
||||||
|
// 为了安全,还是用 emptyMap (含 A) 检查 B 的路径?
|
||||||
|
// 不,用 emptyMap 检查 B 的路径,因为 A 还在原位。
|
||||||
|
if (startNodeB != null && cache.getX() != null && cache.getY() != null) {
|
||||||
|
List<int[]> pathB = PathFinder.findShortestPath(emptyMap,
|
||||||
|
startNodeB.getX(), startNodeB.getY(),
|
||||||
|
cache.getX(), cache.getY());
|
||||||
|
|
||||||
|
if (pathB != null && !pathB.isEmpty() && pathB.size() < minLenForB) {
|
||||||
|
minLenForB = pathB.size();
|
||||||
|
bestCacheForB = siteId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestCacheForB != null) {
|
||||||
|
// 生成 B 的避让任务
|
||||||
|
WcsSrgvQueue taskB = new WcsSrgvQueue();
|
||||||
|
taskB.setGuid(UUID.randomUUID().toString());
|
||||||
|
// 生成纯数字任务号,避免 PLC 解析错误
|
||||||
|
// 格式:9 + HHmmss + 随机位 (防止重复)
|
||||||
|
String timeStr = DateUtil.format(new Date(), "HHmmss");
|
||||||
|
taskB.setTaskNo(String.valueOf(taskCache));
|
||||||
|
taskB.setAgvId(blockingAgv);
|
||||||
|
taskB.setTaskType("4"); // 点到点
|
||||||
|
taskB.setPriority(9L); // 高优先级
|
||||||
|
taskB.setIssued("0");
|
||||||
|
taskB.setExecutionStatus("1");
|
||||||
|
taskB.setStartSite(deviceB.getCurrSite());
|
||||||
|
taskB.setEndSite(bestCacheForB);
|
||||||
|
taskB.setTheFloor(floor.toString());
|
||||||
|
taskB.setCreateDate(DateUtil.now());
|
||||||
|
taskB.setDefault02("4");
|
||||||
|
taskB.setDefault03(deviceB.getCurrSite()); // 默认值填充
|
||||||
|
taskB.setDefault07(floor.toString());
|
||||||
|
taskB.setDefault08("1");
|
||||||
|
wcsSagvQueueMapper.insertWcsSrgvQueue(taskB);
|
||||||
|
taskCache++;
|
||||||
|
log.info("成功调度阻挡车 {} 前往避让点 {}", blockingAgv, bestCacheForB);
|
||||||
|
return false; // A 等待
|
||||||
|
} else {
|
||||||
|
log.warn("阻挡车 {} 无可用避让点", blockingAgv);
|
||||||
|
// Fallback to Strategy 2 (A moves)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("调度阻挡车避让逻辑异常", e);
|
||||||
|
// Fallback to Strategy 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// 策略2:自己避让 (原有逻辑)
|
||||||
|
// ---------------------------------------------------------
|
||||||
//判断是否是1层 空车取货 或者 满车放货
|
//判断是否是1层 空车取货 或者 满车放货
|
||||||
if (floor == 1) {
|
if (floor == 1) {
|
||||||
if ("2".equals(wcsSrgvQueue.getDefault02()) && "tsj".equals(wcsSrgvQueue.getStartSite()) && wcsSrgvQueue.getEndSite().equals(wcsSrgvQueue.getCargoPlaceSite())) {
|
if ("2".equals(wcsSrgvQueue.getDefault02()) && "tsj".equals(wcsSrgvQueue.getStartSite()) && wcsSrgvQueue.getEndSite().equals(wcsSrgvQueue.getCargoPlaceSite())) {
|
||||||
@@ -630,13 +1105,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
if (endSite.equals("tsj")) {
|
if (endSite.equals("tsj")) {
|
||||||
switch (wcsSrgvQueue.getTheFloor()) {
|
switch (wcsSrgvQueue.getTheFloor()) {
|
||||||
case "1":
|
case "1":
|
||||||
endSite = "030501";
|
endSite = "030601";
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "2":
|
||||||
endSite = "030502";
|
endSite = "030602";
|
||||||
break;
|
break;
|
||||||
case "3":
|
case "3":
|
||||||
endSite = "030503";
|
endSite = "030603";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -645,13 +1120,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
if (startSite.equals("tsj")) {
|
if (startSite.equals("tsj")) {
|
||||||
switch (wcsSrgvQueue.getTheFloor()) {
|
switch (wcsSrgvQueue.getTheFloor()) {
|
||||||
case "1":
|
case "1":
|
||||||
startSite = "030501";
|
startSite = "030601";
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "2":
|
||||||
startSite = "030502";
|
startSite = "030602";
|
||||||
break;
|
break;
|
||||||
case "3":
|
case "3":
|
||||||
startSite = "030503";
|
startSite = "030603";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -667,7 +1142,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
} else {
|
} else {
|
||||||
SendData2 path = new SendData2();
|
SendData2 path = new SendData2();
|
||||||
path.setAddress("4004");//地址
|
path.setAddress("4004");//地址
|
||||||
path.setData(startSite + "," + endSite);
|
path.setData(startSite + "," + endSite + ",0,0,0,0,0,0");
|
||||||
path.setType(2);
|
path.setType(2);
|
||||||
sendDataList.add(path);
|
sendDataList.add(path);
|
||||||
}
|
}
|
||||||
@@ -765,6 +1240,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
|
|
||||||
boolean b = true;
|
boolean b = true;
|
||||||
|
|
||||||
|
ScheduleThread scheduleThread = SpringUtils.getBean(ScheduleThread.class);
|
||||||
|
CustomThread<?> ct = scheduleThread.threadMap.get("plcSrgvReadCustomThread" + deviceSrgv.getDeviceId());
|
||||||
|
PlcSrgvRead plcReader = ct != null ? (PlcSrgvRead) ct.getRunnable() : null;
|
||||||
|
if (plcReader == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (SendData2 sendData : sendDataList) {
|
for (SendData2 sendData : sendDataList) {
|
||||||
String address = sendData.getAddress();
|
String address = sendData.getAddress();
|
||||||
String data = sendData.getData();//
|
String data = sendData.getData();//
|
||||||
@@ -779,7 +1261,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
.mapToInt(Integer::parseInt)
|
.mapToInt(Integer::parseInt)
|
||||||
.toArray();
|
.toArray();
|
||||||
boolean write = PlcSrgvRead.Write(address, intData);
|
boolean write = plcReader.write(address, intData);
|
||||||
|
|
||||||
if (!write) {
|
if (!write) {
|
||||||
b = false;
|
b = false;
|
||||||
@@ -801,7 +1283,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean write = PlcSrgvRead.Write(address, shortData);
|
boolean write = plcReader.write(address, shortData);
|
||||||
|
|
||||||
if (!write) {
|
if (!write) {
|
||||||
b = false;
|
b = false;
|
||||||
@@ -968,19 +1450,49 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
WcsSrgvQueue wcsSrgvQueue = wcsSrgvQueues.get(0);
|
WcsSrgvQueue wcsSrgvQueue = wcsSrgvQueues.get(0);
|
||||||
|
|
||||||
String startSite = null;
|
String startSite = null;
|
||||||
//打补丁 出库任务的default03 是040501 提升机前
|
//打补丁 出库任务的default03 是040601 提升机前
|
||||||
if (wcsSrgvQueue.getTaskType().equals("2")) {
|
|
||||||
startSite = wcsSrgvQueue.getStartSite();
|
|
||||||
}else {
|
|
||||||
startSite = wcsSrgvQueue.getDefault03();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// if (wcsSrgvQueue.getTaskType().equals("4")) {
|
||||||
|
// startSite = wcsSrgvQueue.getStartSite();
|
||||||
|
// }
|
||||||
|
// if (wcsSrgvQueue.getTaskType().equals("2")) {
|
||||||
|
// startSite = wcsSrgvQueue.getStartSite();
|
||||||
|
// }else {
|
||||||
|
// if(wcsSrgvQueue.getStartSite().equals("040601")){
|
||||||
|
// startSite=wcsSrgvQueue.getStartSite();
|
||||||
|
// }else {
|
||||||
|
// startSite = wcsSrgvQueue.getDefault03();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
startSite = wcsSrgvQueue.getStartSite();
|
||||||
|
if (startSite.equals("tsj")){
|
||||||
|
startSite=getSite(wcsSrgvQueue.getStartSite(),wcsSrgvQueue.getTheFloor(),wcsSrgvQueue.getTaskType());
|
||||||
|
}
|
||||||
if (!startSite.equals(currSite)) {
|
if (!startSite.equals(currSite)) {
|
||||||
wcsSrgvQueue.setIssued("1");
|
wcsSrgvQueue.setIssued("1");
|
||||||
wcsSrgvQueue.setExecutionStatus("3");
|
wcsSrgvQueue.setExecutionStatus("3");
|
||||||
wcsSrgvQueue.setStartDate(DateUtil.now());
|
wcsSrgvQueue.setStartDate(DateUtil.now());
|
||||||
wcsSagvQueueMapper.updateWcsSrgvQueue(wcsSrgvQueue);
|
wcsSagvQueueMapper.updateWcsSrgvQueue(wcsSrgvQueue);
|
||||||
|
MydoJob mydoJob = mydoJobService.selectMydoJobByTaskNo(Long.valueOf(wcsSrgvQueue.getTaskNo()));
|
||||||
|
mydoJob.setExecutionPhase("4");//小车搬运
|
||||||
|
mydoJobService.updateMydoJob(mydoJob);
|
||||||
}
|
}
|
||||||
|
String endSite = wcsSrgvQueue.getEndSite();
|
||||||
|
if (endSite.equals("tsj")) {
|
||||||
|
endSite = getSite(wcsSrgvQueue.getEndSite(), wcsSrgvQueue.getTheFloor(), wcsSrgvQueue.getTaskType());
|
||||||
|
}
|
||||||
|
if (endSite.equals(currSite)) {
|
||||||
|
if (!wcsSrgvQueue.getTaskType().equals("8")) {
|
||||||
|
wcsSrgvQueue.setIssued("1");
|
||||||
|
wcsSrgvQueue.setExecutionStatus("3");
|
||||||
|
wcsSrgvQueue.setStartDate(DateUtil.now());
|
||||||
|
wcsSagvQueueMapper.updateWcsSrgvQueue(wcsSrgvQueue);
|
||||||
|
MydoJob mydoJob = mydoJobService.selectMydoJobByTaskNo(Long.valueOf(wcsSrgvQueue.getTaskNo()));
|
||||||
|
mydoJob.setExecutionPhase("4");//小车搬运
|
||||||
|
mydoJobService.updateMydoJob(mydoJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -990,13 +1502,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
if (sitId.equals("tsj")) {
|
if (sitId.equals("tsj")) {
|
||||||
switch (floor) {
|
switch (floor) {
|
||||||
case "1":
|
case "1":
|
||||||
sitId = "040501";
|
sitId = "040601";
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "2":
|
||||||
sitId = "040502";
|
sitId = "040602";
|
||||||
break;
|
break;
|
||||||
case "3":
|
case "3":
|
||||||
sitId = "040503";
|
sitId = "040603";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -1006,13 +1518,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
if (sitId.equals("tsj")) {
|
if (sitId.equals("tsj")) {
|
||||||
switch (floor) {
|
switch (floor) {
|
||||||
case "1":
|
case "1":
|
||||||
sitId = "030501";
|
sitId = "030601";
|
||||||
break;
|
break;
|
||||||
case "2":
|
case "2":
|
||||||
sitId = "030502";
|
sitId = "030602";
|
||||||
break;
|
break;
|
||||||
case "3":
|
case "3":
|
||||||
sitId = "030503";
|
sitId = "030603";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ public class SsjThread implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
|
}finally {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,7 +88,14 @@ public class SsjThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void inDispatch1(DeviceSsj deviceSsj) {
|
void inDispatch1(DeviceSsj deviceSsj) {
|
||||||
if (deviceSsj.getRkqq() == 1 && StrUtil.isNotBlank(deviceSsj.getTrayCode())) {
|
if (deviceSsj.getRkqq() == 1 ) {
|
||||||
|
if(deviceSsj.getTrayCode().equals("NoRead")||StrUtil.isBlank(deviceSsj.getTrayCode())){
|
||||||
|
int i = PlcSsjRead.writeToSsj("0", 11, 1);
|
||||||
|
if (i == 1) {
|
||||||
|
log.info(deviceSsj.getDeviceCode() + "未读到条码,下发退回,去向2");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
// 查是否有正执行的出库作业,有退回
|
// 查是否有正执行的出库作业,有退回
|
||||||
MydoJob queryJob = new MydoJob();
|
MydoJob queryJob = new MydoJob();
|
||||||
queryJob.setStatus("3");
|
queryJob.setStatus("3");
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import com.ruoyi.device.srgv.service.IDeviceSrgvService;
|
|||||||
import com.ruoyi.device.srgv.service.impl.DeviceSrgvServiceImpl;
|
import com.ruoyi.device.srgv.service.impl.DeviceSrgvServiceImpl;
|
||||||
import com.ruoyi.device.ssj.domain.DeviceSsj;
|
import com.ruoyi.device.ssj.domain.DeviceSsj;
|
||||||
import com.ruoyi.device.tsj.domain.DeviceTsj;
|
import com.ruoyi.device.tsj.domain.DeviceTsj;
|
||||||
|
import com.ruoyi.job.domain.JobCallBack;
|
||||||
import com.ruoyi.job.domain.MydoJob;
|
import com.ruoyi.job.domain.MydoJob;
|
||||||
|
import com.ruoyi.job.service.IJobCallBackService;
|
||||||
import com.ruoyi.job.service.IMydoJobService;
|
import com.ruoyi.job.service.IMydoJobService;
|
||||||
import com.ruoyi.queue.srgv.domain.WcsSrgvQueue;
|
import com.ruoyi.queue.srgv.domain.WcsSrgvQueue;
|
||||||
import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService;
|
import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService;
|
||||||
@@ -42,7 +44,7 @@ public class TsjThread implements Runnable {
|
|||||||
private HashMap<String, String> inSsjList;
|
private HashMap<String, String> inSsjList;
|
||||||
private IMydoJobService mydoJobService;
|
private IMydoJobService mydoJobService;
|
||||||
private IDeviceSrgvService deviceSrgvService;
|
private IDeviceSrgvService deviceSrgvService;
|
||||||
|
private IJobCallBackService jobCallBackService;
|
||||||
|
|
||||||
public void init() {
|
public void init() {
|
||||||
tsjDeviceExecutionQueueService = SpringUtils.getBean(ITsjDeviceExecutionQueueService.class);
|
tsjDeviceExecutionQueueService = SpringUtils.getBean(ITsjDeviceExecutionQueueService.class);
|
||||||
@@ -51,6 +53,7 @@ public class TsjThread implements Runnable {
|
|||||||
wcsSrgvQueueService = SpringUtils.getBean(IWcsSrgvQueueService.class);
|
wcsSrgvQueueService = SpringUtils.getBean(IWcsSrgvQueueService.class);
|
||||||
mydoJobService =SpringUtils.getBean(IMydoJobService.class);
|
mydoJobService =SpringUtils.getBean(IMydoJobService.class);
|
||||||
deviceSrgvService=SpringUtils.getBean(DeviceSrgvServiceImpl.class);
|
deviceSrgvService=SpringUtils.getBean(DeviceSrgvServiceImpl.class);
|
||||||
|
jobCallBackService = SpringUtils.getBean(IJobCallBackService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -64,6 +67,12 @@ public class TsjThread implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
|
}finally {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +85,7 @@ public class TsjThread implements Runnable {
|
|||||||
Long rwh = tsj.getRwh();//任务号
|
Long rwh = tsj.getRwh();//任务号
|
||||||
int yxxf = tsj.getYxxf();//允许下发
|
int yxxf = tsj.getYxxf();//允许下发
|
||||||
|
|
||||||
if (czfs == 1 && sbzt == 98 && jdbz == 11 && rwh > 999) {
|
if (czfs == 1 && sbzt == 99 && (jdbz == 0||jdbz == 11||jdbz == 8) && rwh > 999) {
|
||||||
//任务完成
|
//任务完成
|
||||||
finishTask(tsj);
|
finishTask(tsj);
|
||||||
}
|
}
|
||||||
@@ -107,9 +116,11 @@ public class TsjThread implements Runnable {
|
|||||||
if (CollUtil.isNotEmpty(wcsSrgvQueues)) {
|
if (CollUtil.isNotEmpty(wcsSrgvQueues)) {
|
||||||
WcsSrgvQueue wcsSrgvQueue = wcsSrgvQueues.get(0);
|
WcsSrgvQueue wcsSrgvQueue = wcsSrgvQueues.get(0);
|
||||||
String rwlx = "";
|
String rwlx = "";
|
||||||
|
String tarFloor = wcsSrgvQueue.getDefault07();
|
||||||
if ("2".equals(wcsSrgvQueue.getTaskType())) {
|
if ("2".equals(wcsSrgvQueue.getTaskType())) {
|
||||||
//出库
|
//出库
|
||||||
rwlx = "2";
|
rwlx = "2";
|
||||||
|
tarFloor="11";
|
||||||
}
|
}
|
||||||
if ("3".equals(wcsSrgvQueue.getTaskType())) {
|
if ("3".equals(wcsSrgvQueue.getTaskType())) {
|
||||||
//
|
//
|
||||||
@@ -122,8 +133,6 @@ public class TsjThread implements Runnable {
|
|||||||
TsjDeviceExecutionQueue tsjDeviceExecutionQueueByRwh = tsjDeviceExecutionQueueService.selectTsjDeviceExecutionQueueByRwh(Convert.toLong(deviceSrgv.getTaskNo()));
|
TsjDeviceExecutionQueue tsjDeviceExecutionQueueByRwh = tsjDeviceExecutionQueueService.selectTsjDeviceExecutionQueueByRwh(Convert.toLong(deviceSrgv.getTaskNo()));
|
||||||
if (tsjDeviceExecutionQueueByRwh == null && StrUtil.isNotEmpty(rwlx)) {
|
if (tsjDeviceExecutionQueueByRwh == null && StrUtil.isNotEmpty(rwlx)) {
|
||||||
String strFloor = wcsSrgvQueue.getTheFloor();
|
String strFloor = wcsSrgvQueue.getTheFloor();
|
||||||
String tarFloor = wcsSrgvQueue.getDefault07();
|
|
||||||
if (!Convert.toStr(tsj.getDqcs()).equals(strFloor)) {
|
|
||||||
//提升机层数和取车任务层数不一致
|
//提升机层数和取车任务层数不一致
|
||||||
//todo 判断目标楼层存在不存在其他小车
|
//todo 判断目标楼层存在不存在其他小车
|
||||||
TsjDeviceExecutionQueue tsjDeviceExecutionQueue = new TsjDeviceExecutionQueue();
|
TsjDeviceExecutionQueue tsjDeviceExecutionQueue = new TsjDeviceExecutionQueue();
|
||||||
@@ -141,8 +150,6 @@ public class TsjThread implements Runnable {
|
|||||||
tsjDeviceExecutionQueue.setTaskType("1");
|
tsjDeviceExecutionQueue.setTaskType("1");
|
||||||
tsjDeviceExecutionQueue.setRwlx(rwlx);
|
tsjDeviceExecutionQueue.setRwlx(rwlx);
|
||||||
tsjDeviceExecutionQueueService.insertTsjDeviceExecutionQueue(tsjDeviceExecutionQueue);
|
tsjDeviceExecutionQueueService.insertTsjDeviceExecutionQueue(tsjDeviceExecutionQueue);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +192,7 @@ public class TsjThread implements Runnable {
|
|||||||
tsjDeviceExecutionQueue.setDeviceName(tsj.getName());
|
tsjDeviceExecutionQueue.setDeviceName(tsj.getName());
|
||||||
tsjDeviceExecutionQueue.setTaskNo(Convert.toLong(ssj.getTaskNo()));
|
tsjDeviceExecutionQueue.setTaskNo(Convert.toLong(ssj.getTaskNo()));
|
||||||
tsjDeviceExecutionQueue.setSrcRow("0");
|
tsjDeviceExecutionQueue.setSrcRow("0");
|
||||||
tsjDeviceExecutionQueue.setSrcLayer(String.valueOf(tsj.getDqcs()));
|
tsjDeviceExecutionQueue.setSrcLayer("11");
|
||||||
tsjDeviceExecutionQueue.setTarRow("0");
|
tsjDeviceExecutionQueue.setTarRow("0");
|
||||||
tsjDeviceExecutionQueue.setTarLayer(theFloor);
|
tsjDeviceExecutionQueue.setTarLayer(theFloor);
|
||||||
tsjDeviceExecutionQueue.setSendType("1");
|
tsjDeviceExecutionQueue.setSendType("1");
|
||||||
@@ -244,7 +251,7 @@ public class TsjThread implements Runnable {
|
|||||||
if (ObjUtil.isNotNull(tsjDeviceExecutionQueue)) {
|
if (ObjUtil.isNotNull(tsjDeviceExecutionQueue)) {
|
||||||
//完成提升机任务 插入历史表
|
//完成提升机任务 插入历史表
|
||||||
String senFlag= tsjDeviceExecutionQueue.getSendFlag()==null?"0":"1";
|
String senFlag= tsjDeviceExecutionQueue.getSendFlag()==null?"0":"1";
|
||||||
if (tsjDeviceExecutionQueue.getTarLayer().equals(String.valueOf(tsj.getDqcs()))&&senFlag.equals("1")){
|
if ((tsjDeviceExecutionQueue.getTarLayer().equals(String.valueOf(tsj.getDqcs()))||tsjDeviceExecutionQueue.getTarLayer().equals("11"))&&senFlag.equals("1")){
|
||||||
TsjDeviceExecutionQueueFinish tsjDeviceExecutionQueueFinish = new TsjDeviceExecutionQueueFinish();
|
TsjDeviceExecutionQueueFinish tsjDeviceExecutionQueueFinish = new TsjDeviceExecutionQueueFinish();
|
||||||
BeanUtil.copyProperties(tsjDeviceExecutionQueue, tsjDeviceExecutionQueueFinish);
|
BeanUtil.copyProperties(tsjDeviceExecutionQueue, tsjDeviceExecutionQueueFinish);
|
||||||
tsjDeviceExecutionQueueFinish.setFinishDate(DateUtil.formatDateTime(DateUtil.date()));
|
tsjDeviceExecutionQueueFinish.setFinishDate(DateUtil.formatDateTime(DateUtil.date()));
|
||||||
@@ -255,6 +262,19 @@ public class TsjThread implements Runnable {
|
|||||||
mydoJob.setExecutionPhase("3");
|
mydoJob.setExecutionPhase("3");
|
||||||
mydoJobService.updateMydoJob(mydoJob);
|
mydoJobService.updateMydoJob(mydoJob);
|
||||||
}
|
}
|
||||||
|
if (mydoJob != null&&tsjDeviceExecutionQueue.getRwlx().equals("2")) {
|
||||||
|
mydoJob.setStatus("4");
|
||||||
|
mydoJobService.updateMydoJob(mydoJob);
|
||||||
|
mydoJobService.insertHistory(mydoJob.getJobId());
|
||||||
|
mydoJobService.deleteMydoJobByJobId(mydoJob.getJobId());
|
||||||
|
JobCallBack jobCallBack = new JobCallBack();
|
||||||
|
jobCallBack.setType("2");
|
||||||
|
jobCallBack.setMydojobId(mydoJob.getJobId());
|
||||||
|
jobCallBack.setStatus("0");
|
||||||
|
jobCallBack.setTaskNo(Convert.toLong(mydoJob.getTaskNo()));
|
||||||
|
jobCallBack.setCreateTime(new Date());
|
||||||
|
jobCallBackService.insertJobCallBack(jobCallBack);
|
||||||
|
}
|
||||||
log.info("提升机任务下发完成 taskNo{} 任务类型:{}", tsj.getRwh(), "提升机任务");
|
log.info("提升机任务下发完成 taskNo{} 任务类型:{}", tsj.getRwh(), "提升机任务");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
package com.ruoyi.web.controller.schedule;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.schedule.ScheduleThread;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程管理控制器
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/schedule/thread")
|
||||||
|
public class ThreadManageController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ScheduleThread scheduleThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取线程列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/list")
|
||||||
|
public AjaxResult list() {
|
||||||
|
if (scheduleThread.threadTypeMap.isEmpty()) {
|
||||||
|
scheduleThread.refreshThreadMap();
|
||||||
|
}
|
||||||
|
return AjaxResult.success(scheduleThread.getAllThreadStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动线程
|
||||||
|
*/
|
||||||
|
@PostMapping("/start/{key}")
|
||||||
|
public AjaxResult start(@PathVariable String key) {
|
||||||
|
try {
|
||||||
|
scheduleThread.startThread(key);
|
||||||
|
return AjaxResult.success("启动成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("启动失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止线程
|
||||||
|
*/
|
||||||
|
@PostMapping("/stop/{key}")
|
||||||
|
public AjaxResult stop(@PathVariable String key) {
|
||||||
|
try {
|
||||||
|
scheduleThread.stopThread(key);
|
||||||
|
return AjaxResult.success("停止指令已下发");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("停止失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动全部线程
|
||||||
|
*/
|
||||||
|
@PostMapping("/startAll")
|
||||||
|
public AjaxResult startAll() {
|
||||||
|
try {
|
||||||
|
for (String key : scheduleThread.threadMap.keySet()) {
|
||||||
|
try {
|
||||||
|
scheduleThread.startThread(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 忽略单个启动失败,继续启动下一个
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AjaxResult.success("全部启动指令已下发");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止全部线程
|
||||||
|
*/
|
||||||
|
@PostMapping("/stopAll")
|
||||||
|
public AjaxResult stopAll() {
|
||||||
|
try {
|
||||||
|
for (String key : scheduleThread.threadMap.keySet()) {
|
||||||
|
scheduleThread.stopThread(key);
|
||||||
|
}
|
||||||
|
return AjaxResult.success("全部停止指令已下发");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动分组线程
|
||||||
|
*/
|
||||||
|
@PostMapping("/startGroup/{type}")
|
||||||
|
public AjaxResult startGroup(@PathVariable String type) {
|
||||||
|
try {
|
||||||
|
for (Map.Entry<String, String> entry : scheduleThread.threadTypeMap.entrySet()) {
|
||||||
|
if (type.equals(entry.getValue())) {
|
||||||
|
try {
|
||||||
|
scheduleThread.startThread(entry.getKey());
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AjaxResult.success("分组启动指令已下发");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止分组线程
|
||||||
|
*/
|
||||||
|
@PostMapping("/stopGroup/{type}")
|
||||||
|
public AjaxResult stopGroup(@PathVariable String type) {
|
||||||
|
try {
|
||||||
|
for (Map.Entry<String, String> entry : scheduleThread.threadTypeMap.entrySet()) {
|
||||||
|
if (type.equals(entry.getValue())) {
|
||||||
|
scheduleThread.stopThread(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AjaxResult.success("分组停止指令已下发");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取线程日志
|
||||||
|
*/
|
||||||
|
@GetMapping("/log/{key}")
|
||||||
|
public AjaxResult log(@PathVariable String key) {
|
||||||
|
// 如果key是"ALL",则不进行关键词过滤,显示所有日志(除了堆栈合并逻辑外)
|
||||||
|
String target = "ALL".equals(key) ? null : key;
|
||||||
|
|
||||||
|
// 日志路径,根据logback配置及实际环境确认
|
||||||
|
File file = new File("D:/home/ruoyi/logs/sys-info.log");
|
||||||
|
if (!file.exists()) {
|
||||||
|
return AjaxResult.error("日志文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedList<String> lines = new LinkedList<>();
|
||||||
|
// 简单的日志行首匹配模式 (yyyy-MM-dd HH:mm:ss)
|
||||||
|
Pattern logStartPattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}");
|
||||||
|
boolean isMatchingStack = false;
|
||||||
|
// 如果是查看所有日志,默认所有行都匹配,除非遇到新的日志行且我们想做更复杂的过滤(目前全显)
|
||||||
|
// 但为了支持堆栈合并,我们还是需要判断行首
|
||||||
|
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
boolean isLogStart = logStartPattern.matcher(line).find();
|
||||||
|
|
||||||
|
if (target == null) {
|
||||||
|
// 查看所有日志:直接添加,或者如果是异常日志查看模式可以在这里过滤
|
||||||
|
// 暂时逻辑:全部添加
|
||||||
|
lines.add(line);
|
||||||
|
} else {
|
||||||
|
// 查看特定线程日志
|
||||||
|
if (line.contains(target)) {
|
||||||
|
isMatchingStack = true;
|
||||||
|
lines.add(line);
|
||||||
|
} else if (isLogStart) {
|
||||||
|
isMatchingStack = false;
|
||||||
|
} else if (isMatchingStack) {
|
||||||
|
lines.add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 限制行数,避免内存溢出,保留最后1000行
|
||||||
|
if (lines.size() > 1000) {
|
||||||
|
lines.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("读取日志失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return AjaxResult.success(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取异常日志
|
||||||
|
*/
|
||||||
|
@GetMapping("/errorLog")
|
||||||
|
public AjaxResult errorLog() {
|
||||||
|
File file = new File("D:/home/ruoyi/logs/sys-error.log");
|
||||||
|
if (!file.exists()) {
|
||||||
|
// 如果没有单独的error log,尝试从info log中过滤ERROR级别?
|
||||||
|
// 假设有 sys-error.log
|
||||||
|
return AjaxResult.error("异常日志文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedList<String> lines = new LinkedList<>();
|
||||||
|
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
lines.add(line);
|
||||||
|
if (lines.size() > 1000) {
|
||||||
|
lines.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("读取日志失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
return AjaxResult.success(lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ spring:
|
|||||||
druid:
|
druid:
|
||||||
#主数据信息
|
#主数据信息
|
||||||
master:
|
master:
|
||||||
url: jdbc:sqlserver://172.16.2.170:1433;databaseName=FT542-wcs;
|
url: jdbc:sqlserver://192.168.10.200:1433;databaseName=FT542-wcs;
|
||||||
username: sa
|
username: sa
|
||||||
password: Flrd0914.
|
password: Flrd0914.
|
||||||
# 从库数据源
|
# 从库数据源
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ spring:
|
|||||||
devtools:
|
devtools:
|
||||||
restart:
|
restart:
|
||||||
# 热部署开关
|
# 热部署开关
|
||||||
enabled: true
|
enabled: false
|
||||||
# redis 配置
|
# redis 配置
|
||||||
redis:
|
redis:
|
||||||
# 地址
|
# 地址
|
||||||
host: 172.16.2.170
|
host: 192.168.10.200
|
||||||
# 端口,默认为6379
|
# 端口,默认为6379
|
||||||
port: 6379
|
port: 6379
|
||||||
# 数据库索引
|
# 数据库索引
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</select>
|
</select>
|
||||||
<select id="selectDeviceCdzListNoSRgvId" resultMap="DeviceCdzResult">
|
<select id="selectDeviceCdzListNoSRgvId" resultMap="DeviceCdzResult">
|
||||||
<include refid="selectDeviceCdzVo"/>
|
<include refid="selectDeviceCdzVo"/>
|
||||||
where spare1 is null
|
where spare1 ='0'
|
||||||
</select>
|
</select>
|
||||||
<select id="selectDeviceCdzHasSRgvList" resultMap="DeviceCdzResult">
|
<select id="selectDeviceCdzHasSRgvList" resultMap="DeviceCdzResult">
|
||||||
<include refid="selectDeviceCdzVo"/>
|
<include refid="selectDeviceCdzVo"/>
|
||||||
where spare1 is not null
|
where spare1 <> '0'
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insertDeviceCdz" parameterType="DeviceCdz">
|
<insert id="insertDeviceCdz" parameterType="DeviceCdz">
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="theFloor != null and theFloor != ''"> and the_floor = #{theFloor}</if>
|
<if test="theFloor != null and theFloor != ''"> and the_floor = #{theFloor}</if>
|
||||||
<if test="productId != null and productId != ''"> and product_id = #{productId}</if>
|
<if test="productId != null and productId != ''"> and product_id = #{productId}</if>
|
||||||
<if test="productName != null and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
|
<if test="productName != null and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
|
||||||
|
<if test="inOut != null and inOut != '' and inOut == '1'"> and in_or_out < 20 </if>
|
||||||
|
<if test="inOut != null and inOut != '' and inOut == '2'"> and in_or_out >= 20</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -262,6 +264,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</select>
|
</select>
|
||||||
<select id="selectOutJobList" resultMap="MydoJobResult">
|
<select id="selectOutJobList" resultMap="MydoJobResult">
|
||||||
<include refid="selectMydoJobVo"/>
|
<include refid="selectMydoJobVo"/>
|
||||||
where status=1 and in_or_out >20 and the_floor =#{theFloor}
|
where status=1 and in_or_out >=20 and the_floor =#{theFloor}
|
||||||
|
</select>
|
||||||
|
<select id="selectInJobList" resultMap="MydoJobResult">
|
||||||
|
<include refid="selectMydoJobVo"/>
|
||||||
|
where status=3 and in_or_out < 20 and the_floor =#{theFloor} and execution_phase=3
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
73
ruoyi-ui/src/api/schedule/thread.js
Normal file
73
ruoyi-ui/src/api/schedule/thread.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询线程列表
|
||||||
|
export function listThread() {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/list',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动线程
|
||||||
|
export function startThread(key) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/start/' + key,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止线程
|
||||||
|
export function stopThread(key) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/stop/' + key,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志
|
||||||
|
export function getThreadLog(key) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/log/' + key,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动全部线程
|
||||||
|
export function startAllThread() {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/startAll',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止全部线程
|
||||||
|
export function stopAllThread() {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/stopAll',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动分组线程
|
||||||
|
export function startGroupThread(type) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/startGroup/' + type,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止分组线程
|
||||||
|
export function stopGroupThread(type) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/stopGroup/' + type,
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取异常日志
|
||||||
|
export function getErrorLog() {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/thread/errorLog',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -7,18 +7,6 @@
|
|||||||
|
|
||||||
<div class="right-menu">
|
<div class="right-menu">
|
||||||
<template v-if="device!=='mobile'">
|
<template v-if="device!=='mobile'">
|
||||||
<el-tooltip :content="$t('top.read')" effect="dark" placement="bottom">
|
|
||||||
<el-button class="right-menu-item hover-effect" :type="plcReadStatus ? 'success' : 'info'" size="mini" @click="togglePlcRead">
|
|
||||||
{{ plcReadStatus ? $t('top.stopRead') : $t('top.startRead') }}
|
|
||||||
</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
<el-tooltip :content="$t('top.task')" effect="dark" placement="bottom">
|
|
||||||
<el-button class="right-menu-item hover-effect" :type="plcScheduleStatus ? 'success' : 'info'" size="mini" @click="togglePlcSchedule">
|
|
||||||
{{ plcScheduleStatus ? $t('top.stopTask') : $t('top.startTask') }}
|
|
||||||
</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
|
|
||||||
<search id="header-search" class="right-menu-item" />
|
<search id="header-search" class="right-menu-item" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
<!-- 统计卡片 -->
|
<!-- 统计卡片 -->
|
||||||
<el-row :gutter="20" class="stats-row">
|
<el-row :gutter="40" class="stats-row">
|
||||||
|
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
<el-card class="stats-card">
|
<el-card class="stats-card">
|
||||||
<div class="stats-content">
|
<div class="stats-content">
|
||||||
<div class="stats-icon ddj-icon">
|
<div class="stats-icon ddj-icon">
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
<el-card class="stats-card">
|
<el-card class="stats-card">
|
||||||
<div class="stats-content">
|
<div class="stats-content">
|
||||||
<div class="stats-icon ctu-icon">
|
<div class="stats-icon ctu-icon">
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
<el-card class="stats-card">
|
<el-card class="stats-card">
|
||||||
<div class="stats-content">
|
<div class="stats-content">
|
||||||
<div class="stats-icon tsj-icon">
|
<div class="stats-icon tsj-icon">
|
||||||
@@ -42,7 +42,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
</el-row>
|
||||||
|
<el-row :gutter="40" class="stats-row">
|
||||||
|
<el-col :span="8">
|
||||||
<el-card class="stats-card">
|
<el-card class="stats-card">
|
||||||
<div class="stats-content">
|
<div class="stats-content">
|
||||||
<div class="stats-icon queue-icon">
|
<div class="stats-icon queue-icon">
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
<el-card class="stats-card">
|
<el-card class="stats-card">
|
||||||
<div class="stats-content">
|
<div class="stats-content">
|
||||||
<div class="stats-icon running-icon">
|
<div class="stats-icon running-icon">
|
||||||
@@ -68,7 +70,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
<el-card class="stats-card">
|
<el-card class="stats-card">
|
||||||
<div class="stats-content">
|
<div class="stats-content">
|
||||||
<div class="stats-icon finish-icon">
|
<div class="stats-icon finish-icon">
|
||||||
@@ -379,9 +381,7 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
// 默认数据
|
// 默认数据
|
||||||
chartData = [
|
chartData = [
|
||||||
{ value: 45, name: this.$t('index.inboundTask') }, // 入库任务
|
|
||||||
{ value: 35, name: this.$t('index.outboundTask') }, // 出库任务
|
|
||||||
{ value: 20, name: this.$t('index.transferTask') } // 移库任务
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
331
ruoyi-ui/src/views/schedule/thread/index.vue
Normal file
331
ruoyi-ui/src/views/schedule/thread/index.vue
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<!-- 全局控制卡片 -->
|
||||||
|
<el-card class="box-card" shadow="hover" style="margin-bottom: 20px;">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span style="font-weight: bold; font-size: 18px;"><i class="el-icon-setting"></i> 全局控制中心</span>
|
||||||
|
</div>
|
||||||
|
<el-row :gutter="20" type="flex" align="middle">
|
||||||
|
<el-col :span="7">
|
||||||
|
<div class="control-group">
|
||||||
|
<span class="control-label">系统总控:</span>
|
||||||
|
<el-button type="success" size="small" icon="el-icon-video-play" @click="handleStartAll">全部开启</el-button>
|
||||||
|
<el-button type="danger" size="small" icon="el-icon-video-pause" @click="handleStopAll">全部关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="11" style="border-left: 1px solid #EBEEF5; border-right: 1px solid #EBEEF5;">
|
||||||
|
<div class="control-group" style="justify-content: space-evenly;">
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<span class="control-label"><i class="el-icon-cpu"></i> 通讯组:</span>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button type="primary" size="mini" icon="el-icon-video-play" @click="handleStartGroup('read')">开启</el-button>
|
||||||
|
<el-button type="info" size="mini" icon="el-icon-video-pause" @click="handleStopGroup('read')">停止</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider direction="vertical" style="height: 20px;"></el-divider>
|
||||||
|
|
||||||
|
<div style="display: flex; align-items: center;">
|
||||||
|
<span class="control-label"><i class="el-icon-s-operation"></i> 调度组:</span>
|
||||||
|
<el-button-group>
|
||||||
|
<el-button type="primary" size="mini" icon="el-icon-video-play" @click="handleStartGroup('schedule')">开启</el-button>
|
||||||
|
<el-button type="info" size="mini" icon="el-icon-video-pause" @click="handleStopGroup('schedule')">停止</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="control-group" style="justify-content: flex-end;">
|
||||||
|
<span class="control-label">日志:</span>
|
||||||
|
<el-button type="primary" plain size="small" icon="el-icon-document" @click="handleGlobalLog">系统日志</el-button>
|
||||||
|
<el-button type="danger" plain size="small" icon="el-icon-warning-outline" @click="handleErrorLog">异常日志</el-button>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<!-- 读取线程组 -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card class="box-card" shadow="hover">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span style="font-weight: bold; font-size: 16px;"><i class="el-icon-cpu"></i> PLC读取线程</span>
|
||||||
|
<el-tag size="small" type="info" style="float: right">硬件通信</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="loading" :data="readThreads" size="small" :show-header="true">
|
||||||
|
<el-table-column label="线程名称" prop="name" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="状态" align="center" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag :type="scope.row.isRun ? 'success' : 'danger'" size="mini" effect="dark">
|
||||||
|
{{ scope.row.isRun ? '运行中' : '已停止' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-video-play" v-if="!scope.row.isRun" @click="handleStart(scope.row)">启动</el-button>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-video-pause" v-if="scope.row.isRun" @click="handleStop(scope.row)">停止</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 调度线程组 -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card class="box-card" shadow="hover">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span style="font-weight: bold; font-size: 16px;"><i class="el-icon-s-operation"></i> 调度控制线程</span>
|
||||||
|
<el-tag size="small" type="primary" style="float: right">业务逻辑</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="loading" :data="scheduleThreads" size="small" :show-header="true">
|
||||||
|
<el-table-column label="线程名称" prop="name" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="状态" align="center" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag :type="scope.row.isRun ? 'success' : 'danger'" size="mini" effect="dark">
|
||||||
|
{{ scope.row.isRun ? '运行中' : '已停止' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-video-play" v-if="!scope.row.isRun" @click="handleStart(scope.row)">启动</el-button>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-video-pause" v-if="scope.row.isRun" @click="handleStop(scope.row)">停止</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="20" style="margin-top: 20px;">
|
||||||
|
<!-- 监控线程组 -->
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-card class="box-card" shadow="hover">
|
||||||
|
<div slot="header" class="clearfix">
|
||||||
|
<span style="font-weight: bold; font-size: 16px;"><i class="el-icon-monitor"></i> 系统监控线程</span>
|
||||||
|
<el-tag size="small" type="warning" style="float: right">状态监控</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-table v-loading="loading" :data="monitorThreads" size="small" :show-header="true">
|
||||||
|
<el-table-column label="线程名称" prop="name" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="标识" prop="key" :show-overflow-tooltip="true" />
|
||||||
|
<el-table-column label="状态" align="center" width="100">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag :type="scope.row.isRun ? 'success' : 'danger'" size="mini" effect="dark">
|
||||||
|
{{ scope.row.isRun ? '运行中' : '已停止' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" width="150">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-video-play" v-if="!scope.row.isRun" @click="handleStart(scope.row)">启动</el-button>
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-video-pause" v-if="scope.row.isRun" @click="handleStop(scope.row)">停止</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 日志弹窗 -->
|
||||||
|
<el-dialog :title="logTitle" :visible.sync="openLog" width="800px" append-to-body>
|
||||||
|
<div class="log-container" v-loading="logLoading">
|
||||||
|
<pre v-if="logContent.length > 0">{{ logContent.join('\n') }}</pre>
|
||||||
|
<div v-else style="text-align: center; color: #909399; padding-top: 200px;">暂无日志</div>
|
||||||
|
</div>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="refreshLog">刷 新</el-button>
|
||||||
|
<el-button @click="openLog = false">关 闭</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listThread, startThread, stopThread, getThreadLog, startAllThread, stopAllThread, startGroupThread, stopGroupThread, getErrorLog } from "@/api/schedule/thread";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Thread",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 遮罩层
|
||||||
|
loading: true,
|
||||||
|
// 线程表格数据
|
||||||
|
threadList: [],
|
||||||
|
// 日志弹窗
|
||||||
|
openLog: false,
|
||||||
|
logTitle: "",
|
||||||
|
logLoading: false,
|
||||||
|
logContent: [],
|
||||||
|
logType: 'system', // system, error
|
||||||
|
currentLogKey: null // for refresh
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
readThreads() {
|
||||||
|
return this.threadList.filter(item => item.type === 'read' || !item.type);
|
||||||
|
},
|
||||||
|
scheduleThreads() {
|
||||||
|
return this.threadList.filter(item => item.type === 'schedule');
|
||||||
|
},
|
||||||
|
monitorThreads() {
|
||||||
|
return this.threadList.filter(item => item.type === 'monitor');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 查询线程列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
listThread().then(response => {
|
||||||
|
this.threadList = response.data;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 启动按钮操作 */
|
||||||
|
handleStart(row) {
|
||||||
|
this.$confirm('确认要启动 "' + row.name + '" 吗?', "警告", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
return startThread(row.key);
|
||||||
|
}).then(response => {
|
||||||
|
this.$modal.msgSuccess("启动指令已下发");
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getList();
|
||||||
|
}, 1000);
|
||||||
|
}).catch(error => {
|
||||||
|
console.error("启动失败:", error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 停止按钮操作 */
|
||||||
|
handleStop(row) {
|
||||||
|
this.$confirm('确认要停止 "' + row.name + '" 吗?', "警告", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
return stopThread(row.key);
|
||||||
|
}).then(response => {
|
||||||
|
this.$modal.msgSuccess("停止指令已下发");
|
||||||
|
// 稍微延迟一下刷新,等待线程退出
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getList();
|
||||||
|
}, 1000);
|
||||||
|
}).catch(error => {
|
||||||
|
console.error("停止失败:", error);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 一键开启所有 */
|
||||||
|
handleStartAll() {
|
||||||
|
this.$confirm('确认要启动所有线程吗?', "警告", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
return startAllThread();
|
||||||
|
}).then(() => {
|
||||||
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
setTimeout(() => { this.getList(); }, 2000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 一键关闭所有 */
|
||||||
|
handleStopAll() {
|
||||||
|
this.$confirm('确认要停止所有线程吗?', "警告", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "error"
|
||||||
|
}).then(() => {
|
||||||
|
return stopAllThread();
|
||||||
|
}).then(() => {
|
||||||
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
setTimeout(() => { this.getList(); }, 2000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 分组开启 */
|
||||||
|
handleStartGroup(type) {
|
||||||
|
startGroupThread(type).then(() => {
|
||||||
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
setTimeout(() => { this.getList(); }, 1500);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 分组停止 */
|
||||||
|
handleStopGroup(type) {
|
||||||
|
stopGroupThread(type).then(() => {
|
||||||
|
this.$modal.msgSuccess("操作成功");
|
||||||
|
setTimeout(() => { this.getList(); }, 1500);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 系统日志 */
|
||||||
|
handleGlobalLog() {
|
||||||
|
this.logTitle = "系统运行日志";
|
||||||
|
this.logType = 'system';
|
||||||
|
this.currentLogKey = 'ALL';
|
||||||
|
this.openLog = true;
|
||||||
|
this.refreshLog();
|
||||||
|
},
|
||||||
|
/** 异常日志 */
|
||||||
|
handleErrorLog() {
|
||||||
|
this.logTitle = "系统异常日志";
|
||||||
|
this.logType = 'error';
|
||||||
|
this.openLog = true;
|
||||||
|
this.refreshLog();
|
||||||
|
},
|
||||||
|
refreshLog() {
|
||||||
|
this.logLoading = true;
|
||||||
|
if (this.logType === 'system') {
|
||||||
|
getThreadLog(this.currentLogKey).then(response => {
|
||||||
|
this.logContent = response.data;
|
||||||
|
this.logLoading = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const container = this.$el.querySelector('.log-container');
|
||||||
|
if (container) container.scrollTop = container.scrollHeight;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
getErrorLog().then(response => {
|
||||||
|
this.logContent = response.data;
|
||||||
|
this.logLoading = false;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const container = this.$el.querySelector('.log-container');
|
||||||
|
if (container) container.scrollTop = container.scrollHeight;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.log-container {
|
||||||
|
height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-family: Consolas, Monaco, monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.box-card {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.control-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.control-label {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user