Browse Source

小高薪

cqp 2 months ago
parent
commit
ce667ea4e8
1 changed files with 167 additions and 1 deletions
  1. 167 1
      app/Service/DeviceWorkService.php

+ 167 - 1
app/Service/DeviceWorkService.php

@@ -1037,7 +1037,7 @@ class DeviceWorkService extends Service
         ]];
     }
 
-    private function calculateDailyDeviceAllocation($monthStart, $topDepartId, $user)
+    private function calculateDailyDeviceAllocation1($monthStart, $topDepartId, $user)
     {
         // 加载月度设备明细
         $monthlyOrder = DB::table('monthly_dw_order_details as d')
@@ -1189,6 +1189,172 @@ class DeviceWorkService extends Service
         return ['status' => true, 'data' => $previewList];
     }
 
+    private function calculateDailyDeviceAllocation($monthStart, $topDepartId, $user)
+    {
+        // 加载月度设备明细
+        $monthlyOrder = DB::table('monthly_dw_order_details as d')
+            ->join('monthly_dw_order as m', 'm.id', '=', 'd.main_id')
+            ->where('m.month', $monthStart)
+            ->where('m.top_depart_id', $topDepartId)
+            ->where('m.del_time', 0)
+            ->where('d.del_time', 0)
+            ->select('d.*')
+            ->get();
+
+        if ($monthlyOrder->isEmpty()) return ['status' => false, 'msg' => '未找到设备月度工时明细'];
+
+        $usedDeviceIds = $monthlyOrder->pluck('device_id')->unique()->toArray();
+
+        $deviceMap = DB::table('device')
+            ->whereIn('id', $usedDeviceIds)
+            ->pluck('title', 'id')
+            ->toArray();
+
+        // 加载分配规则
+        $ruleSet = DB::table('rule_set_details as rd')
+            ->join('rule_set as r', 'r.id', '=', 'rd.main_id')
+            ->where('r.month', $monthStart)
+            ->where('rd.type', 2) // 设备类型
+            ->where('rd.top_depart_id', $topDepartId)
+            ->where('r.del_time', 0)
+            ->where('rd.del_time', 0)
+            ->select('rd.*')
+            ->get();
+
+        $usedItemIds = $ruleSet->pluck('item_id')->unique()->toArray();
+        $itemMap = DB::table('item')
+            ->whereIn('id', $usedItemIds)
+            ->pluck('title', 'id')
+            ->toArray();
+
+        $ruleSetGrouped = $ruleSet->groupBy('data_id');
+
+        // 标准班次 & 日历
+        $standardWorkRanges = DB::table('work_range_details')
+            ->where('top_depart_id', $topDepartId)
+            ->where('del_time', 0)
+            ->get();
+        $dayMaxAvail = (int)$standardWorkRanges->sum('total_work_min');
+
+        $workDays = DB::table('calendar_details')
+            ->where('top_depart_id', $topDepartId)
+            ->where('month', $monthStart)
+            ->where('is_work', 1)
+            ->where('del_time', 0)
+            ->orderBy('time', 'asc')->get();
+
+        if ($workDays->isEmpty()) return ['status' => false, 'msg' => '未配置工作日历'];
+
+        // --- 2. 阶段一:计算每天每台设备分配的项目分钟数 (保持原逻辑) ---
+        $finalAlloc = [];
+        foreach ($monthlyOrder as $mDetail) {
+            $deviceId = $mDetail->device_id;
+            $deviceRules = $ruleSetGrouped->get($deviceId);
+            if (!$deviceRules) continue;
+
+            $remainingMin = (int)round((float)$mDetail->rd_total_hours * 60);
+            if ($remainingMin <= 0) continue;
+
+            foreach ($workDays as $dayInfo) {
+                if ($remainingMin <= 0) break;
+
+                $canAllocToday = min($remainingMin, $dayMaxAvail);
+                $allocatedInDay = 0;
+                $ruleCount = count($deviceRules);
+
+                foreach ($deviceRules as $index => $rule) {
+                    $rate = (float)$rule->rate / 100;
+                    if ($index === $ruleCount - 1) {
+                        $projectMin = $canAllocToday - $allocatedInDay;
+                    } else {
+                        $projectMin = (int)round($canAllocToday * $rate);
+                    }
+
+                    if ($projectMin > 0) {
+                        $finalAlloc[$dayInfo->time][$rule->item_id][$deviceId] = $projectMin;
+                        $allocatedInDay += $projectMin;
+                    }
+                }
+                $remainingMin -= $canAllocToday;
+            }
+        }
+
+        // --- 3. 阶段二:生成预览行并对齐 30 分钟 ---
+        $previewList = [];
+        $dailyDevicePools = [];
+        $tempMainIdCounter = 1;
+        $step = 30; // 步长
+
+        foreach ($finalAlloc as $dayTs => $projects) {
+            foreach ($projects as $itemId => $devices) {
+
+                $currentTempMainId = $tempMainIdCounter++;
+                $itemTitle = $itemMap[$itemId] ?? '未知项目';
+
+                foreach ($devices as $deviceId => $toAllocMin) {
+                    if (!isset($dailyDevicePools[$dayTs][$deviceId])) {
+                        $pool = [];
+                        foreach ($standardWorkRanges as $swr) {
+                            $pool[] = [
+                                's' => (int)($swr->start_time_hour * 60 + $swr->start_time_min),
+                                'e' => (int)($swr->end_time_hour * 60 + $swr->end_time_min)
+                            ];
+                        }
+                        $dailyDevicePools[$dayTs][$deviceId] = $pool;
+                    }
+
+                    $tempRem = (int)$toAllocMin;
+                    foreach ($dailyDevicePools[$dayTs][$deviceId] as &$p) {
+                        if ($tempRem <= 0) break;
+
+                        // 【改动】起始点对齐:非30分钟整点则向上对齐
+                        if ($p['s'] % $step != 0) {
+                            $p['s'] = ceil($p['s'] / $step) * $step;
+                        }
+
+                        $pMax = (int)($p['e'] - $p['s']);
+                        if ($pMax <= 0) continue;
+
+                        // 【改动】取量对齐逻辑
+                        if ($tempRem >= $step) {
+                            // 尽量按步长分配
+                            $take = min(floor($tempRem / $step) * $step, floor($pMax / $step) * $step);
+                            if ($take <= 0) continue;
+                        } else {
+                            // 最后一丁点零头
+                            $take = min($tempRem, $pMax);
+                        }
+
+                        $start = (int)$p['s'];
+                        $end = $start + $take;
+
+                        $previewList[] = [
+                            'temp_main_id'    => $currentTempMainId,
+                            'order_time'      => date('Y-m-d', $dayTs),
+                            'order_timestamp' => $dayTs,
+                            'item_id'         => $itemId,
+                            'item_title'      => $itemTitle,
+                            'device_id'       => $deviceId,
+                            'device_title'    => $deviceMap[$deviceId] ?? '未知设备',
+                            'start_time'      => sprintf('%02d:%02d', floor($start / 60), $start % 60),
+                            'end_time'        => sprintf('%02d:%02d', floor($end / 60), $end % 60),
+                            'start_hour'      => (int)floor($start / 60),
+                            'start_min'       => (int)($start % 60),
+                            'end_hour'        => (int)floor($end / 60),
+                            'end_min'         => (int)($end % 60),
+                            'total_work_min'  => $take,
+                        ];
+
+                        $tempRem -= $take;
+                        $p['s'] = $end;
+                    }
+                }
+            }
+        }
+
+        return ['status' => true, 'data' => $previewList];
+    }
+
     public function dailyDwOrderSave($data, $user)
     {
         $list = $data['list'] ?? [];