|
|
|
|
@ -9,6 +9,7 @@ import com.aucma.dms.domain.*;
|
|
|
|
|
import com.aucma.dms.domain.dto.DmsBaseDeviceLedgerDTO;
|
|
|
|
|
import com.aucma.dms.domain.vo.DmsBillsFaultInstanceScanVo;
|
|
|
|
|
import com.aucma.dms.domain.vo.DmsBillsInspectInstanceScanVo;
|
|
|
|
|
import com.aucma.dms.domain.vo.DmsPdaDeviceParamUpdateVo;
|
|
|
|
|
import com.aucma.base.domain.BaseDeviceLedger;
|
|
|
|
|
import com.aucma.base.domain.BaseOrderInfo;
|
|
|
|
|
import com.aucma.base.service.IBaseDeviceLedgerService;
|
|
|
|
|
@ -252,410 +253,7 @@ public class DmsMobileController extends BaseController {
|
|
|
|
|
return dms;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-按物料关键字查询关联工单
|
|
|
|
|
*/
|
|
|
|
|
@GetMapping("/order/listByMaterial")
|
|
|
|
|
public AjaxResult listOrdersByMaterial(String keyword) {
|
|
|
|
|
// 物料关键字是PDA唯一输入入口,空值时直接拒绝,避免放大后端模糊查询范围
|
|
|
|
|
if (keyword == null || keyword.trim().isEmpty()) {
|
|
|
|
|
throw new ServiceException("物料关键字不能为空");
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// Why:先按物料主数据检索,再按物料编码反查订单,能保证PDA搜索口径与主数据一致
|
|
|
|
|
List<BaseOrderInfo> orders = baseOrderInfoService.selectPdaOrderListByMaterialKeyword(keyword.trim());
|
|
|
|
|
return success(orders);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("PDA按物料查询工单失败 | keyword={}, 异常信息: {}", keyword, e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("查询工单失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-维护订单状态与数量
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/order/updateStatusAndQty")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult updateOrderStatusAndQty(@RequestBody BaseOrderInfo baseOrderInfo) {
|
|
|
|
|
// 请求体为空时没有任何维护目标,直接拦截比进入service后再判空更清晰
|
|
|
|
|
if (baseOrderInfo == null) {
|
|
|
|
|
throw new ServiceException("请求体不能为空");
|
|
|
|
|
}
|
|
|
|
|
// PDA下拉选中订单后至少应能定位到一条工单,兼容前端传objId或orderCode两种方式
|
|
|
|
|
if (baseOrderInfo.getObjId() == null
|
|
|
|
|
&& (baseOrderInfo.getOrderCode() == null || baseOrderInfo.getOrderCode().trim().isEmpty())) {
|
|
|
|
|
throw new ServiceException("objId和orderCode不能同时为空");
|
|
|
|
|
}
|
|
|
|
|
// 状态和数量都在控制器前置校验,避免脏数据落到service或数据库层
|
|
|
|
|
validateOrderExecutionStatus(baseOrderInfo.getExecutionStatus());
|
|
|
|
|
validateOrderQty(baseOrderInfo.getActualCompleteQty(), "完工数量");
|
|
|
|
|
validateOrderQty(baseOrderInfo.getActualDefectQty(), "不良数量");
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Why:PDA订单维护属于人工修正场景,统一走service封装,避免控制器直接拼装状态流转细节
|
|
|
|
|
int rows = baseOrderInfoService.updatePdaOrderExecution(baseOrderInfo);
|
|
|
|
|
return rows > 0 ? success(rows) : error("工单不存在或更新失败");
|
|
|
|
|
} catch (ServiceException e) {
|
|
|
|
|
throw e;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("PDA维护订单失败 | objId={}, orderCode={}, executionStatus={}, actualCompleteQty={}, 异常信息: {}",
|
|
|
|
|
baseOrderInfo.getObjId(), baseOrderInfo.getOrderCode(), baseOrderInfo.getExecutionStatus(),
|
|
|
|
|
baseOrderInfo.getActualCompleteQty(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("维护订单失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateOrderExecutionStatus(String executionStatus) {
|
|
|
|
|
// PDA当前仅允许维护执行态,保持与execution.vue和现有执行页状态枚举一致
|
|
|
|
|
if (executionStatus == null || executionStatus.trim().isEmpty()) {
|
|
|
|
|
throw new ServiceException("执行状态不能为空");
|
|
|
|
|
}
|
|
|
|
|
String normalized = executionStatus.trim();
|
|
|
|
|
if (!ORDER_EXECUTION_PENDING.equals(normalized)
|
|
|
|
|
&& !ORDER_EXECUTION_RUNNING.equals(normalized)
|
|
|
|
|
&& !ORDER_EXECUTION_PAUSED.equals(normalized)
|
|
|
|
|
&& !ORDER_EXECUTION_COMPLETED.equals(normalized)) {
|
|
|
|
|
throw new ServiceException("执行状态不合法");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateOrderQty(Long qty, String fieldName) {
|
|
|
|
|
// 数量允许为空,表示本次只改状态;但一旦传值就必须满足非负约束
|
|
|
|
|
if (qty != null && qty < 0) {
|
|
|
|
|
throw new ServiceException(fieldName + "不能小于0");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ========== PDA 停机相关 ==========
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取OLD开头的设备列表(仅启用)
|
|
|
|
|
*/
|
|
|
|
|
@GetMapping("/device/listOld")
|
|
|
|
|
public AjaxResult listOldDevices() {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
List<DmsBaseDeviceLedgerDTO> resultList = new ArrayList<>();
|
|
|
|
|
if (!CollectionUtils.isEmpty(list)) {
|
|
|
|
|
for (BaseDeviceLedger base : list) {
|
|
|
|
|
if (base.getDeviceCode() != null && base.getDeviceCode().startsWith("OLD")) {
|
|
|
|
|
resultList.add(convertDeviceLedgerToDto(convertToDeviceLedger(base)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return success(resultList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-获取停机原因列表(仅启用 isFlag=1)
|
|
|
|
|
*/
|
|
|
|
|
@GetMapping("/shutReason/list")
|
|
|
|
|
public AjaxResult listShutReasonsForPda(DmsBaseShutReason reason) {
|
|
|
|
|
reason.setIsFlag("1");
|
|
|
|
|
List<DmsBaseShutReason> list = dmsBaseShutReasonService.selectDmsBaseShutReasonList(reason);
|
|
|
|
|
return success(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-新增停机记录:根据停机原因自动匹配停机类型
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/shutDown/add")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult addShutDownForPda(@RequestBody DmsRecordShutDown shutDown) {
|
|
|
|
|
try {
|
|
|
|
|
// 若传入了停机原因ID,则查询原因并回填类型
|
|
|
|
|
if (shutDown.getShutReason() != null) {
|
|
|
|
|
DmsBaseShutReason query = new DmsBaseShutReason();
|
|
|
|
|
query.setShutReason(shutDown.getShutReason());
|
|
|
|
|
query.setIsFlag("1");
|
|
|
|
|
List<DmsBaseShutReason> reasons = dmsBaseShutReasonService.selectDmsBaseShutReasonList(query);
|
|
|
|
|
if (!reasons.isEmpty()) {
|
|
|
|
|
shutDown.setShutType(reasons.get(0).getShutTypeId());
|
|
|
|
|
shutDown.setShutReasonId(reasons.get(0).getShutReasonId());
|
|
|
|
|
// 若前端未传 deviceId,尝试从原因带出
|
|
|
|
|
if (shutDown.getDeviceId() == null) {
|
|
|
|
|
shutDown.setDeviceId(reasons.get(0).getDeviceId());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 默认启用标识
|
|
|
|
|
if (shutDown.getIsFlag() == null) {
|
|
|
|
|
shutDown.setIsFlag(1L);
|
|
|
|
|
}
|
|
|
|
|
// 新增停机记录默认未结束
|
|
|
|
|
if (shutDown.getDowntimeFlag() == null) {
|
|
|
|
|
shutDown.setDowntimeFlag("0");
|
|
|
|
|
}
|
|
|
|
|
// 若未传入开始时间,则使用当前时间
|
|
|
|
|
if (shutDown.getShutBeginTime() == null) {
|
|
|
|
|
shutDown.setShutBeginTime(new Date());
|
|
|
|
|
}
|
|
|
|
|
int rows = dmsRecordShutDownService.insertDmsRecordShutDown(shutDown);
|
|
|
|
|
|
|
|
|
|
// 对指定设备(OLD-01~OLD-05)同步写入三色灯状态参数,供设备状态统计使用
|
|
|
|
|
String deviceCode = shutDown.getDeviceCode();
|
|
|
|
|
if (deviceCode != null && deviceCode.startsWith("OLD-")) {
|
|
|
|
|
// 新增停机记录代表进入停机,三色灯置为“暂停”
|
|
|
|
|
insertTriColorStatusParams(deviceCode, shutDown.getDeviceId(), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success(rows);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA新增停机记录失败 | deviceCode={}, shutReason={}, deviceId={}, 异常信息: {}",
|
|
|
|
|
shutDown.getDeviceCode(), shutDown.getShutReason(), shutDown.getDeviceId(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("新增停机记录失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-获取待处理停机记录列表
|
|
|
|
|
* 返回条件:停机结束时间为空(老设备未完成)或 停机原因ID=1(新设备默认原因待修改)
|
|
|
|
|
*/
|
|
|
|
|
@GetMapping("/shutDown/get")
|
|
|
|
|
public AjaxResult getShutDownForPda() {
|
|
|
|
|
try {
|
|
|
|
|
List<DmsRecordShutDown> list = dmsRecordShutDownService.selectPdaShutDownList();
|
|
|
|
|
return success(list);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA获取待处理停机记录失败 | 异常信息: {}", e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("获取停机记录失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-更新停机记录
|
|
|
|
|
* 老设备(shutEndTime为空):更新停机结束时间、计算停机时长、更新停机原因ID
|
|
|
|
|
* 新设备(shutEndTime不为空):仅更新停机原因ID
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/shutDown/complete")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult completeShutDownForPda(@RequestBody DmsRecordShutDown shutDown) {
|
|
|
|
|
if (shutDown.getRecordShutDownId() == null) {
|
|
|
|
|
throw new ServiceException("recordShutDownId不能为空");
|
|
|
|
|
}
|
|
|
|
|
if (shutDown.getShutReasonId() == null) {
|
|
|
|
|
throw new ServiceException("shutReasonId不能为空");
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// 查询原记录
|
|
|
|
|
DmsRecordShutDown origin = dmsRecordShutDownService.selectDmsRecordShutDownByRecordShutDownId(shutDown.getRecordShutDownId());
|
|
|
|
|
if (origin == null) {
|
|
|
|
|
throw new ServiceException("停机记录不存在");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建更新对象,仅设置需要更新的字段
|
|
|
|
|
DmsRecordShutDown updateRecord = new DmsRecordShutDown();
|
|
|
|
|
updateRecord.setRecordShutDownId(shutDown.getRecordShutDownId());
|
|
|
|
|
updateRecord.setShutReasonId(shutDown.getShutReasonId());
|
|
|
|
|
|
|
|
|
|
if (origin.getShutEndTime() == null) {
|
|
|
|
|
// 老设备:标记停机已结束
|
|
|
|
|
updateRecord.setDowntimeFlag("1");
|
|
|
|
|
// 老设备:补充结束时间和停机时长
|
|
|
|
|
Date end = new Date();
|
|
|
|
|
Date begin = origin.getShutBeginTime();
|
|
|
|
|
updateRecord.setShutEndTime(end);
|
|
|
|
|
if (begin != null) {
|
|
|
|
|
long minutes = Math.max(0, (end.getTime() - begin.getTime()) / 60000);
|
|
|
|
|
updateRecord.setShutTime(BigDecimal.valueOf(minutes));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 新设备(shutEndTime已有值):仅更新shutReasonId,无需额外处理
|
|
|
|
|
|
|
|
|
|
int rows = dmsRecordShutDownService.updateDmsRecordShutDown(updateRecord);
|
|
|
|
|
|
|
|
|
|
// 对老设备(OLD-01~OLD-05)同步写入三色灯状态参数
|
|
|
|
|
if (origin.getShutEndTime() == null && origin.getDeviceId() != null) {
|
|
|
|
|
// 原记录不含deviceCode,需通过deviceId反查设备编号
|
|
|
|
|
BaseDeviceLedger deviceQuery = new BaseDeviceLedger();
|
|
|
|
|
deviceQuery.setObjId(origin.getDeviceId());
|
|
|
|
|
List<BaseDeviceLedger> devices = baseDeviceLedgerService.selectBaseDeviceLedgerList(deviceQuery);
|
|
|
|
|
if (!devices.isEmpty()) {
|
|
|
|
|
String deviceCode = devices.get(0).getDeviceCode();
|
|
|
|
|
if (deviceCode != null && deviceCode.startsWith("OLD-")) {
|
|
|
|
|
// 完成停机代表重新运行,三色灯置为"运行"
|
|
|
|
|
insertTriColorStatusParams(deviceCode, origin.getDeviceId(), true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rows > 0 ? success(origin.getRecordShutDownId()) : error("更新停机记录失败");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA完成停机记录失败 | recordShutDownId={}, shutReasonId={}, 异常信息: {}",
|
|
|
|
|
shutDown.getRecordShutDownId(), shutDown.getShutReasonId(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("完成停机失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 插入三色灯状态参数(运行/暂停/报警),以“暂停”为当前状态
|
|
|
|
|
*/
|
|
|
|
|
private void insertTriColorStatusParams(String deviceCode, Long deviceId, boolean running) {
|
|
|
|
|
// 仅处理 OLD-01~OLD-05
|
|
|
|
|
if (!"OLD-01".equals(deviceCode) && !"OLD-02".equals(deviceCode)
|
|
|
|
|
&& !"OLD-03".equals(deviceCode) && !"OLD-04".equals(deviceCode)
|
|
|
|
|
&& !"OLD-05".equals(deviceCode)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 补齐 deviceId(如果未传)
|
|
|
|
|
Long resolvedDeviceId = deviceId;
|
|
|
|
|
if (resolvedDeviceId == null) {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setDeviceCode(deviceCode);
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
if (!list.isEmpty()) {
|
|
|
|
|
resolvedDeviceId = list.get(0).getObjId();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Date now = new Date();
|
|
|
|
|
// 运行、暂停、报警 三个参数,运行/暂停取决于状态
|
|
|
|
|
List<BaseDeviceParamVal> records = new ArrayList<>();
|
|
|
|
|
String runVal = running ? "True" : "False";
|
|
|
|
|
String pauseVal = running ? "False" : "True";
|
|
|
|
|
records.add(buildParamVal(PARAM_CODE_PDA_CUSTOM, deviceCode, resolvedDeviceId, "机台状态-三色灯机器运行", runVal, now));
|
|
|
|
|
records.add(buildParamVal(PARAM_CODE_PDA_CUSTOM, deviceCode, resolvedDeviceId, "机台状态-三色灯机器暂停", pauseVal, now));
|
|
|
|
|
records.add(buildParamVal(PARAM_CODE_PDA_CUSTOM, deviceCode, resolvedDeviceId, "机台状态-三色灯机器报警", "False", now));
|
|
|
|
|
|
|
|
|
|
for (BaseDeviceParamVal rec : records) {
|
|
|
|
|
baseDeviceParamValService.insertBaseDeviceParamVal(rec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BaseDeviceParamVal buildParamVal(String paramCode, String deviceCode, Long deviceId,
|
|
|
|
|
String paramName, String paramValue, Date time) {
|
|
|
|
|
BaseDeviceParamVal v = new BaseDeviceParamVal();
|
|
|
|
|
v.setParamCode(paramCode);
|
|
|
|
|
v.setDeviceCode(deviceCode);
|
|
|
|
|
v.setDeviceId(deviceId);
|
|
|
|
|
v.setParamName(paramName);
|
|
|
|
|
v.setParamValue(paramValue);
|
|
|
|
|
v.setCollectTime(time);
|
|
|
|
|
v.setRecordTime(time);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-选择设备后更新运行时间(写入参数:机台状态-实际生产时间)
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/device/updateRunTime")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult updateDeviceRunTime(@RequestBody BaseDeviceParamVal baseDeviceParamVal) {
|
|
|
|
|
return updatePdaDeviceParamValue(baseDeviceParamVal, PARAM_NAME_ACTUAL_RUNTIME, false, "运行时间");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-选择设备后更新当日产量(写入参数:机台状态-实际产出数量)
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/device/updateDailyOutput")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult updateDeviceDailyOutput(@RequestBody BaseDeviceParamVal baseDeviceParamVal) {
|
|
|
|
|
return updatePdaDeviceParamValue(baseDeviceParamVal, PARAM_NAME_DAILY_OUTPUT, true, "当日产量");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private AjaxResult updatePdaDeviceParamValue(BaseDeviceParamVal baseDeviceParamVal, String paramName,
|
|
|
|
|
boolean integerRequired, String bizName) {
|
|
|
|
|
// 请求体为空时直接拒绝,避免后续空指针并明确返回可读错误
|
|
|
|
|
if (baseDeviceParamVal == null) {
|
|
|
|
|
throw new ServiceException("请求体不能为空");
|
|
|
|
|
}
|
|
|
|
|
// PDA上报的业务值统一从paramValue读取,后续会按业务类型做数值校验
|
|
|
|
|
String rawValue = baseDeviceParamVal.getParamValue();
|
|
|
|
|
if (rawValue == null || rawValue.trim().isEmpty()) {
|
|
|
|
|
throw new ServiceException(bizName + "不能为空");
|
|
|
|
|
}
|
|
|
|
|
// 运行时间允许小数;当日产量要求整数,规则由integerRequired控制
|
|
|
|
|
validateNumericParamValue(rawValue.trim(), integerRequired, bizName);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 兼容PDA只传deviceId或只传deviceCode的场景,统一补齐设备主数据标识
|
|
|
|
|
fillDeviceIdentity(baseDeviceParamVal);
|
|
|
|
|
Date now = new Date();
|
|
|
|
|
// 参数名由后端强制指定,避免前端透传导致写错业务口径
|
|
|
|
|
baseDeviceParamVal.setParamName(paramName);
|
|
|
|
|
baseDeviceParamVal.setParamValue(rawValue.trim());
|
|
|
|
|
if (baseDeviceParamVal.getParamCode() == null || baseDeviceParamVal.getParamCode().trim().isEmpty()) {
|
|
|
|
|
// Why:该参数值用于PDA手工更新场景,统一标识便于后续数据追溯与运维排查
|
|
|
|
|
baseDeviceParamVal.setParamCode(PARAM_CODE_PDA_CUSTOM);
|
|
|
|
|
}
|
|
|
|
|
// 采集时间/记录时间均取服务端当前时间,确保同一时区口径一致
|
|
|
|
|
baseDeviceParamVal.setCollectTime(now);
|
|
|
|
|
baseDeviceParamVal.setRecordTime(now);
|
|
|
|
|
|
|
|
|
|
// 直接插入一条新参数记录,保留完整时间序列,避免覆盖历史值
|
|
|
|
|
int rows = baseDeviceParamValService.upsertTodayParamValue(baseDeviceParamVal);
|
|
|
|
|
return rows > 0 ? success(rows) : error("更新" + bizName + "失败");
|
|
|
|
|
} catch (ServiceException e) {
|
|
|
|
|
// 业务异常原样抛出,保留明确可读的提示信息
|
|
|
|
|
throw e;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA更新设备{}失败 | deviceCode={}, deviceId={}, paramName={}, paramValue={}, 异常信息: {}",
|
|
|
|
|
bizName, baseDeviceParamVal.getDeviceCode(), baseDeviceParamVal.getDeviceId(),
|
|
|
|
|
paramName, baseDeviceParamVal.getParamValue(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("更新" + bizName + "失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillDeviceIdentity(BaseDeviceParamVal baseDeviceParamVal) {
|
|
|
|
|
String deviceCode = baseDeviceParamVal.getDeviceCode();
|
|
|
|
|
Long deviceId = baseDeviceParamVal.getDeviceId();
|
|
|
|
|
boolean hasCode = deviceCode != null && !deviceCode.trim().isEmpty();
|
|
|
|
|
|
|
|
|
|
// 未传deviceCode时,必须依赖deviceId反查设备编码;否则无法确定落库维度
|
|
|
|
|
if (!hasCode) {
|
|
|
|
|
// 两个标识都没有时无法定位设备,直接拒绝请求
|
|
|
|
|
if (deviceId == null) {
|
|
|
|
|
throw new ServiceException("deviceCode和deviceId不能同时为空");
|
|
|
|
|
}
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setObjId(deviceId);
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
|
|
|
throw new ServiceException("设备不存在或已停用");
|
|
|
|
|
}
|
|
|
|
|
baseDeviceParamVal.setDeviceCode(list.get(0).getDeviceCode());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 已传deviceCode时统一去空白,并在缺少deviceId时补齐主键
|
|
|
|
|
baseDeviceParamVal.setDeviceCode(deviceCode.trim());
|
|
|
|
|
if (deviceId == null) {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setDeviceCode(baseDeviceParamVal.getDeviceCode());
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
|
|
|
throw new ServiceException("设备不存在或已停用");
|
|
|
|
|
}
|
|
|
|
|
baseDeviceParamVal.setDeviceId(list.get(0).getObjId());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateNumericParamValue(String value, boolean integerRequired, String bizName) {
|
|
|
|
|
try {
|
|
|
|
|
BigDecimal decimal = new BigDecimal(value);
|
|
|
|
|
// 业务口径下运行时间/产量都不允许负值
|
|
|
|
|
if (decimal.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
throw new ServiceException(bizName + "不能小于0");
|
|
|
|
|
}
|
|
|
|
|
// 当日产量必须是整数,避免出现1.2这类无意义产量值
|
|
|
|
|
if (integerRequired && decimal.stripTrailingZeros().scale() > 0) {
|
|
|
|
|
throw new ServiceException(bizName + "必须为整数");
|
|
|
|
|
}
|
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
|
throw new ServiceException(bizName + "必须为数字");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-报修
|
|
|
|
|
@ -988,71 +586,513 @@ public class DmsMobileController extends BaseController {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// /**
|
|
|
|
|
// * 获取最新一条待保养或保养中的保养工单
|
|
|
|
|
// *
|
|
|
|
|
// * @return
|
|
|
|
|
// */
|
|
|
|
|
// // //@PreAuthorize("@ss.hasPermi('qms:checkrule:list')" )
|
|
|
|
|
// @GetMapping("/getNewestMaintInstance")
|
|
|
|
|
// public AjaxResult getNewestMaintInstance(DmsBillsMaintInstance dmsBillsMaintInstance) {
|
|
|
|
|
// DmsBillsMaintInstance newestMaintInstance = dmsBillsMaintInstanceService.getNewestBillsMaintInstance(dmsBillsMaintInstance);
|
|
|
|
|
// return success(newestMaintInstance);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 开始保养
|
|
|
|
|
// */
|
|
|
|
|
//// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
// ////@Log(title = "保养工单", businessType = BusinessType.START)
|
|
|
|
|
// @PostMapping("/startMaint")
|
|
|
|
|
// public AjaxResult startMaint(@RequestBody DmsBillsMaintDetail dmsBillsMaintDetail) {
|
|
|
|
|
// return success(dmsBillsMaintInstanceService.startMaint(dmsBillsMaintDetail));
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 完成保养
|
|
|
|
|
// */
|
|
|
|
|
//// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
// ////@Log(title = "保养工单", businessType = BusinessType.COMPLETE)
|
|
|
|
|
// @PostMapping("/completeMaint")
|
|
|
|
|
// public AjaxResult completeMaint(@RequestBody DmsBillsMaintDetail dmsBillsMaintDetail) {
|
|
|
|
|
// return success(dmsBillsMaintInstanceService.completeMaint(dmsBillsMaintDetail));
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 获取最新一条待润滑或润滑中的润滑工单
|
|
|
|
|
// *
|
|
|
|
|
// * @return
|
|
|
|
|
// */
|
|
|
|
|
// // //@PreAuthorize("@ss.hasPermi('qms:checkrule:list')" )
|
|
|
|
|
// @GetMapping("/getNewestLubeInstance")
|
|
|
|
|
// public AjaxResult getNewestLubeInstance(DmsBillsLubeInstance dmsBillsLubeInstance) {
|
|
|
|
|
// DmsBillsLubeInstance newestLubeInstance = dmsBillsLubeInstanceService.getNewestBillsLubeInstance(dmsBillsLubeInstance);
|
|
|
|
|
// return success(newestLubeInstance);
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 开始润滑
|
|
|
|
|
// */
|
|
|
|
|
//// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
// ////@Log(title = "润滑工单", businessType = BusinessType.START)
|
|
|
|
|
// @PostMapping("/startLube")
|
|
|
|
|
// public AjaxResult startLube(@RequestBody DmsBillsLubeDetail dmsBillsLubeDetail) {
|
|
|
|
|
//
|
|
|
|
|
// return success(dmsBillsLubeInstanceService.startLube(dmsBillsLubeDetail));
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// /**
|
|
|
|
|
// * 完成润滑
|
|
|
|
|
// */
|
|
|
|
|
//// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
// ////@Log(title = "润滑工单", businessType = BusinessType.COMPLETE)
|
|
|
|
|
// @PostMapping("/completeLube")
|
|
|
|
|
// public AjaxResult completeLube(@RequestBody DmsBillsLubeDetail dmsBillsLubeDetail) {
|
|
|
|
|
// return success(dmsBillsLubeInstanceService.completeLube(dmsBillsLubeDetail));
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取最新一条待保养或保养中的保养工单
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* 获取OLD开头的设备列表(仅启用)
|
|
|
|
|
*/
|
|
|
|
|
// //@PreAuthorize("@ss.hasPermi('qms:checkrule:list')" )
|
|
|
|
|
@GetMapping("/getNewestMaintInstance")
|
|
|
|
|
public AjaxResult getNewestMaintInstance(DmsBillsMaintInstance dmsBillsMaintInstance) {
|
|
|
|
|
DmsBillsMaintInstance newestMaintInstance = dmsBillsMaintInstanceService.getNewestBillsMaintInstance(dmsBillsMaintInstance);
|
|
|
|
|
return success(newestMaintInstance);
|
|
|
|
|
@GetMapping("/device/listOld")
|
|
|
|
|
public AjaxResult listOldDevices() {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
List<DmsBaseDeviceLedgerDTO> resultList = new ArrayList<>();
|
|
|
|
|
if (!CollectionUtils.isEmpty(list)) {
|
|
|
|
|
for (BaseDeviceLedger base : list) {
|
|
|
|
|
if (base.getDeviceCode() != null && base.getDeviceCode().startsWith("OLD")) {
|
|
|
|
|
resultList.add(convertDeviceLedgerToDto(convertToDeviceLedger(base)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return success(resultList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 开始保养
|
|
|
|
|
* PDA-获取停机原因列表(仅启用 isFlag=1)
|
|
|
|
|
*/
|
|
|
|
|
// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
////@Log(title = "保养工单", businessType = BusinessType.START)
|
|
|
|
|
@PostMapping("/startMaint")
|
|
|
|
|
public AjaxResult startMaint(@RequestBody DmsBillsMaintDetail dmsBillsMaintDetail) {
|
|
|
|
|
return success(dmsBillsMaintInstanceService.startMaint(dmsBillsMaintDetail));
|
|
|
|
|
@GetMapping("/shutReason/list")
|
|
|
|
|
public AjaxResult listShutReasonsForPda(DmsBaseShutReason reason) {
|
|
|
|
|
reason.setIsFlag("1");
|
|
|
|
|
List<DmsBaseShutReason> list = dmsBaseShutReasonService.selectDmsBaseShutReasonList(reason);
|
|
|
|
|
return success(list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 完成保养
|
|
|
|
|
* PDA-新增停机记录:根据停机原因自动匹配停机类型
|
|
|
|
|
*/
|
|
|
|
|
// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
////@Log(title = "保养工单", businessType = BusinessType.COMPLETE)
|
|
|
|
|
@PostMapping("/completeMaint")
|
|
|
|
|
public AjaxResult completeMaint(@RequestBody DmsBillsMaintDetail dmsBillsMaintDetail) {
|
|
|
|
|
return success(dmsBillsMaintInstanceService.completeMaint(dmsBillsMaintDetail));
|
|
|
|
|
@PostMapping("/shutDown/add")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult addShutDownForPda(@RequestBody DmsRecordShutDown shutDown) {
|
|
|
|
|
try {
|
|
|
|
|
// 若传入了停机原因ID,则查询原因并回填类型
|
|
|
|
|
if (shutDown.getShutReason() != null) {
|
|
|
|
|
DmsBaseShutReason query = new DmsBaseShutReason();
|
|
|
|
|
query.setShutReason(shutDown.getShutReason());
|
|
|
|
|
query.setIsFlag("1");
|
|
|
|
|
List<DmsBaseShutReason> reasons = dmsBaseShutReasonService.selectDmsBaseShutReasonList(query);
|
|
|
|
|
if (!reasons.isEmpty()) {
|
|
|
|
|
shutDown.setShutType(reasons.get(0).getShutTypeId());
|
|
|
|
|
shutDown.setShutReasonId(reasons.get(0).getShutReasonId());
|
|
|
|
|
// 若前端未传 deviceId,尝试从原因带出
|
|
|
|
|
if (shutDown.getDeviceId() == null) {
|
|
|
|
|
shutDown.setDeviceId(reasons.get(0).getDeviceId());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 默认启用标识
|
|
|
|
|
if (shutDown.getIsFlag() == null) {
|
|
|
|
|
shutDown.setIsFlag(1L);
|
|
|
|
|
}
|
|
|
|
|
// 新增停机记录默认未结束
|
|
|
|
|
if (shutDown.getDowntimeFlag() == null) {
|
|
|
|
|
shutDown.setDowntimeFlag("0");
|
|
|
|
|
}
|
|
|
|
|
// 若未传入开始时间,则使用当前时间
|
|
|
|
|
if (shutDown.getShutBeginTime() == null) {
|
|
|
|
|
shutDown.setShutBeginTime(new Date());
|
|
|
|
|
}
|
|
|
|
|
int rows = dmsRecordShutDownService.insertDmsRecordShutDown(shutDown);
|
|
|
|
|
|
|
|
|
|
// 对指定设备(OLD-01~OLD-05)同步写入三色灯状态参数,供设备状态统计使用
|
|
|
|
|
String deviceCode = shutDown.getDeviceCode();
|
|
|
|
|
if (deviceCode != null && deviceCode.startsWith("OLD-")) {
|
|
|
|
|
// 新增停机记录代表进入停机,三色灯置为“暂停”
|
|
|
|
|
insertTriColorStatusParams(deviceCode, shutDown.getDeviceId(), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success(rows);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA新增停机记录失败 | deviceCode={}, shutReason={}, deviceId={}, 异常信息: {}",
|
|
|
|
|
shutDown.getDeviceCode(), shutDown.getShutReason(), shutDown.getDeviceId(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("新增停机记录失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-获取待处理停机记录列表
|
|
|
|
|
* 返回条件:停机结束时间为空(老设备未完成)或 停机原因ID=1(新设备默认原因待修改)
|
|
|
|
|
*/
|
|
|
|
|
@GetMapping("/shutDown/get")
|
|
|
|
|
public AjaxResult getShutDownForPda() {
|
|
|
|
|
try {
|
|
|
|
|
List<DmsRecordShutDown> list = dmsRecordShutDownService.selectPdaShutDownList();
|
|
|
|
|
return success(list);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA获取待处理停机记录失败 | 异常信息: {}", e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("获取停机记录失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-更新停机记录
|
|
|
|
|
* 老设备(shutEndTime为空):更新停机结束时间、计算停机时长、更新停机原因ID
|
|
|
|
|
* 新设备(shutEndTime不为空):仅更新停机原因ID
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/shutDown/complete")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult completeShutDownForPda(@RequestBody DmsRecordShutDown shutDown) {
|
|
|
|
|
if (shutDown.getRecordShutDownId() == null) {
|
|
|
|
|
throw new ServiceException("recordShutDownId不能为空");
|
|
|
|
|
}
|
|
|
|
|
if (shutDown.getShutReasonId() == null) {
|
|
|
|
|
throw new ServiceException("shutReasonId不能为空");
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// 查询原记录
|
|
|
|
|
DmsRecordShutDown origin = dmsRecordShutDownService.selectDmsRecordShutDownByRecordShutDownId(shutDown.getRecordShutDownId());
|
|
|
|
|
if (origin == null) {
|
|
|
|
|
throw new ServiceException("停机记录不存在");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建更新对象,仅设置需要更新的字段
|
|
|
|
|
DmsRecordShutDown updateRecord = new DmsRecordShutDown();
|
|
|
|
|
updateRecord.setRecordShutDownId(shutDown.getRecordShutDownId());
|
|
|
|
|
updateRecord.setShutReasonId(shutDown.getShutReasonId());
|
|
|
|
|
|
|
|
|
|
if (origin.getShutEndTime() == null) {
|
|
|
|
|
// 老设备:标记停机已结束
|
|
|
|
|
updateRecord.setDowntimeFlag("1");
|
|
|
|
|
// 老设备:补充结束时间和停机时长
|
|
|
|
|
Date end = new Date();
|
|
|
|
|
Date begin = origin.getShutBeginTime();
|
|
|
|
|
updateRecord.setShutEndTime(end);
|
|
|
|
|
if (begin != null) {
|
|
|
|
|
long minutes = Math.max(0, (end.getTime() - begin.getTime()) / 60000);
|
|
|
|
|
updateRecord.setShutTime(BigDecimal.valueOf(minutes));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 新设备(shutEndTime已有值):仅更新shutReasonId,无需额外处理
|
|
|
|
|
|
|
|
|
|
int rows = dmsRecordShutDownService.updateDmsRecordShutDown(updateRecord);
|
|
|
|
|
|
|
|
|
|
// 对老设备(OLD-01~OLD-05)同步写入三色灯状态参数
|
|
|
|
|
if (origin.getShutEndTime() == null && origin.getDeviceId() != null) {
|
|
|
|
|
// 原记录不含deviceCode,需通过deviceId反查设备编号
|
|
|
|
|
BaseDeviceLedger deviceQuery = new BaseDeviceLedger();
|
|
|
|
|
deviceQuery.setObjId(origin.getDeviceId());
|
|
|
|
|
List<BaseDeviceLedger> devices = baseDeviceLedgerService.selectBaseDeviceLedgerList(deviceQuery);
|
|
|
|
|
if (!devices.isEmpty()) {
|
|
|
|
|
String deviceCode = devices.get(0).getDeviceCode();
|
|
|
|
|
if (deviceCode != null && deviceCode.startsWith("OLD-")) {
|
|
|
|
|
// 完成停机代表重新运行,三色灯置为"运行"
|
|
|
|
|
insertTriColorStatusParams(deviceCode, origin.getDeviceId(), true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rows > 0 ? success(origin.getRecordShutDownId()) : error("更新停机记录失败");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA完成停机记录失败 | recordShutDownId={}, shutReasonId={}, 异常信息: {}",
|
|
|
|
|
shutDown.getRecordShutDownId(), shutDown.getShutReasonId(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("完成停机失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 插入三色灯状态参数(运行/暂停/报警),以“暂停”为当前状态
|
|
|
|
|
*/
|
|
|
|
|
private void insertTriColorStatusParams(String deviceCode, Long deviceId, boolean running) {
|
|
|
|
|
// 仅处理 OLD-01~OLD-05
|
|
|
|
|
if (!"OLD-01".equals(deviceCode) && !"OLD-02".equals(deviceCode)
|
|
|
|
|
&& !"OLD-03".equals(deviceCode) && !"OLD-04".equals(deviceCode)
|
|
|
|
|
&& !"OLD-05".equals(deviceCode)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 补齐 deviceId(如果未传)
|
|
|
|
|
Long resolvedDeviceId = deviceId;
|
|
|
|
|
if (resolvedDeviceId == null) {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setDeviceCode(deviceCode);
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
if (!list.isEmpty()) {
|
|
|
|
|
resolvedDeviceId = list.get(0).getObjId();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Date now = new Date();
|
|
|
|
|
// 运行、暂停、报警 三个参数,运行/暂停取决于状态
|
|
|
|
|
List<BaseDeviceParamVal> records = new ArrayList<>();
|
|
|
|
|
String runVal = running ? "True" : "False";
|
|
|
|
|
String pauseVal = running ? "False" : "True";
|
|
|
|
|
records.add(buildParamVal(PARAM_CODE_PDA_CUSTOM, deviceCode, resolvedDeviceId, "机台状态-三色灯机器运行", runVal, now));
|
|
|
|
|
records.add(buildParamVal(PARAM_CODE_PDA_CUSTOM, deviceCode, resolvedDeviceId, "机台状态-三色灯机器暂停", pauseVal, now));
|
|
|
|
|
records.add(buildParamVal(PARAM_CODE_PDA_CUSTOM, deviceCode, resolvedDeviceId, "机台状态-三色灯机器报警", "False", now));
|
|
|
|
|
|
|
|
|
|
for (BaseDeviceParamVal rec : records) {
|
|
|
|
|
baseDeviceParamValService.insertBaseDeviceParamVal(rec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BaseDeviceParamVal buildParamVal(String paramCode, String deviceCode, Long deviceId,
|
|
|
|
|
String paramName, String paramValue, Date time) {
|
|
|
|
|
BaseDeviceParamVal v = new BaseDeviceParamVal();
|
|
|
|
|
v.setParamCode(paramCode);
|
|
|
|
|
v.setDeviceCode(deviceCode);
|
|
|
|
|
v.setDeviceId(deviceId);
|
|
|
|
|
v.setParamName(paramName);
|
|
|
|
|
v.setParamValue(paramValue);
|
|
|
|
|
v.setCollectTime(time);
|
|
|
|
|
v.setRecordTime(time);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ========== PDA 参数相关 ==========
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取所有的设备列表(仅启用)
|
|
|
|
|
*/
|
|
|
|
|
@GetMapping("/device/getDevices")
|
|
|
|
|
public AjaxResult getDevices() {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
List<DmsBaseDeviceLedgerDTO> resultList = new ArrayList<>();
|
|
|
|
|
if (!CollectionUtils.isEmpty(list)) {
|
|
|
|
|
for (BaseDeviceLedger base : list) {
|
|
|
|
|
resultList.add(convertDeviceLedgerToDto(convertToDeviceLedger(base)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return success(resultList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-选择设备后更新运行时间(写入参数:机台状态-实际生产时间)
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/device/updateRunTime")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult updateDeviceRunTime(@RequestBody DmsPdaDeviceParamUpdateVo request) {
|
|
|
|
|
if (request == null) {
|
|
|
|
|
throw new ServiceException("请求体不能为空");
|
|
|
|
|
}
|
|
|
|
|
return updatePdaDeviceParamValue(request.getDeviceCode(), request.getDeviceId(), request.getParamValue(),
|
|
|
|
|
PARAM_NAME_ACTUAL_RUNTIME, false, "运行时间");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PDA-选择设备后更新当日产量(写入参数:机台状态-实际产出数量)
|
|
|
|
|
*/
|
|
|
|
|
@PostMapping("/device/updateDailyOutput")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult updateDeviceDailyOutput(@RequestBody DmsPdaDeviceParamUpdateVo request) {
|
|
|
|
|
if (request == null) {
|
|
|
|
|
throw new ServiceException("请求体不能为空");
|
|
|
|
|
}
|
|
|
|
|
return updatePdaDeviceParamValue(request.getDeviceCode(), request.getDeviceId(), request.getParamValue(),
|
|
|
|
|
PARAM_NAME_DAILY_OUTPUT, true, "当日产量");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private AjaxResult updatePdaDeviceParamValue(String deviceCode, Long deviceId, BigDecimal paramValue, String paramName,
|
|
|
|
|
boolean integerRequired, String bizName) {
|
|
|
|
|
// 业务参数值为空时直接拒绝,避免后续数值转换出现非预期错误
|
|
|
|
|
if (paramValue == null) {
|
|
|
|
|
throw new ServiceException(bizName + "不能为空");
|
|
|
|
|
}
|
|
|
|
|
// PDA上报的业务值统一从paramValue读取,后续会按业务类型做数值校验
|
|
|
|
|
BigDecimal rawValue = paramValue;
|
|
|
|
|
if (rawValue == null || rawValue.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
throw new ServiceException(bizName + "不能为空");
|
|
|
|
|
}
|
|
|
|
|
// 运行时间允许小数;当日产量要求整数,规则由integerRequired控制
|
|
|
|
|
validateNumericParamValue(rawValue, integerRequired, bizName);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 兼容PDA只传deviceId或只传deviceCode的场景,统一补齐设备主数据标识
|
|
|
|
|
BaseDeviceParamVal baseDeviceParamVal = fillDeviceIdentity(deviceCode, deviceId);
|
|
|
|
|
Date now = new Date();
|
|
|
|
|
// 参数名由后端强制指定,避免前端透传导致写错业务口径
|
|
|
|
|
baseDeviceParamVal.setParamName(paramName);
|
|
|
|
|
baseDeviceParamVal.setParamValue(rawValue.toString());
|
|
|
|
|
if (baseDeviceParamVal.getParamCode() == null || baseDeviceParamVal.getParamCode().trim().isEmpty()) {
|
|
|
|
|
// Why:该参数值用于PDA手工更新场景,统一标识便于后续数据追溯与运维排查
|
|
|
|
|
baseDeviceParamVal.setParamCode(PARAM_CODE_PDA_CUSTOM);
|
|
|
|
|
}
|
|
|
|
|
// 采集时间/记录时间均取服务端当前时间,确保同一时区口径一致
|
|
|
|
|
baseDeviceParamVal.setCollectTime(now);
|
|
|
|
|
baseDeviceParamVal.setRecordTime(now);
|
|
|
|
|
|
|
|
|
|
// 直接插入一条新参数记录,保留完整时间序列,避免覆盖历史值
|
|
|
|
|
int rows = baseDeviceParamValService.upsertTodayParamValue(baseDeviceParamVal);
|
|
|
|
|
return rows > 0 ? success(rows) : error("更新" + bizName + "失败");
|
|
|
|
|
} catch (ServiceException e) {
|
|
|
|
|
// 业务异常原样抛出,保留明确可读的提示信息
|
|
|
|
|
throw e;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 系统异常统一落日志并转业务异常,避免将内部堆栈直接暴露给调用方
|
|
|
|
|
log.error("PDA更新设备{}失败 | deviceCode={}, deviceId={}, paramName={}, paramValue={}, 异常信息: {}",
|
|
|
|
|
bizName, deviceCode, deviceId, paramName, rawValue, e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("更新" + bizName + "失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BaseDeviceParamVal fillDeviceIdentity(String deviceCode, Long deviceId) {
|
|
|
|
|
BaseDeviceParamVal baseDeviceParamVal = new BaseDeviceParamVal();
|
|
|
|
|
boolean hasCode = deviceCode != null && !deviceCode.trim().isEmpty();
|
|
|
|
|
|
|
|
|
|
// 未传deviceCode时,必须依赖deviceId反查设备编码;否则无法确定落库维度
|
|
|
|
|
if (!hasCode) {
|
|
|
|
|
// 两个标识都没有时无法定位设备,直接拒绝请求
|
|
|
|
|
if (deviceId == null) {
|
|
|
|
|
throw new ServiceException("deviceCode和deviceId不能同时为空");
|
|
|
|
|
}
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setObjId(deviceId);
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
|
|
|
throw new ServiceException("设备不存在或已停用");
|
|
|
|
|
}
|
|
|
|
|
baseDeviceParamVal.setDeviceId(deviceId);
|
|
|
|
|
baseDeviceParamVal.setDeviceCode(list.get(0).getDeviceCode());
|
|
|
|
|
return baseDeviceParamVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 已传deviceCode时统一去空白,并在缺少deviceId时补齐主键
|
|
|
|
|
baseDeviceParamVal.setDeviceCode(deviceCode.trim());
|
|
|
|
|
if (deviceId == null) {
|
|
|
|
|
BaseDeviceLedger query = new BaseDeviceLedger();
|
|
|
|
|
query.setDeviceCode(baseDeviceParamVal.getDeviceCode());
|
|
|
|
|
query.setIsFlag(1L);
|
|
|
|
|
List<BaseDeviceLedger> list = baseDeviceLedgerService.selectBaseDeviceLedgerList(query);
|
|
|
|
|
if (CollectionUtils.isEmpty(list)) {
|
|
|
|
|
throw new ServiceException("设备不存在或已停用");
|
|
|
|
|
}
|
|
|
|
|
baseDeviceParamVal.setDeviceId(list.get(0).getObjId());
|
|
|
|
|
return baseDeviceParamVal;
|
|
|
|
|
}
|
|
|
|
|
baseDeviceParamVal.setDeviceId(deviceId);
|
|
|
|
|
return baseDeviceParamVal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateNumericParamValue(BigDecimal value, boolean integerRequired, String bizName) {
|
|
|
|
|
try {
|
|
|
|
|
BigDecimal decimal = value;
|
|
|
|
|
// 业务口径下运行时间/产量都不允许负值
|
|
|
|
|
if (decimal.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
throw new ServiceException(bizName + "不能小于0");
|
|
|
|
|
}
|
|
|
|
|
// 当日产量必须是整数,避免出现1.2这类无意义产量值
|
|
|
|
|
if (integerRequired && decimal.stripTrailingZeros().scale() > 0) {
|
|
|
|
|
throw new ServiceException(bizName + "必须为整数");
|
|
|
|
|
}
|
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
|
throw new ServiceException(bizName + "必须为数字");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取最新一条待润滑或润滑中的润滑工单
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
* PDA-按物料关键字查询关联工单
|
|
|
|
|
*/
|
|
|
|
|
// //@PreAuthorize("@ss.hasPermi('qms:checkrule:list')" )
|
|
|
|
|
@GetMapping("/getNewestLubeInstance")
|
|
|
|
|
public AjaxResult getNewestLubeInstance(DmsBillsLubeInstance dmsBillsLubeInstance) {
|
|
|
|
|
DmsBillsLubeInstance newestLubeInstance = dmsBillsLubeInstanceService.getNewestBillsLubeInstance(dmsBillsLubeInstance);
|
|
|
|
|
return success(newestLubeInstance);
|
|
|
|
|
@GetMapping("/order/listByMaterial")
|
|
|
|
|
public AjaxResult listOrdersByMaterial(String keyword) {
|
|
|
|
|
// 物料关键字是PDA唯一输入入口,空值时直接拒绝,避免放大后端模糊查询范围
|
|
|
|
|
if (keyword == null || keyword.trim().isEmpty()) {
|
|
|
|
|
throw new ServiceException("物料关键字不能为空");
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// Why:先按物料主数据检索,再按物料编码反查订单,能保证PDA搜索口径与主数据一致
|
|
|
|
|
List<BaseOrderInfo> orders = baseOrderInfoService.selectPdaOrderListByMaterialKeyword(keyword.trim());
|
|
|
|
|
return success(orders);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("PDA按物料查询工单失败 | keyword={}, 异常信息: {}", keyword, e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("查询工单失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 开始润滑
|
|
|
|
|
* PDA-维护订单状态与数量
|
|
|
|
|
*/
|
|
|
|
|
// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
////@Log(title = "润滑工单", businessType = BusinessType.START)
|
|
|
|
|
@PostMapping("/startLube")
|
|
|
|
|
public AjaxResult startLube(@RequestBody DmsBillsLubeDetail dmsBillsLubeDetail) {
|
|
|
|
|
@PostMapping("/order/updateStatusAndQty")
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public AjaxResult updateOrderStatusAndQty(@RequestBody BaseOrderInfo baseOrderInfo) {
|
|
|
|
|
// 请求体为空时没有任何维护目标,直接拦截比进入service后再判空更清晰
|
|
|
|
|
if (baseOrderInfo == null) {
|
|
|
|
|
throw new ServiceException("请求体不能为空");
|
|
|
|
|
}
|
|
|
|
|
// PDA下拉选中订单后至少应能定位到一条工单,兼容前端传objId或orderCode两种方式
|
|
|
|
|
if (baseOrderInfo.getObjId() == null
|
|
|
|
|
&& (baseOrderInfo.getOrderCode() == null || baseOrderInfo.getOrderCode().trim().isEmpty())) {
|
|
|
|
|
throw new ServiceException("objId和orderCode不能同时为空");
|
|
|
|
|
}
|
|
|
|
|
// 状态和数量都在控制器前置校验,避免脏数据落到service或数据库层
|
|
|
|
|
validateOrderExecutionStatus(baseOrderInfo.getExecutionStatus());
|
|
|
|
|
validateOrderQty(baseOrderInfo.getActualCompleteQty(), "完工数量");
|
|
|
|
|
validateOrderQty(baseOrderInfo.getActualDefectQty(), "不良数量");
|
|
|
|
|
|
|
|
|
|
return success(dmsBillsLubeInstanceService.startLube(dmsBillsLubeDetail));
|
|
|
|
|
try {
|
|
|
|
|
// Why:PDA订单维护属于人工修正场景,统一走service封装,避免控制器直接拼装状态流转细节
|
|
|
|
|
int rows = baseOrderInfoService.updatePdaOrderExecution(baseOrderInfo);
|
|
|
|
|
return rows > 0 ? success(rows) : error("工单不存在或更新失败");
|
|
|
|
|
} catch (ServiceException e) {
|
|
|
|
|
throw e;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("PDA维护订单失败 | objId={}, orderCode={}, executionStatus={}, actualCompleteQty={}, 异常信息: {}",
|
|
|
|
|
baseOrderInfo.getObjId(), baseOrderInfo.getOrderCode(), baseOrderInfo.getExecutionStatus(),
|
|
|
|
|
baseOrderInfo.getActualCompleteQty(), e.getMessage(), e);
|
|
|
|
|
throw new ServiceException("维护订单失败: " + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 完成润滑
|
|
|
|
|
*/
|
|
|
|
|
// //@PreAuthorize("@ss.hasPermi('qms:checkresultdetail:add')" )
|
|
|
|
|
////@Log(title = "润滑工单", businessType = BusinessType.COMPLETE)
|
|
|
|
|
@PostMapping("/completeLube")
|
|
|
|
|
public AjaxResult completeLube(@RequestBody DmsBillsLubeDetail dmsBillsLubeDetail) {
|
|
|
|
|
return success(dmsBillsLubeInstanceService.completeLube(dmsBillsLubeDetail));
|
|
|
|
|
private void validateOrderExecutionStatus(String executionStatus) {
|
|
|
|
|
// PDA当前仅允许维护执行态,保持与execution.vue和现有执行页状态枚举一致
|
|
|
|
|
if (executionStatus == null || executionStatus.trim().isEmpty()) {
|
|
|
|
|
throw new ServiceException("执行状态不能为空");
|
|
|
|
|
}
|
|
|
|
|
String normalized = executionStatus.trim();
|
|
|
|
|
if (!ORDER_EXECUTION_PENDING.equals(normalized)
|
|
|
|
|
&& !ORDER_EXECUTION_RUNNING.equals(normalized)
|
|
|
|
|
&& !ORDER_EXECUTION_PAUSED.equals(normalized)
|
|
|
|
|
&& !ORDER_EXECUTION_COMPLETED.equals(normalized)) {
|
|
|
|
|
throw new ServiceException("执行状态不合法");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateOrderQty(Long qty, String fieldName) {
|
|
|
|
|
// 数量允许为空,表示本次只改状态;但一旦传值就必须满足非负约束
|
|
|
|
|
if (qty != null && qty < 0) {
|
|
|
|
|
throw new ServiceException(fieldName + "不能小于0");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|