12 Commits

Author SHA1 Message Date
zgw
89b2fff3d1 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	ruoyi-admin/src/main/java/com/ruoyi/api/controller/AgvController.java
#	ruoyi-admin/src/main/java/com/ruoyi/api/service/IApiService.java
#	ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/ApiServiceImpl.java
#	ruoyi-admin/src/main/java/com/ruoyi/api/service/impl/RequestLogServiceImpl.java
#	ruoyi-admin/src/main/java/com/ruoyi/bas/srgvmap/service/impl/RoadCacheServiceImpl.java
#	ruoyi-admin/src/main/java/com/ruoyi/common/Constant.java
#	ruoyi-admin/src/main/java/com/ruoyi/job/mapper/MydoJobMapper.java
#	ruoyi-admin/src/main/java/com/ruoyi/job/service/IMydoJobService.java
#	ruoyi-admin/src/main/java/com/ruoyi/job/service/impl/MydoJobServiceImpl.java
#	ruoyi-admin/src/main/java/com/ruoyi/queue/srgv/mapper/WcsSrgvQueueMapper.java
#	ruoyi-admin/src/main/java/com/ruoyi/queue/srgv/service/impl/WcsSrgvQueueServiceImpl.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/cdz/PlcCdzRead.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/srgv/PlcSrgvRead.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/plcRead/ssj/PlcSsjRead.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/cdz/CdzThread.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/srgv/BaseSRgvThread.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/ssj/SsjThread.java
#	ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/tsj/TsjThread.java
#	ruoyi-admin/src/main/resources/mapper/job/MydoJobMapper.xml
#	ruoyi-admin/src/main/resources/mapper/queue/WcsSrgvQueueMapper.xml
2026-07-24 08:52:43 +08:00
zgw
72b88ed0e3 chore: upload current WCS changes 2026-07-24 08:51:41 +08:00
1009473166@qq.com
d98fe2a30c 2026.3.19 晚
新增出库到位自动过账
2026-03-19 18:44:54 +08:00
1009473166@qq.com
af308d7dc9 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	ruoyi-admin/src/main/java/com/ruoyi/api/controller/AgvController.java
2026-03-19 18:20:39 +08:00
张怡蓉
ad9f8d87fd 小车 2026-03-19 15:08:50 +08:00
1009473166@qq.com
fa9386773f 2026.3.18 晚
新增agv获取输送机接口
2026-03-18 20:29:00 +08:00
1009473166@qq.com
cafcde4a35 2026.3.18 2026-03-18 14:26:26 +08:00
1009473166@qq.com
24eaaa2823 2026.3.18 2026-03-18 14:22:57 +08:00
猫猫guowen
24fb696a67 数字孪生:修改输送机入库时到位信号为到位,出库时为空闲 2026-03-18 14:13:14 +08:00
liuhanqing
9b008f5fe7 现场调度修改 2026-03-11 09:02:58 +08:00
liuhanqing
03e30d1db0 现场调度修改 2026-03-02 08:40:01 +08:00
liuhanqing
9c6c32b7ed 现场调度修改 2026-02-26 09:46:54 +08:00
19 changed files with 353 additions and 116 deletions

View File

@@ -0,0 +1,30 @@
package com.ruoyi.algorithm.controller;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.algorithm.service.ITidyService;
import com.ruoyi.common.core.domain.AjaxResult;
@RestController
@RequestMapping("/algorithm/tidy")
public class TidyController {
@Autowired
private ITidyService tidyService;
@PreAuthorize("@ss.hasPermi('algorithm:tidy:query')")
@GetMapping("/status")
public AjaxResult status() { return AjaxResult.success(tidyService.getStatus()); }
@PreAuthorize("@ss.hasPermi('algorithm:tidy:edit')")
@PutMapping("/mode")
public AjaxResult mode(@RequestBody Map<String, String> body) {
try { return AjaxResult.success(tidyService.updateMode(body == null ? null : body.get("mode"))); }
catch (IllegalArgumentException ex) { return AjaxResult.error(ex.getMessage()); }
}
}

View File

@@ -0,0 +1,8 @@
package com.ruoyi.algorithm.service;
import java.util.Map;
public interface ITidyService {
Map<String, Object> getStatus();
Map<String, Object> updateMode(String mode);
}

View File

@@ -0,0 +1,29 @@
package com.ruoyi.algorithm.service.impl;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.stereotype.Service;
import com.ruoyi.algorithm.service.ITidyService;
@Service
public class TidyServiceImpl implements ITidyService {
private final AtomicReference<String> mode = new AtomicReference<>("AUTO");
@Override
public Map<String, Object> getStatus() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("mode", mode.get());
result.put("enabled", true);
return result;
}
@Override
public Map<String, Object> updateMode(String requestedMode) {
if (requestedMode == null || !("AUTO".equalsIgnoreCase(requestedMode) || "MANUAL".equalsIgnoreCase(requestedMode))) {
throw new IllegalArgumentException("mode must be AUTO or MANUAL");
}
mode.set(requestedMode.toUpperCase());
return getStatus();
}
}

View File

@@ -53,6 +53,12 @@ public class Wcs2WmsController {
return apiService.cancelMydoJob(jobParam);
}
/** Return a read-only snapshot of all S-RGV vehicles. */
@PostMapping("/tidyVehicleSnapshot")
public AjaxResult tidyVehicleSnapshot() {
return apiService.tidyVehicleSnapshot();
}

View File

@@ -14,143 +14,187 @@ import java.util.UUID;
@Data
public class GenAgvSchedulingTaskRequest {
/**
* 请求编号
* 同一个请求重复提交, 使用同一编号
* 起始站点
*/
@NotNull
private String reqCode = UUID.randomUUID().toString();
private String FromStation;
/**
* 请求时间
* 格式: “yyyy-MM-dd HH:mm:ss”
* 目的站点
*/
private String reqTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
private String ToStation;
/**
* 客户端编号
* 客户端编号,如PDA,HCWMS等
* 任务类型(以实际的任务类型为准)
*/
private String clientCode;
private String Type;
/**
* 令牌号
* 由调度系统颁发
* 类名
*/
private String tokenCode;
private String ClassName;
/**
* 任务类型
* 内置任务类型:
* 厂内货架搬运: F01
* 厂内货架空满交换: F02
* 辊筒搬运接驳:F03
* 厂内货架出库AGV待命:F04
* 旋转货架: F05
* 厂内电梯任务: F06
* 以下为叉车专用任务类型
* 高位货架到工作台: F11
* 工作台到高位货架: F12
* 巷道到工作台: F13
* 工作台到巷道: F14
* 高位货架到工作台(接驳) : F15
* 工作台到高位货架 (接驳) : F16
* 巷道到工作台(接驳) : F17
* 工作台到巷道(接驳) : F18
* 叉车电梯主任务: F20
* 任务引导ID
*/
@NotNull
private String taskTyp;
private String TaskGuideId;
/**
* 容器类型(叉车/CTU专用) 叉车项目必传
* 订单 ID
*/
private String ctnrTyp;
private String OrderId;
/**
* 容器编号 (叉车/CTU专用)
* 触发ID
*/
private String ctnrCode; //
private String TriggerId;
/**
* 容器数量(叉车堆叠专用),默认值1,仅记录堆叠的数量不记录堆叠的每个容器号
* 扩展字段4
*/
private String ctnrNum;
private String Extend4;
/**
* 任务模式
* 0-普通move 1-出库move 2-入库move 3-移库move
* 扩展字段5
*/
private String taskMode;
private String Extend5;
/**
* 工作位
* 与RCS-2000端配置的位置名称一致, 工作位名称为字母\数字\或组合
* 扩展字段6
*/
private String wbCode;
private String Extend6;
/**
* 位置路径
* AGV关键路径位置集合,与任务类型中模板配置的位置路径一一对应。待现场地图部署、配置完成后可获取
* 扩展字段7
*/
private List<PositionCodeData> positionCodePath;
private String Extend7;
/**
* 货架编号
* 不指定货架可以为空
* 扩展字段8
*/
private String podCode;
private String Extend8;
/**
* 货架方向
* “180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下”
* 不指定方向可以为空
* 如果终点不是工作台或工作台未配置操作方向则货架拣货方向podDir作为终点方向
* 如果工作台配有操作方向,则系统会根据货架拣货方向podDir和工作台操作方向计算货架终点方向
* 扩展字段9
*/
private String podDir;
private String Extend9;
/**
* 货架类型, 传空时表示随机找个货架
* 找空货架传参方式如下:
* -1: 代表不关心货架类型, 找到空货架即可.
* -2: 代表从工作位获取关联货架类型, 如果未配置, 只找空货架.
* 货架类型编号: 只找该货架类型的空货架
* 任务附加信息
*/
private String podTyp;
private TaskAdditionallInfo TaskAdditionallInfo;
/**
* 物料批次
* 物料批次或货架上的物料唯一编码,生成任务单时,货架与物料直接绑定时使用. (通过同时传podCode和materialLot来绑定或通过 wbCode 找到位置上的货架和materialLot来绑定)
* 如果是区域/策略内查找货架,可以匹配对应物料批次的货架,支持以下值:
* 0:区域/策略内查找空货架
* 1:区域/策略内查找满货架
* 其他值:查找指定物料批次对应的货架
* 巷道任务通过该字段传入特征值
* 任务附加信息类
*/
private String materialLot;
/**
* 优先级
* 从(1~127)级,最大优先级最高。为空时,采用任务模板的优先级
*/
private String priority;
/**
* AGV编号
* 填写表示指定某一编号的AGV执行该任务
*/
private String agvCode;
/**
* 任务单号
* 选填, 不填系统自动生成
*/
private String taskCode;
/**
* 组编号
* CTU场景下用于按组出库,同组任务优先拼车。 如业务需要任务组间或组内按顺序出库,则需调用料箱顺序出库(CTU)接口。
* 潜伏式场景下,通过组号来管理顺序出库的顺序,组号小的优先出库。
*/
private String groupId;
/**
* 设备类型
*/
private String agvTyp;
/**
* 选择策略
* 区域/策略中挑选货架以及根据物料批次挑选货架时的先进先出规则,支持以下4个值:
* 1:按照货架到达储位的时间顺序,先进先出
* 2:按照货架到达储位的时间顺序,先进后出
* 9:按照货架绑定物料批次的时间顺序,先进先出
* 10:按照货架绑定物料批次的时间顺序,先进后出
*/
private String positionSelStrategy;
/**
* 自定义数据
*/
private String data;
@Data
public static class TaskAdditionallInfo {
/**
* 任务ID
*/
private String TaskId;
/**
* 库存ID
*/
private String StockId;
/**
* 任务引导ID
*/
private String TaskGuideId;
/**
* 触发ID
*/
private String TriggerId;
/**
* 下一任务添加阶段
*/
private String NextTaskAddStage;
/**
* 链ID
*/
private String ChainId;
/**
* 链类型
*/
private Integer ChainType;
/**
* 链排序
*/
private Integer ChainSort;
/**
* 图号
*/
private String FigureNo;
/**
* 尺寸
*/
private String Size;
/**
* 箱号
*/
private String BoxNo;
/**
* 物料
*/
private String Mater;
/**
* 相关数量
*/
private Integer RelatedCount;
/**
* 序列号
*/
private String SerialNo;
/**
* 重量
*/
private String Weight;
/**
* 站点号
*/
private String StationNo;
/**
* 手动计数
*/
private String HandCount;
/**
* 批次
*/
private String Batch;
/**
* 前置相关任务ID
*/
private String PreviousRelatedTaskId;
/**
* 下一相关任务ID
*/
private String NextRelatedTaskId;
/**
* 级联任务开始
*/
private String CascadeTaskBeginning;
/**
* 级联任务结束
*/
private String CascadeTaskEnding;
}
}

View File

@@ -0,0 +1,23 @@
package com.ruoyi.api.domain.wcs2wms;
import lombok.Data;
/** Read-only vehicle status snapshot exposed to WMS. */
@Data
public class SrgvVehicleSnapshot {
private String guid;
private Integer deviceId;
private String deviceName;
private String agvStatus;
private Boolean online;
private Boolean healthy;
private Boolean idle;
private Integer taskNo;
private Integer alarm;
private Integer errMsg;
private Integer chargeFlag;
private Integer locked;
private Integer battery;
private String currSite;
private Integer currFloor;
}

View File

@@ -150,4 +150,6 @@ public interface IApiService
AjaxResult insertAgvQuene(HashMap<String, Object> objectObjectHashMap);
void finishAgvJob(String container);
AjaxResult tidyVehicleSnapshot();
}

View File

@@ -68,6 +68,8 @@ public interface IRequestLogService
*/
public RequestLog getRequestLog(String url, String param, String endPoint);
public RequestLog getRequestLogAgv(String url, String endPoint, String param);
/**
* 接收请求,并插入日志
* @param url

View File

@@ -17,6 +17,9 @@ import com.ruoyi.api.domain.agv.genAgvSchedulingTask.GenAgvSchedulingTaskRespons
import com.ruoyi.api.domain.agv.genAgvSchedulingTask.PositionCodeData;
import com.ruoyi.api.domain.wcs2wms.JobParam;
import com.ruoyi.api.domain.wcs2wms.ReceiveJob;
import com.ruoyi.api.domain.wcs2wms.SrgvVehicleSnapshot;
import com.ruoyi.device.srgv.domain.DeviceSrgv;
import com.ruoyi.device.srgv.mapper.DeviceSrgvMapper;
import com.ruoyi.api.service.IApiService;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
@@ -55,6 +58,8 @@ public class ApiServiceImpl implements IApiService {
private IMydoJobService mydoJobService;
@Autowired
private IAgvContainerTaskService agvContainerTaskService;
@Autowired
private DeviceSrgvMapper deviceSrgvMapper;
/**
@@ -513,4 +518,38 @@ public class ApiServiceImpl implements IApiService {
}
}
@Override
public AjaxResult tidyVehicleSnapshot() {
List<DeviceSrgv> vehicles = deviceSrgvMapper.selectDeviceSrgvList(new DeviceSrgv());
List<SrgvVehicleSnapshot> snapshots = new ArrayList<>();
for (DeviceSrgv vehicle : vehicles) {
boolean online = "1".equals(vehicle.getAgvStatus());
boolean healthy = online && value(vehicle.getAlarm()) <= 1 && value(vehicle.getErrMsg()) == 0;
boolean idle = healthy && value(vehicle.getTaskNo()) == 0
&& value(vehicle.getLocked()) == 0 && value(vehicle.getChargeFlag()) == 0;
SrgvVehicleSnapshot snapshot = new SrgvVehicleSnapshot();
snapshot.setGuid(vehicle.getGuid());
snapshot.setDeviceId(vehicle.getDeviceId());
snapshot.setDeviceName(vehicle.getDeviceName());
snapshot.setAgvStatus(vehicle.getAgvStatus());
snapshot.setOnline(online);
snapshot.setHealthy(healthy);
snapshot.setIdle(idle);
snapshot.setTaskNo(vehicle.getTaskNo());
snapshot.setAlarm(vehicle.getAlarm());
snapshot.setErrMsg(vehicle.getErrMsg());
snapshot.setChargeFlag(vehicle.getChargeFlag());
snapshot.setLocked(vehicle.getLocked());
snapshot.setBattery(vehicle.getBattery());
snapshot.setCurrSite(vehicle.getCurrSite());
snapshot.setCurrFloor(vehicle.getCurrFloor());
snapshots.add(snapshot);
}
return AjaxResult.success(snapshots);
}
private int value(Integer number) {
return number == null ? 0 : number;
}
}

View File

@@ -67,6 +67,8 @@ public interface AgvQueueMapper
*/
AgvQueue selectAgvQueueByTaskCode(String taskCode);
AgvQueue selectAgvQueueByStatus();
void insertHistory(String reqCode);
void selectKx(HashMap<String, Object> map);

View File

@@ -67,6 +67,8 @@ public interface IAgvQueueService
*/
AgvQueue selectAgvQueueByTaskCode(String taskCode);
AgvQueue selectAgvQueueByStatus();
/**
* 插入agv完成历史
* @param reqCode

View File

@@ -97,6 +97,11 @@ public class AgvQueueServiceImpl implements IAgvQueueService
return agvQueueMapper.selectAgvQueueByTaskCode(taskCode);
}
@Override
public AgvQueue selectAgvQueueByStatus() {
return agvQueueMapper.selectAgvQueueByStatus();
}
@Override
public void insertHistory(String reqCode) {
agvQueueMapper.insertHistory(reqCode);

View File

@@ -62,6 +62,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where task_code = #{taskCode}
</select>
<select id="selectAgvQueueByStatus" resultMap="AgvQueueResult">
select top(1)* from agv_queue
where status=0
</select>
<insert id="insertAgvQueue" parameterType="AgvQueue">
insert into agv_queue
<trim prefix="(" suffix=")" suffixOverrides=",">

View File

@@ -262,10 +262,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
a.target_cargo_space_id,
ROW_NUMBER() OVER (
PARTITION BY b.the_floor, b.group_coding_no
ORDER BY b.group_coding DESC,
CASE WHEN a.in_or_out = 30 THEN 0 ELSE 1 END,
a.create_time ASC,
a.job_id ASC
ORDER BY b.group_coding desc
) AS rn
FROM mydo_job_wcs a
INNER JOIN bas_cargo_space b

View File

@@ -119,6 +119,7 @@ public class SecurityConfig
.antMatchers("/api/agv/**").permitAll()
.antMatchers("/device/api/**").permitAll()
.antMatchers("/wcs2Wms/api/**").permitAll()
.antMatchers("/agv/api/**").permitAll()
.antMatchers("/test/**").permitAll()
.antMatchers("/largeScreen/monitor/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证

View File

@@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getTidyStatus() {
return request({ url: '/algorithm/tidy/status', method: 'get' })
}
export function updateTidyMode(mode) {
return request({ url: '/algorithm/tidy/mode', method: 'put', data: { mode } })
}

View File

@@ -0,0 +1,33 @@
<template>
<div class="app-container tidy-page">
<el-card>
<div slot="header"><span>理货控制</span></div>
<el-switch v-model="manual" active-text="手动理货" inactive-text="自动理货" :disabled="loading || !hasEdit" @change="changeMode" />
<span class="mode-status">当前模式:{{ modeLabel }}</span>
</el-card>
</div>
</template>
<script>
import { getTidyStatus, updateTidyMode } from '@/api/algorithm/tidy'
export default {
name: 'TidyControl',
data() { return { manual: false, mode: 'AUTO', loading: false, timer: null, hasEdit: this.$auth.hasPermi('algorithm:tidy:edit') } },
computed: { modeLabel() { return this.mode === 'MANUAL' ? '手动' : '自动' } },
created() { this.refresh(); this.timer = setInterval(this.refresh, 5000) },
beforeDestroy() { if (this.timer) { clearInterval(this.timer); this.timer = null } },
methods: {
refresh() { getTidyStatus().then(res => { const data = res.data || {}; this.mode = data.mode || 'AUTO'; this.manual = this.mode === 'MANUAL' }).catch(() => {}) },
changeMode(value) {
const previous = this.mode
this.loading = true
updateTidyMode(value ? 'MANUAL' : 'AUTO').then(res => { const data = res.data || {}; this.mode = data.mode || (value ? 'MANUAL' : 'AUTO') }).catch(() => { this.manual = previous === 'MANUAL'; this.$message.error('理货模式切换失败') }).finally(() => { this.loading = false })
}
}
}
</script>
<style scoped>
.mode-status { margin-left: 16px; color: #606266; }
</style>

View File

@@ -157,7 +157,6 @@ export default {
{ key: 'kx', label: '空闲', value: d.kx, dict: 'ssj_kx' },
{ key: 'dw', label: '到位', value: d.dw, dict: 'ssj_dw' },
{ key: 'exception', label: '异常', value: d.exception, dict: 'ssj_ex'},
]
}
if (dev.kind === 'srgv') {

View File

@@ -9,7 +9,7 @@ const CompressionPlugin = require('compression-webpack-plugin')
const name = process.env.VUE_APP_TITLE || 'FORTUCKY WCS SYSTEM' // 网页标题
const baseUrl = 'http://localhost:8081' // 后端接口地址(你的后端端口是8081)
const baseUrl = 'http://192.168.188.236:8081' // 后端接口地址(你的后端端口是8081)
const port = process.env.port || process.env.npm_config_port || 80 // 前端端口
@@ -18,6 +18,7 @@ module.exports = {
outputDir: 'dist',
assetsDir: 'static',
productionSourceMap: false,
parallel: false,
transpileDependencies: ['quill'],
devServer: {
host: '0.0.0.0',