SCTMES_V5/mes_in_sct/app/functions.php

344 lines
13 KiB
PHP
Raw Permalink Normal View History

2025-06-14 18:55:09 +08:00
<?php
use Ramsey\Uuid\Uuid;
use libs\db\Db;
/**
* 判断二维数组某个元素是否存在重复值
* @param $array
* @param $elementKey
* @return bool
*/
function hasDuplicates($array, $elementKey)
{
$values = [];
foreach ($array as $item) {
if (array_key_exists($elementKey, $item)) {
if (in_array($item[$elementKey], $values)) {
return true; // 找到了重复值
}
$values[] = $item[$elementKey];
}
}
return false; // 没有找到重复值
}
/**
* 二维关联数组重复键值判定,指定需要校验的键名,同时可设置忽略键值对,不设置键值对忽略,就进行键值重复判定
* @param $array 二维关联数组
* @param $checkKeys 需要校验键名['id','name', 'age'];
* @param $$ignoreKeyValuePairs 忽略键值对[['key' => 'id', 'value' => 1], ['key' => 'id', 'value' => -1], ['key' => 'age', 'value' => 25]]
* @return array
*/
function findDuplicates($array, $checkKeys = [], $ignoreKeyValuePairs = []) {
$values = [];
$duplicates = [];
foreach ($array as $subArray) {
foreach ($subArray as $key => $value) {
// 检查是否在指定的键名中
if (!in_array($key, $checkKeys)) {
continue;
}
// 检查是否需要忽略当前键值对
$shouldIgnore = false;
foreach ($ignoreKeyValuePairs as $pair) {
if ($key === $pair['key'] && $value === $pair['value']) {
$shouldIgnore = true;
break;
}
}
if ($shouldIgnore) {
continue;
}
// 进行键值重复判断
if (isset($values[$key]) && in_array($value, $values[$key])) {
if (!isset($duplicates[$key])) {
$duplicates[$key] = [];
}
$duplicates[$key][] = $value;
} else {
$values[$key][] = $value;
}
}
}
// 清理重复的值,只保留唯一的重复值
foreach ($duplicates as &$duplicateValues) {
$duplicateValues = array_unique($duplicateValues);
}
return $duplicates;
}
/**
* 生成唯一uuid
* @return string
*/
function generateUniqueId() {
return Uuid::uuid4()->toString();
}
/**
* 生成MES内部物料item_id虚拟码,编码规则为工序单元-物料类别编码-物料编码-年月日时分秒
* @param $workingsubclass 工序单元
* @param $bom_source_category_code 物料类别编码
* @param $bom_source_code 物料编码
* @return string
*/
function generate_material_item_id($workingsubclass, $bom_source_category_code, $bom_source_code){
return $workingsubclass.'-'.$bom_source_category_code.'-'.$bom_source_code.'-'.date('YmdHis');
}
/**
* 生成MES内部物料item_id虚拟码,编码规则为工序单元-物料类别编码-物料编码-年月日时分秒
* @param $workingsubclass 工序单元
* @param $bom_source_category_code 物料类别编码
* @param $bom_source_code 物料编码
* @return string
*/
function generate_material_item_id_wip($workingsubclass, $device_code, $batch, $cut_list)
{
// 产地(固定 深圳 S
$origin = 'S';
// 线体(固定 C线 02
$Line = '02';
//分切卷号默认就是传入的$cut_list 但是分切后的开槽设备(或者后续其他设备)例外,需要从上料的半成品编码中获取
// 查询 hf_mes_bkv_batch_process_log 表获取 item_id
$sql = sprintf(
"SELECT item_id FROM hf_mes_bkv_batch_process_log
WHERE batch='%s'
AND item_device_code='%s'
AND workingsubclass='%s'
AND status=0
AND jsonb_typeof(pid) = 'array'
LIMIT 1;",
$batch,
$device_code,
$workingsubclass
);
$itemData = Db::fetch($sql);
if ($workingsubclass == 'FJKC') {
// 检查是否返回了有效的开槽设备结果
if ($itemData === false || !isset($itemData['item_id'])) {
return [false, 'Item ID not found for FJKC subclass'];
}
// 获取到的 item_idcut_list就是item_id最后一个元素
$cut_list = substr($itemData['item_id'], -1);
}
// 配置信息
$processUnits = [
'ZJJB' => ['code' => 'C', 'category' => 'S00'], // 正极、工序类别为 S
'ZJTB' => ['code' => 'C', 'category' => 'TD0'], // 正极、工序类别为 T
'ZJTB_S' => ['code' => 'C', 'category' => 'TS0'], // 正极、工序类别为 T
'ZJGY' => ['code' => 'C', 'category' => 'GD1'], // 正极、工序类别为 G
'ZJGY_S' => ['code' => 'C', 'category' => 'GS1'], // 正极、工序类别为 G
'ZJFQ' => ['code' => 'C', 'category' => 'FD0'], // 正极、工序类别为 F
'ZJFQ_S' => ['code' => 'C', 'category' => 'FS0'], // 正极、工序类别为 F
'FJJB' => ['code' => 'A', 'category' => 'S00'], // 负极、工序类别为 S
'FJTB' => ['code' => 'A', 'category' => 'TS0'], // 负极、工序类别为 T
'FJGY' => ['code' => 'A', 'category' => 'GS1'], // 负极、工序类别为 G
'FJECGY' => ['code' => 'A', 'category' => 'GS2'], // 负极、工序类别为 G
'FJFQ' => ['code' => 'A', 'category' => 'FS0'], // 负极、工序类别为 F
'FJKC' => ['code' => 'A', 'category' => 'KS0'], // 负极、工序类别为 K
];
if (!isset($processUnits[$workingsubclass])) {
return [false, 'Invalid workingsubclass'];
}
// 正负极
$type = $processUnits[$workingsubclass]['code'];
// 工序代号
$process_short_code = $processUnits[$workingsubclass]['category'];
// 获取机台号
$sql = sprintf("SELECT device_number FROM hf_mes_device WHERE code='%s' LIMIT 1;", $device_code);
$device_number = Db::fetch($sql);
if ($device_number === false) {
return [false, 'Device number not found'];
}
// 补0
$device_number = str_pad($device_number['device_number'], 2, '0', STR_PAD_LEFT);
// 查询 hf_mes_production_planning_management_batch 表获取 flow_id
$sql = sprintf("SELECT flow_id FROM hf_mes_production_planning_management_batch WHERE batch='%s' LIMIT 1;", $batch);
$flowId = Db::fetch($sql);
if ($flowId === false) {
return [false, 'Flow ID not found for batch'];
}
// 查询 hf_mes_technology_flow 表获取 product_model_id
$sql = sprintf("SELECT product_model_id FROM hf_mes_technology_flow WHERE id='%s' LIMIT 1;", $flowId['flow_id']);
$productModelId = Db::fetch($sql);
if ($productModelId === false) {
return [false, 'Product model ID not found'];
}
// 查询 hf_mes_product_model 表获取电池型号的 code
$sql = sprintf("SELECT code FROM hf_mes_product_model WHERE id='%s' LIMIT 1;", $productModelId['product_model_id']);
$batteryModelCode = Db::fetch($sql);
if ($batteryModelCode === false) {
return [false, 'Battery model code not found'];
}
// 获取当前年代码例如2024 -> 24
$yearCode = date('y'); // 取年份的最后两位
// 获取当前是今年的第几周
$weekCode = date('W'); // 取当前日期在今年的周数
// 获取当前是星期几1 = Monday, 7 = Sunday并映射到 A-G
$dayOfWeek = date('N'); // 'N' 返回数字 1周一到 7周日
$dayCode = chr(64 + $dayOfWeek); // 'A' 对应 1'B' 对应 2依此类推到 'G'
// 获取当前日期
$currentDate = date('Y-m-d');
// 查询 hf_mes_wip_workingsubclass_lot 表,获取 count 和 last_reset_date
$sql = sprintf("SELECT count, last_reset_date FROM hf_mes_wip_workingsubclass_lot WHERE workingsubclass='%s' LIMIT 1;", $workingsubclass);
$workingsubclassData = Db::fetch($sql);
if ($workingsubclassData === false) {
return [false, 'Workingsubclass data not found'];
}
// 如果当前日期与 last_reset_date 不同,则重置 count 为 1
if ($workingsubclassData['last_reset_date'] !== $currentDate) {
$sql = sprintf(
"UPDATE hf_mes_wip_workingsubclass_lot SET count = 1, last_reset_date = '%s' WHERE workingsubclass='%s';",
$currentDate,
$workingsubclass
);
$result = Db::query($sql);
if ($result === false) {
return [false, 'Failed to reset count'];
}
$count = 1;
} else {
$count = $workingsubclassData['count'];
}
// 生成流水号,补零
$serialNumber = str_pad($count, 2, '0', STR_PAD_LEFT);
//流水号如果不是搅拌或者涂布设备流水号需要通过通过上料的原材料获取
if ($workingsubclass != 'ZJJB' && $workingsubclass != 'ZJTB' && $workingsubclass != 'ZJTB_S' && $workingsubclass != 'FJJB' && $workingsubclass != 'FJTB') {
// 获取到倒数两位的流水号
$get_count = substr($itemData['item_id'], -3, 2);
$serialNumber = str_pad($get_count, 2, '0', STR_PAD_LEFT);
}
// 更新计数值 +1 到数据库
$sql = sprintf("UPDATE hf_mes_wip_workingsubclass_lot SET count = %d WHERE workingsubclass='%s';", $count + 1, $workingsubclass);
$result = Db::query($sql);
if ($result === false) {
return [false, 'Failed to update count'];
}
// 生成物料项目ID
$material_item_id = $batteryModelCode['code'] . $yearCode . $weekCode . $dayCode . $origin . $Line . $type . '-' . $process_short_code . $device_number . '-' . $serialNumber . $cut_list;
return [true, $material_item_id];
}
/**
* 校验变量值与要求数据类型是否一致
* @param $variable_name 变量名
* @param $variable_val 变量值
* @param $required_data_type 要求数据类型
* @return string
*/
function verify_data_type($variable_name, $variable_val, $required_data_type){
$ret = '';
if($variable_val != ""){
if($required_data_type == 'TIMESTAMP' && date('Y-m-d H:i:s', strtotime($variable_val)) != $variable_val){
$ret = "变量名[".$variable_name."]的数据为[".$variable_val."]与要求数据类型[".$required_data_type."]类型要求不相符,请检查!【要求数据类型格式比如为:'2022-11-11 09:00:00'】";
}elseif($required_data_type == 'FLOAT' && !is_numeric($variable_val)){
$ret = "变量名[".$variable_name."]的数据为[".$variable_val."]与要求数据类型[".$required_data_type."]类型要求不相符,请检查!【要求数据类型格式比如为: 12.8】";
}elseif($required_data_type == 'INT' && !is_int($variable_val)){
$ret = "变量名[".$variable_name."]的数据为[".$variable_val."]与要求数据类型[".$required_data_type."]类型要求不相符,请检查!【要求数据类型格式比如为: 12】";
}
}else{
$ret = '数据为空,校验数据类型失败';
}
return $ret;
}
/**
* curl
* @param $url
* @param $type
* @param string $data
* @return array|mixed
*/
function curl_open($url, $type, $data = "", $timeout = 20)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
if ($type == "POST") {
curl_setopt($ch, CURLOPT_POST, 1);
// curl_setopt($ch,CURLOPT_HTTPHEADER,array ( "Accept: application/json" ));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
} else {
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
// curl_setopt($ch, CURLOPT_SSLVERSION, 3);
}
$output = curl_exec($ch);
curl_close($ch);
if ($output != "") {
$val = json_decode($output, true);
return array("errcode" => 0, "msg" => "", "rtval" => $val);
} else {
return array("errcode" => 4002, "msg" => "Timeout", "rtval" => null);
}
}
/**
* 数组按照某个元素分组
* @param $arr
*/
function array_group($arr, $field)
{
$newArr = [];
foreach ($arr as $key => $value) {
$newArr[$value[$field]][] = $value;
}
return $newArr;
}
/**
* 判断是否是json
* @param $string
* @return bool
*/
function isJson($string)
{
json_decode($string);
return (json_last_error() == JSON_ERROR_NONE);
}
/**
* 获取时间毫秒数
*
*/
function get_subtraction(){
list($msec, $sec) = explode(' ',microtime());
$msectime = (float)sprintf('%.0f',(floatval($msec)+floatval($sec)) * 1000);
return $msectime;
}