package com.zy.asrs.controller; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.core.common.Cools; import com.core.common.R; import com.core.exception.CoolException; import com.zy.asrs.domain.Result.CancelTaskBatchResult; import com.zy.asrs.domain.param.*; import com.core.annotations.ManagerAuth; import com.zy.asrs.entity.DeviceConfig; import com.zy.asrs.entity.LocMast; import com.zy.asrs.entity.WrkMast; import com.zy.asrs.service.DeviceConfigService; import com.zy.asrs.service.LocMastService; import com.zy.asrs.service.RuntimeConfigService; import com.zy.asrs.service.WrkMastService; import com.zy.common.annotations.OpenApiLog; import com.zy.common.service.CommonService; import com.zy.core.cache.SlaveConnection; import com.zy.core.enums.SlaveType; import com.zy.core.enums.WrkIoType; import com.zy.core.model.protocol.CrnProtocol; import com.zy.core.model.protocol.DualCrnProtocol; import com.zy.core.model.protocol.RgvProtocol; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.network.fake.FakeConfigKeys; import com.zy.core.thread.CrnThread; import com.zy.core.thread.DualCrnThread; import com.zy.core.thread.RgvThread; import com.zy.core.thread.StationThread; import com.zy.system.entity.Config; import com.zy.system.service.ConfigService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @Slf4j @RestController @RequestMapping("/openapi") public class OpenController { @Value("${mainProcessPlugin}") private String mainProcessPlugin; @Value("${app.version:1.0.0}") private String appVersion; @Value("${app.version-type:stable}") private String appVersionType; @Autowired private CommonService commonService; @Autowired private LocMastService locMastService; @Autowired private WrkMastService wrkMastService; @Autowired private ConfigService configService; @Autowired private DeviceConfigService deviceConfigService; @Autowired private RuntimeConfigService runtimeConfigService; // 移库任务 @PostMapping("/createLocMoveTask") @OpenApiLog(memo = "移库任务") public R createLocMoveTask(@RequestBody CreateLocMoveTaskParam param) { if (param == null) { return R.error("参数不能为空"); } boolean result = commonService.createLocMoveTask(param); if (result) { return R.ok(); } return R.error("生成移库任务失败"); } // 入库任务 @PostMapping("/createInTask") @OpenApiLog(memo = "入库任务") public R createInTask(@RequestBody CreateInTaskParam param) { if (param == null) { return R.error("参数不能为空"); } WrkMast wrkMast = commonService.createInTask(param); if (wrkMast != null) { return R.ok(); } return R.error("生成入库任务失败"); } // 出库任务 @PostMapping("/createOutTask") @OpenApiLog(memo = "出库任务") public R createOutTask(@RequestBody CreateOutTaskParam param) { if (param == null) { return R.error("参数不能为空"); } boolean result = commonService.createOutTask(param); if (result) { return R.ok(); } return R.error("生成出库任务失败"); } // 批量出库任务 @PostMapping("/createOutTaskBatch") @OpenApiLog(memo = "批量出库任务") @Transactional public R createOutTaskBatch(@RequestBody CreateOutTaskBatchParam param) { if (param == null) { return R.error("参数不能为空"); } boolean result = commonService.createOutTaskBatch(param); if (result) { return R.ok(); } return R.error("生成批量出库任务失败"); } @PostMapping("/completeTask") @OpenApiLog(memo = "任务完成") public R completeTask(@RequestBody CompleteTaskParam param) { if (param == null) { return R.error("参数不能为空"); } boolean completeTask = commonService.completeTask(param); if (completeTask) { return R.ok(); } return R.error("任务完成失败"); } @PostMapping("/cancelTask") @OpenApiLog(memo = "任务取消") public R cancelTask(@RequestBody CancelTaskParam param) { if (param == null) { return R.error("参数不能为空"); } boolean completeTask = commonService.cancelTask(param); if (completeTask) { return R.ok(); } return R.error("任务取消失败"); } @PostMapping("/manualRollbackTask") @OpenApiLog(memo = "任务人工回滚") public R manualRollbackTask(@RequestBody ManualRollbackTaskParam param) { if (param == null) { return R.error("参数不能为空"); } boolean rollback = commonService.manualRollbackTask(param); if (rollback) { return R.ok(); } return R.error("任务人工回滚失败"); } @PostMapping("/cancelTaskBatch") @OpenApiLog(memo = "任务批量取消") public R cancelTaskBatch(@RequestBody CancelTaskBatchParam param) { if (param == null) { return R.error("参数不能为空"); } CancelTaskBatchResult result = commonService.cancelTaskBatch(param); return R.ok().add(result); } @PostMapping("/updateTaskPriorityAndBatchSeq") @OpenApiLog(memo = "修改任务优先级和批次序号") public R updateTaskPriorityAndBatchSeq(@RequestBody UpdateTaskPriorityAndBatchSeqParam param) { if (param == null) { return R.error("参数不能为空"); } boolean result = commonService.updateTaskPriorityAndBatchSeq(param); if (result) { return R.ok(); } return R.error("修改任务优先级和批次序号失败"); } @PostMapping("/cancelOutTaskBatchInfo") @OpenApiLog(memo = "取消出库任务批次和批次序号") public R cancelOutTaskBatchInfo(@RequestBody CancelTaskBatchParam param) { if (param == null) { return R.error("参数不能为空"); } CancelTaskBatchResult result = commonService.cancelOutTaskBatchInfo(param); return R.ok().add(result); } @PostMapping("/deviceStatus") // @OpenApiLog(memo = "获取设备状态") public R getDeviceStatus() { HashMap map = new HashMap<>(); // 获取堆垛机数据 ArrayList crnProtocols = new ArrayList<>(); List crnList = deviceConfigService.list(new QueryWrapper() .eq("device_type", String.valueOf(SlaveType.Crn))); for (DeviceConfig device : crnList) { CrnThread crnThread = (CrnThread) SlaveConnection.get(SlaveType.Crn, device.getDeviceNo()); if (crnThread == null) { continue; } CrnProtocol crnProtocol = crnThread.getStatus(); if (crnProtocol == null) { continue; } crnProtocols.add(crnProtocol); } // 获取RGV数据 ArrayList rgvProtocols = new ArrayList<>(); List rgvList = deviceConfigService.list(new QueryWrapper() .eq("device_type", String.valueOf(SlaveType.Rgv))); for (DeviceConfig device : rgvList) { RgvThread rgvThread = (RgvThread) SlaveConnection.get(SlaveType.Rgv, device.getDeviceNo()); if (rgvThread == null) { continue; } RgvProtocol rgvProtocol = rgvThread.getStatus(); if (rgvProtocol == null) { continue; } rgvProtocols.add(rgvProtocol); } // 获取双工位堆垛机数据 ArrayList dualCrnProtocols = new ArrayList<>(); List dualCrnList = deviceConfigService.list(new QueryWrapper() .eq("device_type", String.valueOf(SlaveType.DualCrn))); for (DeviceConfig device : dualCrnList) { DualCrnThread dualCrnThread = (DualCrnThread) SlaveConnection.get(SlaveType.DualCrn, device.getDeviceNo()); if (dualCrnThread == null) { continue; } DualCrnProtocol dualCrnProtocol = dualCrnThread.getStatus(); if (dualCrnProtocol == null) { continue; } dualCrnProtocols.add(dualCrnProtocol); } // 获取输送站点数据 ArrayList stationProtocols = new ArrayList<>(); List stationList = deviceConfigService.list(new QueryWrapper() .eq("device_type", String.valueOf(SlaveType.Devp))); for (DeviceConfig device : stationList) { StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, device.getDeviceNo()); if (stationThread == null) { continue; } List stationProtocolList = stationThread.getStatus(); if (stationProtocolList == null) { continue; } stationProtocols.addAll(stationProtocolList); } map.put("crnList", crnProtocols); map.put("rgvList", rgvList); map.put("dualCrnList", dualCrnProtocols); map.put("stationList", stationProtocols); return R.ok().add(map); } @PostMapping("/stationStatus") public R getStationStatus(@RequestBody GetStationStatusParam param) { // 获取输送站点数据 List stationProtocols = new ArrayList<>(); List devpList = deviceConfigService.list(new QueryWrapper() .eq("device_type", String.valueOf(SlaveType.Devp)) ); for (DeviceConfig device : devpList) { StationThread stationThread = (StationThread) SlaveConnection.get(SlaveType.Devp, device.getDeviceNo()); if (stationThread == null) { continue; } List tmp = new ArrayList<>(); if(param.getStationIds() == null || param.getStationIds().isEmpty()) { tmp.addAll(stationThread.getStatus()); }else { Map statusMap = stationThread.getStatusMap(); for (Integer stationId : param.getStationIds()) { StationProtocol stationProtocol = statusMap.get(stationId); if (stationProtocol == null) { continue; } tmp.add(stationProtocol); } } stationProtocols.addAll(tmp); } return R.ok().add(stationProtocols); } @PostMapping("/getLocInformation") @OpenApiLog(memo = "获取指定库位信息") public R getLocInformation(@RequestBody GetLocInformationParam param) { if (param == null) { return R.error("参数不能为空"); } LocMast locMast = locMastService.queryByLoc(param.getLocNo()); if (locMast == null) { return R.error("库位信息不存在"); } HashMap map = new HashMap<>(); map.put("locNo", locMast.getLocNo()); map.put("locSts", locMast.getLocSts()); map.put("barcode", locMast.getBarcode()); return R.ok().add(map); } @PostMapping("/getAllLocInformation") @OpenApiLog(memo = "获取全部库位信息") public R getAllLocInformation(@RequestBody GetAllLocInformationParam param) { List> list = new ArrayList<>(); QueryWrapper wrapper = new QueryWrapper<>(); if (!Cools.isEmpty(param.getRow())) { wrapper.eq("row1", param.getRow()); } if (!Cools.isEmpty(param.getLev())) { wrapper.eq("lev1", param.getLev()); } List locMasts = locMastService.list(wrapper); if (locMasts.isEmpty()) { return R.ok().add(list); } for (LocMast locMast : locMasts) { HashMap map = new HashMap<>(); map.put("locNo", locMast.getLocNo()); map.put("locSts", locMast.getLocSts()); map.put("barcode", locMast.getBarcode()); map.put("row", locMast.getRow1()); map.put("bay", locMast.getBay1()); map.put("lev", locMast.getLev1()); list.add(map); } return R.ok().add(list); } @PostMapping("/queryTask") @OpenApiLog(memo = "查询任务") public R queryTask(@RequestBody QueryTaskParam param) { QueryWrapper wrapper = new QueryWrapper<>(); if (param.getTaskNo() != null) { wrapper.eq("wms_wrk_no", param.getTaskNo()); } if (param.getTaskType() != null) { WrkIoType ioType = WrkIoType.get(param.getTaskType()); if (ioType == null) { return R.error("任务类型不存在"); } wrapper.eq("io_type", ioType.id); } List wrkMasts = wrkMastService.list(wrapper); return R.ok().add(wrkMasts); } @GetMapping("/systemStatus") public R systemStatus() { return R.ok(); } @GetMapping("/getSystemVersion") public R getSystemVersion() { HashMap map = new HashMap<>(); map.put("version", appVersion); map.put("versionType", appVersionType); return R.ok().add(map); } @GetMapping("/getBranding") public R getBranding() { HashMap map = new HashMap<>(); map.put("logo", configService.getConfigValue("system.logo", "/static/images/zy-logo.png")); map.put("title", configService.getConfigValue("system.title", "浙江中扬 - 自动化立体仓库 - WCS")); map.put("copyright", configService.getConfigValue("system.copyright", "© 2026 浙江中扬立库技术有限公司")); return R.ok().add(map); } @PostMapping("/runtimeConfig/update") @OpenApiLog(memo = "修改运行参数") public R updateRuntimeConfig(@RequestBody RuntimeConfigUpdateParam param) { if (param == null || param.getConfigMap() == null || param.getConfigMap().isEmpty()) { return R.error("参数不能为空"); } return R.ok().add(runtimeConfigService.updateRuntimeConfig(param.getConfigMap())); } @GetMapping("/getFakeSystemRunStatus") public R getFakeSystemRunStatus() { HashMap map = new HashMap<>(); if (mainProcessPlugin.contains("Fake")) { map.put("running", false); map.put("isFake", true); Config config = configService.getOne(new QueryWrapper().eq("code", "enableFake")); if (config != null) { if (config.getValue().equals("Y")) { map.put("running", true); } } } else { map.put("isFake", false); } return R.ok().add(map); } @PostMapping("/startFakeSystem") @OpenApiLog(memo = "启动仿真模拟") public R startFakeSystem() { Config config = configService.getOne(new QueryWrapper().eq("code", "enableFake")); if (config != null) { config.setValue("Y"); configService.updateById(config); } return R.ok(); } @PostMapping("/stopFakeSystem") @OpenApiLog(memo = "停止仿真模拟") public R stopFakeSystem() { Config config = configService.getOne(new QueryWrapper().eq("code", "enableFake")); if (config != null) { config.setValue("N"); configService.updateById(config); } return R.ok(); } @GetMapping("/fakeConfig/auth") @ManagerAuth public R getFakeConfig() { LinkedHashMap map = new LinkedHashMap<>(); for (String key : FakeConfigKeys.ALL_KEYS) { String defaultValue = FakeConfigKeys.DEFAULTS.get(key); map.put(key, configService.getConfigValue(key, defaultValue)); } return R.ok().add(map); } @PostMapping("/fakeConfig/save/auth") @ManagerAuth public R saveFakeConfig(@RequestBody FakeConfigSaveParam param) { if (param == null || param.getConfigMap() == null || param.getConfigMap().isEmpty()) { return R.error("参数不能为空"); } Set allowKeys = FakeConfigKeys.ALL_KEYS; Map normalizedMap = new LinkedHashMap<>(); for (Map.Entry entry : param.getConfigMap().entrySet()) { String key = entry.getKey(); if (!allowKeys.contains(key)) { return R.error("不支持的配置项: " + key); } normalizedMap.put(key, normalizeFakeConfigValue(key, entry.getValue())); } validateFakeCrnLaserConfig(normalizedMap); for (Map.Entry entry : normalizedMap.entrySet()) { if (!configService.saveConfigValue(entry.getKey(), entry.getValue())) { return R.error("保存失败: " + entry.getKey()); } } configService.refreshSystemConfigCache(); return getFakeConfig(); } private void validateFakeCrnLaserConfig(Map normalizedMap) { long bayMin = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_BAY_MIN); long bayMax = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_BAY_MAX); long laserMin = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_LASER_MIN); long laserMax = resolveFakeLongValue(normalizedMap, FakeConfigKeys.FAKE_CRN_LASER_MAX); if (bayMax <= bayMin) { throw new CoolException("堆垛机 bay 最大值必须大于最小值"); } if (laserMax <= laserMin) { throw new CoolException("堆垛机镭射最大值必须大于最小值"); } } private long resolveFakeLongValue(Map normalizedMap, String key) { String value = normalizedMap.get(key); if (value == null) { value = configService.getConfigValue(key, FakeConfigKeys.DEFAULTS.get(key)); } return Long.parseLong(value); } private String normalizeFakeConfigValue(String key, Object rawValue) { if (rawValue == null) { throw new CoolException(key + " 参数不能为空"); } String value = String.valueOf(rawValue).trim(); if (FakeConfigKeys.BOOLEAN_KEYS.contains(key)) { if (!"Y".equalsIgnoreCase(value) && !"N".equalsIgnoreCase(value)) { throw new CoolException(key + " 仅支持 Y/N"); } return value.toUpperCase(); } if (FakeConfigKeys.LONG_KEYS.contains(key)) { long parsed; try { parsed = Long.parseLong(value); } catch (Exception e) { throw new CoolException(key + " 必须为非负整数"); } if (parsed < 0) { throw new CoolException(key + " 必须为非负整数"); } return String.valueOf(parsed); } throw new CoolException("不支持的配置项: " + key); } }