$battery_id) { // 判断电池是否为空 if (empty($battery_id)) { throw new Exception("电池条码数组第[{$key}]位置的电池条码不能是:[0, '0', '', null, NAN]等,请上传电池条码", 4006); } // 判断如果查询不到battery_map的数据,pid赋予-2,uuid赋予空数组 $pid = '-2'; $uuid = json_encode([]); // 判断是否存在battery_map中 $sql = sprintf( "SELECT batch,tray,lot,subbatch,pid,uuid FROM hf_mes_production_battery_map WHERE battery_id='%s' ORDER BY id DESC LIMIT 1;", $battery_id ); $ret = Db::fetch($sql); if (empty($ret)) { $key += 1; throw new Exception("电池数组[battery_ids]第[{$key}]位置的电池[{$battery_id}]数据不存在系统中,请检查"); } $pid = !empty($ret['pid']) ? $ret['pid'] : $pid; $uuid = !empty($ret['uuid']) ? $ret['uuid'] : $uuid; list($old_batch, $old_tray, $old_lot, $old_subbatch) = [ $ret['batch'], $ret['tray'], $ret['lot'], $ret['subbatch'] ]; if ($key == 0) { $first_batch = $old_subbatch; } // 确认电池在之前托盘是激活状态 $sql = sprintf( "SELECT next_process_code FROM \"%s\" WHERE battery_id='%s' AND tray='%s' AND lot='%s' AND active=1 LIMIT 1;", 'hf_mes_tmp_bkv_' . $old_subbatch, $battery_id, $old_tray, $old_lot ); $ret = Db::fetch($sql); if (empty($ret)) { $key += 1; throw new Exception("电池数组[battery_ids]第[{$key}]位置的电池[{$battery_id}]在原托盘[{$old_tray}]中不是激活状态,请检查"); } $next_process_code = $ret['next_process_code']; // 所有录入的电池的批次必须是一样的 if ($first_batch != $old_subbatch) { $key += 1; throw new Exception("电池数组[battery_ids]第[{$key}]位置的电池[{$battery_id}]与第一个电池的批次不一致,请检查"); } array_push($check_battery_ids, [ 'battery_id' => $battery_id, 'tray' => $old_tray, 'lot' => $old_lot, 'next_process_code' => $next_process_code, 'pid' => $pid, 'uuid' => $uuid, ]); } // 判断所有电池的工序是否一致 $sql = sprintf( "SELECT flow_id FROM hf_mes_production_planning_management_subbatch WHERE subbatch='%s' LIMIT 1;", $first_batch ); $ret = Db::fetch($sql); $flow_id = $ret['flow_id']; $current_process_code = "{$flow_id}_{$workingsubclass}"; // 验证所有电池的当前工序编码是否与当前的工序一致 foreach ($check_battery_ids as $item) { if ($item['next_process_code'] != $current_process_code) { throw new Exception("电池[{$item['battery_id']}]当前工序编码[{$item['next_process_code']}]与当前上传数据要求的设备工序编码[{$current_process_code}]不一致,请检查!"); } } // 判断结果参数是否都上传了 $sql = sprintf( "SELECT a.id,b.process FROM hf_mes_technology_process AS a INNER JOIN hf_mes_technology_flow b ON b.id = a.flow_id WHERE a.code='%s' LIMIT 1;", $current_process_code ); $ret = Db::fetch($sql); list($flow_process, $process_id) = [ json_decode($ret['process'], true), $ret['id'] ]; // 根据电池数组赋予通道数据 $param['CHANNEL'] = array_map(function ($value) { return $value + 1; }, array_keys($battery_ids)); // 赋予设备结果参数数组 $param['DEVICE_CODE'] = array_pad($param['DEVICE_CODE'], count($battery_ids), $device_code); // 赋予完成时间结果参数数组 $param['FINISH_TIME'] = array_pad($param['FINISH_TIME'], count($battery_ids), $date); // 刷选出需要设备上传的结果参数 $sql = sprintf( "SELECT code,field_type,is_upload FROM hf_mes_technology_process_result_param WHERE process_id=%s AND is_upload=1;", $process_id ); $result_param_need = Db::fetchAll($sql); if (!empty($result_param_need)) { $result_param_need_params = array_column($result_param_need, 'code'); // 验证提交的结果数据 // 1、验证是否上传了结果参数 $diff = array_diff($result_param_need_params, array_keys($param)); if (!empty($diff)) { throw new Exception("结果参数:[{" . implode(',', $diff) . "}]没有上传"); } // 1、验证结果参数是否是数组格式 // 2、验证结果参数的数组长度是否与电池数量一致 // 3、验证具体的结果数据有没有上传与数据的类型 foreach ($result_param_need as $item) { // 1、验证结果参数是否是数组格式 if (!is_array($param[$item['code']])) { throw new Exception("上传的结果参数[{$item['code']}] 需要是数组!结果数据均为数组格式,请检查!"); } // 1、验证结果参数的数组长度是否与电池数量一致 if (count($param[$item['code']]) != count($battery_ids)) { $count = count($battery_ids); throw new Exception("结果参数[{$item['code']}]的数组长度与电池数量不相等,电池数量为:[{$count}],请检查"); } // 结果参数数组 $p_vals = $param[$item['code']]; // 结果参数类型 $p_class = $item['field_type']; // 2、验证具体的结果数据有没有上传与数据的类型 foreach ($p_vals as $p_key => $p_val) { if ($p_class == 'TIMESTAMP') { if ($p_val != "" && date('Y-m-d H:i:s', strtotime($p_val)) != $p_val) { throw new Exception(sprintf( "结果数据[%s]第[%s]位置的数据类型与系统[%s]类型要求不相符,请检查!【要求数据类型格式比如为:'2022-11-11 09:00:00'】", $item['code'], $p_key + 1, $p_class )); } } elseif ($p_class == 'FLOAT') { if ($p_val != "" && !is_numeric($p_val)) { throw new Exception(sprintf( "结果数据[%s]第[%s]位置的数据类型与系统[%s]类型要求不相符,请检查!【要求数据类型格式比如为: 12.8】", $item['code'], $p_key + 1, $p_class )); } } elseif ($p_class == 'INT') { if ($p_val != "" && !is_int($p_val)) { throw new Exception(sprintf( "结果数据[%s]第[%s]位置的数据类型与系统[%s]类型要求不相符,请检查!【要求数据类型格式比如为: 12】", $item['code'], $p_key + 1, $p_class )); } } } } } else { $result_param_need = []; } // 把完成时间加入到结果参数上传之中 array_push( $result_param_need, ['code' => 'FINISH_TIME', 'field_type' => 'TIMESTAMP', 'is_upload' => 0], ['code' => 'DEVICE_CODE', 'field_type' => 'VARCHAR', 'is_upload' => 0] ); // 判断是否有下一工序 $current_process_idx = -1; $next_next_process_code = '-1'; $flow_process_column = array_column($flow_process, null, '2'); if ($flow_process_column[$current_process_code][0] < (count($flow_process) - 1)) { $next_next_process_code = $flow_process[$flow_process_column[$current_process_code][0] + 1][2]; } elseif ($flow_process_column[$current_process_code][0] == (count($flow_process) - 1)) { $next_next_process_code = '-1'; } else { $next_next_process_code = '-1'; } $current_process_idx = $flow_process_column[$current_process_code][0]; } catch (Exception $e) { throw new Exception($e->getMessage()); } // 开启事务 Db::beginTrans(); try { // 标记最后一条数据的状态 Event::emit('SetProcessLogEvent.updateLastStatus', $battery_ids); // 更新BKV数据 $common_update_str = sprintf( "process_code='%s',process_idx=%s,next_process_code='%s'", $current_process_code, $current_process_idx, $next_next_process_code ); // 判断如果是最后一个工序,拼接取消激活的状态修改 if ($next_next_process_code == -1) { $common_update_str = $common_update_str . ',active=0'; } // process_log数据 $insert_process_log_data = []; foreach ($check_battery_ids as $battery_index => $val) { // 过滤0的数据 if ($val['battery_id'] === '0') { continue; } $bkv_update_str = ''; $ng_code = ''; foreach ($result_param_need as $p_val) { // 结果参数 $p_param = $p_val['code']; // 结果参数类型 $p_class = $p_val['field_type']; // 结果参数值 $p_param_val = trim($param[$p_param][$battery_index]); if (in_array($p_class, ['FLOAT', 'INT'])) { $bkv_update_str .= "\"{$current_process_code}.{$p_param}\"={$p_param_val},"; } else { $bkv_update_str .= "\"{$current_process_code}.{$p_param}\"='{$p_param_val}',"; } // 判断NG是否存在 if ($p_param == 'NG') { if ($p_param_val != '') { $ng_code = $p_param_val; } else { $ng_code = 0; } } } if (!empty($bkv_update_str)) { $bkv_update_str = $bkv_update_str . $common_update_str; } else { $bkv_update_str = $common_update_str; } $sql = sprintf( "UPDATE \"%s\" SET %s WHERE battery_id='%s' AND tray='%s' AND lot='%s'", config('app.bkv_prefix') . $first_batch, $bkv_update_str, $val['battery_id'], $val['tray'], $val['lot'] ); $row = Db::query($sql); if ($row === NULL) { throw new Exception("PROCESS update failed:[tmp_bkv]"); } $forward_tracing_uuid = []; //读取这个电池在process_log表中最新一条记录的forward_tracing_uuid,如果有的话没有的话则赋值uuid $sql = "SELECT forward_tracing_uuid FROM hf_mes_bkv_batch_process_log WHERE item_id = '" . $val['battery_id'] . "' ORDER BY id DESC LIMIT 1"; $ret = Db::fetch($sql); if (!empty($ret)) { $forward_tracing_uuid = $ret['forward_tracing_uuid']; } // 组装process_log新增数据 array_push($insert_process_log_data, [ 'item_id' => $val['battery_id'], 'batch' => $old_batch, 'subbatch' => $first_batch, 'tray' => $val['tray'], 'lot' => $val['lot'], 'process_code' => $current_process_code, 'workingsubclass' => $workingsubclass, 'device_code' => $device_code, 'device_category_id' => $device_category_id, 'channel' => $param['CHANNEL'][$battery_index], 'finish_time' => $param['FINISH_TIME'][$battery_index], 'input_finish_time' => $param['FINISH_TIME'][$battery_index], 'status' => -1, 'pid' => $val['pid'], 'uuid' => $val['uuid'], 'last_status' => 1, 'ng_code' => $ng_code ? $ng_code : 0, 'class' => $ng_code ? 'NG' : null, 'forward_tracing_uuid' => $forward_tracing_uuid ?: $val['uuid'] ]); } // 写入process_log的数据(同步) Event::emit('SetProcessLogEvent.handle', $insert_process_log_data); // 写入曲线数据(同步) Event::emit('CurveDataPathEvent.handle', ["end_time" => isset($param["end_time"]) ? $param["end_time"] : "", "workingsubclass" => $workingsubclass, "data" => $insert_process_log_data]); // 结果参数转发到scada(异步) Event::emit('SendProcessResultParamsToScadaEvent.handle', ["workingsubclass" => $workingsubclass, "device_code" => $device_code, "param" => $post['param'], "batch" => $old_batch]); } catch (Exception $e) { Db::rollBackTrans(); throw new Exception($e->getMessage()); } Db::commitTrans(); $data['process_code'] = $current_process_code; $data['class_name'] = get_class($this); $data['log_data'] = $insert_process_log_data; try { // 写入process_log的数据(同步) $response = Event::emit('ExtScriptEvent.extScriptEnd', $data); if ($response['ext_script_code'] != 0) { throw new Exception($response['ext_script_msg']); } } catch (Exception $e) { throw new Exception($e->getMessage()); } return ''; } }