cqp 3 kuukautta sitten
vanhempi
sitoutus
c938c1b402

+ 62 - 0
app/Console/Commands/InsertDeviceData.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Http\Controllers\Api\FeederDataGenerator;
+use App\Model\ForDeviceData;
+use App\Model\SystemL;
+use Illuminate\Console\Command;
+
+class InsertDeviceData extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'command:insert_device_data';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return mixed
+     */
+    public function handle()
+    {
+        echo '生成设备数据--------start---------------';
+
+        $dispatch = ForDeviceData::where("del_time",0)
+            ->select('id','finished_num','start_time as upd_time','device_id')
+            ->get()->toArray();
+        if(! empty($dispatch)){
+            $first_id = SystemL::max('id');
+            list($status, $msg) = (new FeederDataGenerator)->generateData($dispatch);
+            if($status){
+                $end_id = SystemL::max('id');
+                ForDeviceData::whereIn('id',array_column($dispatch,'id'))
+                    ->update(['del_time' => time(), 'systeml_id_str' => $first_id . '|' . $end_id]);
+            }else{
+                echo $msg . "\n";
+            }
+        }
+
+        echo '生成设备数据--------end---------------';
+    }
+}

+ 29 - 0
app/Http/Controllers/Api/ScreenController.php

@@ -10,6 +10,7 @@ use App\Model\DispatchEmpSub;
 use App\Model\DispatchSub;
 use App\Model\EmployeeTeamPermission;
 use App\Model\Equipment;
+use App\Model\ForDeviceData;
 use App\Model\OrdersProduct;
 use App\Model\OrdersProductProcess;
 use App\Model\Process;
@@ -25,6 +26,7 @@ use Carbon\Carbon;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\DB;
+use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions\F;
 
 /**
  * 大屏数据展示
@@ -1161,4 +1163,31 @@ class ScreenController extends BaseController
 
         return $order;
     }
+
+    public function createEquipmentData(Request $request){
+        $data = $request->all();
+        if(empty($data['sub'])) return $this->json_return(201,'', "设备信息不能为空");
+        $device = (new EquipmentService())->getDeviceList("code","id");
+        $dispatch = [];
+        foreach ($data['sub'] as $value){
+            if(empty($value['device_no'])) return [false, "设备编码不能为空"];
+            if(empty($value['finished_num'])) continue;
+            $start_time = $value['start_time'];
+            if(empty($value['start_time'])) $start_time = time();
+
+            $device_id = $device[$value['device_no']] ?? 0;
+            if(empty($device_id)) return [false, '设备不存在'];
+            $dispatch[] = [
+                'finished_num' => $value['finished_num'],
+                'start_time' => $start_time,
+                'device_id' => $device_id,
+                'crt_time' => time()
+            ];
+        }
+        if(empty($dispatch)) return $this->json_return(201,'', "请填写至少一个设备的生产数量(吨)");
+
+        ForDeviceData::insert($dispatch);
+
+        return $this->json_return(200,'操作成功', []);
+    }
 }

+ 350 - 0
app/Http/Controllers/Api/TestController.php

@@ -3,6 +3,9 @@
 namespace App\Http\Controllers\Api;
 
 
+use App\Model\DispatchSub;
+use App\Model\Equipment;
+use App\Model\SystemL;
 use App\Service\Box\BoxService;
 use App\Service\ProductionOrderService;
 use Illuminate\Support\Facades\Config;
@@ -19,6 +22,7 @@ class TestController extends BaseController
         (new ProductionOrderService())->delBoxLock();
         dd(1);
     }
+
     public function tt(){dd(1);
         $model_box = DB::connection("mysqlT9");
         $u8 = $model_box->table('setting')
@@ -75,4 +79,350 @@ class TestController extends BaseController
             dd($e->getMessage());
         }
     }
+
+    public function test(){dd(1111);
+        $dispatch = DispatchSub::where('del_time',0)
+            ->where('finished_num', '>',0)
+            ->where('process_id',14)
+            ->select('finished_num','upd_time','device_id')
+            ->orderBy('upd_time','asc')
+            ->get()->toArray();
+        foreach ($dispatch as $key => $value){
+            if(! $value['device_id']) $dispatch[$key]['device_id'] = 8;
+        }
+
+        // 生成数据
+        $generatedData = (new FeederDataGenerator)->generateData($dispatch);
+
+        dd("ok");
+    }
+}
+
+
+class FeederDataGenerator
+{
+    // 设备配置参数
+    const CAPACITY = 0.6; // 容器容量(吨)
+    const SUCTION_CAPACITY = 0.1; // 容器容量(吨) 下料
+    const SUCTION_WEIGHT = 0.1; // 每次吸料重量(吨)
+    const SUCTION_TIME_MIN = 300; // 吸料最短时间(秒) - 5分钟
+    const SUCTION_TIME_MAX = 360; // 吸料最长时间(秒) - 6分钟
+    const SUCTION_INTERVAL_MIN = 300; // 下次吸料最小间隔(秒) -
+    const SUCTION_INTERVAL_MAX = 360; // 下次吸料最大间隔(秒) -
+    const DISCHARGE_TIME_MIN = 240; // 下料最短时间(秒) - 4分钟
+    const DISCHARGE_TIME_MAX = 300; // 下料最长时间(秒) - 5分钟
+    const DISCHARGE_INTERVAL_MIN = 300; // 下次下料最小间隔(秒) -
+    const DISCHARGE_INTERVAL_MAX = 360; // 下次下料最大间隔(秒) -
+
+    private $devices = []; // 存储设备数据
+
+    /**
+     * 处理原始数据并生成设备运行明细
+     * @param array $rawData 原始数据源
+     * @return array 生成的设备运行明细数据
+     */
+    public function generateData(array $rawData): array
+    {
+        // 首先按设备和日期分组汇总产量
+        $this->processRawData($rawData);
+//dd($this->devices);
+        // 为每个设备生成运行明细
+        $result = [];
+        foreach ($this->devices as $deviceId => $deviceData) {
+            // 为每一天生成数据
+            foreach ($deviceData['daily_totals'] as $date => $total) {
+                $details = $this->generateDeviceDayData($deviceData['device'], $date, $total);
+                $result = array_merge($result, $details);
+            }
+        }
+
+        try {
+            DB::beginTransaction();
+
+            if(! empty($result)){
+                $chunkSize = 200; // 每次插入的数量
+                foreach (array_chunk($result, $chunkSize) as $chunk) {
+                    SystemL::insert($chunk); // 使用模型的 insert 方法批量插入
+                    echo '200条写入成功' . "\n";
+                }
+            }
+
+            DB::commit();
+        }catch (\Throwable $exception){
+            DB::rollBack();
+            return [false, $exception->getMessage()];
+        }
+
+        return [true, ''];
+    }
+
+    /**
+     * 处理原始数据,按设备和日期汇总产量
+     * @param array $rawData 原始数据源
+     */
+    private function processRawData(array $rawData)
+    {
+        $map = Equipment::select('id','code','title')->get()->toArray();
+        foreach ($map as $value){
+            $map1[$value['id']] = $value;
+        }
+        foreach ($rawData as $item) {
+            $deviceId = $item['device_id'];
+            $t = $map1[$deviceId];
+            $timestamp = $item['upd_time'];
+            $finishedNum = floatval($item['finished_num']);
+
+            // 解析日期
+            $date = date('Y-m-d', $timestamp);
+
+            // 初始化设备数据
+            if (!isset($this->devices[$deviceId])) {
+                $this->devices[$deviceId] = [
+                    'device' => $t,
+                    'total_production' => 0,
+                    'daily_totals' => []
+                ];
+            }
+
+            // 累加总产量和每日产量
+            $this->devices[$deviceId]['total_production'] += $finishedNum;
+            if (!isset($this->devices[$deviceId]['daily_totals'][$date])) {
+                $this->devices[$deviceId]['daily_totals'][$date] = 0;
+            }
+            $this->devices[$deviceId]['daily_totals'][$date] += $finishedNum;
+        }
+    }
+
+    /**
+     * 为单个设备的一天生成详细的运行数据
+     * @param int $deviceId 设备ID
+     * @param string $date 日期(格式:YYYY-MM-DD)
+     * @param float $totalProduction 当天总产量
+     * @return array 生成的详细数据条目
+     */
+    private function generateDeviceDayData(array $device, string $date, float $totalProduction): array
+    {
+        $result = [];
+
+        // 计算当天需要完成多少轮完整的吸料-下料循环
+        $fullCycles = floor($totalProduction / self::SUCTION_CAPACITY);
+        $filledAmount = $fullCycles * self::SUCTION_CAPACITY;
+        $remainingWeight = bcsub($totalProduction, $filledAmount,2);
+
+        // 设置当天的起始时间戳(早上7:30)
+        $currentTime = strtotime($date . ' 07:30:00');
+
+        // 执行完整循环
+        for ($i = 0; $i < $fullCycles; $i++) {
+            // 执行一次完整的吸料-下料过程
+            $cycleData = $this->generateFullCycle($device, $currentTime);
+            $result = array_merge($result, $cycleData);
+
+            // 更新当前时间
+            $currentTime = end($cycleData)['time'];
+
+//            // 添加随机间隔时间
+//            $interval = rand(self::SUCTION_INTERVAL_MIN, self::SUCTION_INTERVAL_MAX);
+//            $currentTime += $interval;
+        }
+
+        // 如果有剩余量,执行部分吸料过程
+        if ($remainingWeight > 0) {
+            $lastKey = array_key_last($result); // 获取最后一个键
+            $result[$lastKey]['value'] += $remainingWeight;
+//            $remainingCyleData = $this->generatePartialCycle($device, $currentTime, $remainingWeight);
+//            $result = array_merge($result, $remainingCyleData);
+        }
+
+        return $result;
+    }
+
+    /**
+     * 随机插入急停事件,并模拟急停持续时间
+     *
+     * @param int $deviceId 设备ID
+     * @param int &$currentTime 当前时间戳(引用传递,用于更新)
+     * @param array &$result 结果数组(引用传递,用于添加急停记录)
+     */
+    private function maybeInsertEmergencyStop(array $device, int &$currentTime, array &$result, $data_point_id, $data_point_name): void
+    {
+        if (rand(1, 100) <= 3) { // 3% 的概率触发急停
+            $emergencyStopTime = $currentTime;
+
+            // 插入急停开始事件
+            $result[] = [
+                'time' => $emergencyStopTime,
+                'value' => -1, // 标识为急停
+                'device_no' => $device['code'],
+                'device_name' => $device['title'],
+                'data_point_id' => $data_point_id,
+                'data_point_name' => $data_point_name,
+                'push_time' => $emergencyStopTime,
+//                 'push_time_day' =>  date("Y-m-d H:i:s",$suctionStartTime)
+            ];
+
+            // 模拟急停持续时间(10~15秒)
+            $stopDuration = rand(10, 15);
+            $currentTime += $stopDuration;
+
+            // 可选:插入急停结束事件(也可以不插,只用时间推移表示)
+//            $result[] = [
+//                'time' => $currentTime,
+//                'value' => -2, // 急停恢复
+//                'device_no' => $deviceId,
+//                'push_time' => $currentTime
+//            ];
+        }
+    }
+
+    /**
+     * 生成一个完整的吸料-下料循环数据
+     * @param int $deviceId 设备ID
+     * @param int $startTime 起始时间戳
+     * @return array 生成的数据条目
+     */
+    private function generateFullCycle(array $device, int $startTime): array
+    {
+        $result = [];
+        $currentTime = $startTime;
+
+        // 吸料阶段
+        for ($i = 0; $i < 1; $i++) {
+            // 【吸料前】尝试插入急停
+            $this->maybeInsertEmergencyStop($device, $currentTime, $result,5,"吸料急停");
+
+            // 吸料开始
+            $suctionStartTime = $currentTime;
+            $result[] = [
+                'time' => $suctionStartTime,
+                'value' => 1,
+                'device_no' => $device['code'],
+                'device_name' => $device['title'],
+                'data_point_id' => 1,
+                'data_point_name' => "吸料",
+                'push_time' => $suctionStartTime,
+//                 'push_time_day' =>  date("Y-m-d H:i:s",$suctionStartTime)
+            ];
+
+            // 吸料结束
+            $suctionDuration = rand(self::SUCTION_TIME_MIN, self::SUCTION_TIME_MAX);
+            $currentTime += $suctionDuration;
+
+            // 【吸料后】尝试插入急停
+            $this->maybeInsertEmergencyStop($device, $currentTime, $result,5,"吸料急停");
+
+            $result[] = [
+                'time' => $currentTime,
+                'value' => self::SUCTION_WEIGHT,
+                'device_no' => $device['code'],
+                'device_name' => $device['title'],
+                'data_point_id' => 2,
+                'data_point_name' => "吸料结束且本次吸料重量",
+                'push_time' => $currentTime,
+//                 'push_time_day' => date("Y-m-d H:i:s",$currentTime)
+            ];
+
+            // 添加随机间隔时间
+            if ($i < 1) {  // 最后一次吸料后不需要等待
+//                $interval = rand(self::SUCTION_INTERVAL_MIN, self::SUCTION_INTERVAL_MAX);
+                $interval = rand(10, 15);
+                $currentTime += $interval;
+            }
+        }
+
+        // 【下料前】尝试插入急停
+        $this->maybeInsertEmergencyStop($device, $currentTime, $result,6,"下料急停");
+
+        // 下料阶段
+        $dischargeStartTime = $currentTime;
+        $result[] = [
+            'time' => $dischargeStartTime,
+            'value' => 1,
+            'device_no' => $device['code'],
+            'device_name' => $device['title'],
+            'data_point_id' => 3,
+            'data_point_name' => "下料",
+            'push_time' => $dischargeStartTime,
+//             'push_time_day' => date("Y-m-d H:i:s",$dischargeStartTime)
+        ];
+
+        $dischargeDuration = rand(self::DISCHARGE_TIME_MIN, self::DISCHARGE_TIME_MAX);
+        $currentTime += $dischargeDuration;
+
+        // 【下料后】尝试插入急停
+        $this->maybeInsertEmergencyStop($device, $currentTime, $result,6,"下料急停");
+
+        $result[] = [
+            'time' => $currentTime,
+            'value' => self::SUCTION_CAPACITY,
+            'device_no' => $device['code'],
+            'device_name' => $device['title'],
+            'data_point_id' => 4,
+            'data_point_name' => "下料结束且本次下料重量",
+            'push_time' => $currentTime,
+//             'push_time_day' => date("Y-m-d H:i:s",$currentTime)
+        ];
+
+        return $result;
+    }
+
+    /**
+     * 生成一个不完整的循环(只有吸料部分)
+     * @param int $deviceId 设备ID
+     * @param int $startTime 起始时间戳
+     * @param float $requiredWeight 需要吸的重量
+     * @return array 生成的数据条目
+     */
+    private function generatePartialCycle(array $device, int $startTime, float $requiredWeight): array
+    {
+        $result = [];
+        $currentTime = $startTime;
+
+        // 计算需要多少次吸料
+        $suctionsNeeded = ceil($requiredWeight / self::SUCTION_WEIGHT);
+        $totalSuctionWeight = 0;
+
+        for ($i = 0; $i < $suctionsNeeded; $i++) {
+            // 吸料开始
+            $suctionStartTime = $currentTime;
+            $result[] = [
+                'time' => $suctionStartTime,
+                'value' => 1,
+                'device_no' => $device['code'],
+                'device_name' => $device['title'],
+                'data_point_id' => 1,
+                'data_point_name' => "吸料",
+                'push_time' => $suctionStartTime,
+                // 'push_time_day' =>  => date("Y-m-d H:i:s",$suctionStartTime)
+            ];
+
+            // 吸料结束
+            $suctionDuration = rand(self::SUCTION_TIME_MIN, self::SUCTION_TIME_MAX);
+            $currentTime += $suctionDuration;
+
+            // 判断这次吸料是否会导致超过所需总量
+            $addedWeight = ($i == $suctionsNeeded - 1) ? $requiredWeight - $totalSuctionWeight : self::SUCTION_WEIGHT;
+            $totalSuctionWeight += $addedWeight;
+
+            $result[] = [
+                'time' => $currentTime,
+                'value' => $addedWeight,
+                'device_no' => $device['code'],
+                'device_name' => $device['title'],
+                'data_point_id' => 2,
+                'data_point_name' => "吸料结束且本次吸料重量",
+                'push_time' => $currentTime,
+                // 'push_time_day' =>  => date("Y-m-d H:i:s",$currentTime)
+            ];
+
+            // 添加随机间隔时间(在40-50分钟之间)
+            if ($i < $suctionsNeeded - 1) {
+                $interval = rand(self::SUCTION_INTERVAL_MIN, self::SUCTION_INTERVAL_MAX);
+                $currentTime += $interval;
+            }
+        }
+
+        return $result;
+    }
 }
+

+ 13 - 0
app/Model/ForDeviceData.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace App\Model;
+
+use Illuminate\Database\Eloquent\Model;
+
+class ForDeviceData extends Model
+{
+    protected $table = "for_device_data"; //指定表
+    const CREATED_AT = 'crt_time';
+    const UPDATED_AT = 'upd_time';
+    protected $dateFormat = 'U';
+}

+ 1 - 0
routes/api.php

@@ -197,6 +197,7 @@ Route::group(['middleware'=> ['checkLogin']],function ($route){
 
     //设备报表
     $route->any('deviceLists','Api\ReportFormsController@deviceList');
+    $route->any('createEquipmentData','Api\ScreenController@createEquipmentData');
     $route->any('deviceStatisticsReport', 'Api\ReportFormsController@deviceStatisticsReport');
     $route->any('deviceStatisticsReportDetail', 'Api\ReportFormsController@deviceStatisticsReportDetail');
     $route->any('deviceStatisticsReportChart', 'Api\ReportFormsController@deviceStatisticsReportChart');