|
|
@@ -1117,7 +1117,7 @@ class PersonWorkService extends Service
|
|
|
* @param array $user 用户信息
|
|
|
* @return array
|
|
|
*/
|
|
|
- private function calculateDailyAllocation1($monthStart, $topDepartId, $user)
|
|
|
+ private function calculateDailyAllocation($monthStart, $topDepartId, $user)
|
|
|
{
|
|
|
$monthEnd = strtotime('+1 month', $monthStart) - 1;
|
|
|
$now = time();
|
|
|
@@ -1277,170 +1277,6 @@ class PersonWorkService extends Service
|
|
|
return ['status' => true, 'data' => $previewList];
|
|
|
}
|
|
|
|
|
|
- private function calculateDailyAllocation($monthStart, $topDepartId, $user)
|
|
|
- {
|
|
|
- $monthEnd = strtotime('+1 month', $monthStart) - 1;
|
|
|
- $now = time();
|
|
|
-
|
|
|
- // --- 1. 基础数据加载 (保持原逻辑) ---
|
|
|
- $monthlyOrder = DB::table('monthly_pw_order_details as d')
|
|
|
- ->join('monthly_pw_order as m', 'm.id', '=', 'd.main_id')
|
|
|
- ->leftJoin('employee as e', 'e.id', '=', 'd.employee_id')
|
|
|
- ->where('m.month', $monthStart)
|
|
|
- ->where('m.top_depart_id', $topDepartId)
|
|
|
- ->where('m.del_time', 0)
|
|
|
- ->where('d.del_time', 0)
|
|
|
- ->select('d.*', 'e.title as employee_title')
|
|
|
- ->get();
|
|
|
-
|
|
|
- if ($monthlyOrder->isEmpty()) return ['status' => false, 'msg' => '未找到该月份的月度工时明细'];
|
|
|
-
|
|
|
- $empNameMap = $monthlyOrder->pluck('employee_title', 'employee_id')->toArray();
|
|
|
- $empIds = array_keys($empNameMap);
|
|
|
-
|
|
|
- $itemIds = DB::table('rule_set_details as rd')
|
|
|
- ->join('rule_set as r', 'r.id', '=', 'rd.main_id')
|
|
|
- ->where('r.month', $monthStart)
|
|
|
- ->where('r.top_depart_id', $topDepartId)
|
|
|
- ->pluck('rd.item_id')->unique()->toArray();
|
|
|
-
|
|
|
- $itemMap = DB::table('item')->whereIn('id', $itemIds)->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', 1)
|
|
|
- ->where('r.del_time', 0)
|
|
|
- ->where('rd.del_time', 0)
|
|
|
- ->select('rd.*')
|
|
|
- ->get()
|
|
|
- ->groupBy('data_id');
|
|
|
-
|
|
|
- $empWorkRanges = DB::table('employee_work_range')
|
|
|
- ->whereIn('employee_id', $empIds)
|
|
|
- ->where('top_depart_id', $topDepartId)
|
|
|
- ->get()->groupBy('employee_id');
|
|
|
- $standardWorkRanges = DB::table('work_range_details')->where('top_depart_id', $topDepartId)
|
|
|
- ->where('del_time', 0)->get();
|
|
|
- $allDays = DB::table('calendar_details')->where('top_depart_id', $topDepartId)
|
|
|
- ->where('month', $monthStart)
|
|
|
- ->where('del_time', 0)
|
|
|
- ->orderBy('time', 'asc')
|
|
|
- ->get();
|
|
|
- $leaveOverData = DB::table('p_leave_over_order_details as d')->join('p_leave_over_order as m', 'd.main_id', '=', 'm.id')
|
|
|
- ->whereBetween('m.order_time', [$monthStart, $monthEnd])
|
|
|
- ->where('d.top_depart_id', $topDepartId)
|
|
|
- ->where('m.del_time', 0)
|
|
|
- ->select('d.*', 'm.order_time', 'm.type as main_type')
|
|
|
- ->get()->groupBy(['employee_id', 'order_time']);
|
|
|
-
|
|
|
- // --- 2. 阶段一:计算每个人每天在每个项目上应分配的整数分钟数 (保持原逻辑) ---
|
|
|
- $finalAlloc = [];
|
|
|
- foreach ($monthlyOrder as $mDetail) {
|
|
|
- $empId = $mDetail->employee_id;
|
|
|
- $empRules = $ruleSet->get($empId);
|
|
|
- if (!$empRules) continue;
|
|
|
-
|
|
|
- $empRemainingMin = (int)round((float)$mDetail->rd_total_hours * 60);
|
|
|
- if ($empRemainingMin <= 0) continue;
|
|
|
-
|
|
|
- foreach ($allDays as $dayInfo) {
|
|
|
- if ($empRemainingMin <= 0) break;
|
|
|
- $dayTs = $dayInfo->time;
|
|
|
- $tempPool = $this->buildAvailablePool($empId, $dayTs, $allDays, $empWorkRanges, $standardWorkRanges, $leaveOverData);
|
|
|
- $dayAvailableMin = 0;
|
|
|
- foreach ($tempPool as $p) { $dayAvailableMin += (int)($p['e'] - $p['s']); }
|
|
|
- if ($dayAvailableMin <= 0) continue;
|
|
|
-
|
|
|
- $canAllocToday = min($empRemainingMin, $dayAvailableMin);
|
|
|
- $allocatedInDay = 0;
|
|
|
- $ruleCount = count($empRules);
|
|
|
-
|
|
|
- foreach ($empRules 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[$dayTs][$rule->item_id][$empId] = $projectMin;
|
|
|
- $allocatedInDay += $projectMin;
|
|
|
- }
|
|
|
- }
|
|
|
- $empRemainingMin -= $canAllocToday;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // --- 3. 阶段二:打散到具体时间点并对齐 30 分钟步长 ---
|
|
|
- $previewList = [];
|
|
|
- $dailyEmpTimePools = [];
|
|
|
- $tempMainIdCounter = 1;
|
|
|
- $step = 30; // 设定步长为 30 分钟
|
|
|
-
|
|
|
- foreach ($finalAlloc as $dayTs => $projects) {
|
|
|
- foreach ($projects as $itemId => $employees) {
|
|
|
- $currentTempMainId = $tempMainIdCounter++;
|
|
|
- $itemTitle = $itemMap[$itemId] ?? '未知项目';
|
|
|
-
|
|
|
- foreach ($employees as $empId => $toAllocMin) {
|
|
|
- if (!isset($dailyEmpTimePools[$dayTs][$empId])) {
|
|
|
- $dailyEmpTimePools[$dayTs][$empId] = $this->buildAvailablePool($empId, $dayTs, $allDays, $empWorkRanges, $standardWorkRanges, $leaveOverData);
|
|
|
- }
|
|
|
-
|
|
|
- $tempRem = (int)$toAllocMin;
|
|
|
- foreach ($dailyEmpTimePools[$dayTs][$empId] as &$p) {
|
|
|
- if ($tempRem <= 0) break;
|
|
|
-
|
|
|
- // 1. 起始点对齐:如果当前开始时间不是 30 的倍数,向上取整
|
|
|
- // 例如:08:15 (495min) -> 08:30 (510min)
|
|
|
- if ($p['s'] % $step != 0) {
|
|
|
- $p['s'] = ceil($p['s'] / $step) * $step;
|
|
|
- }
|
|
|
-
|
|
|
- $pMax = (int)($p['e'] - $p['s']);
|
|
|
- if ($pMax <= 0) continue;
|
|
|
-
|
|
|
- // 2. 确定本次扣除的分钟数
|
|
|
- // 如果剩余量大于步长,取步长的倍数;如果小于步长,则一次性取完
|
|
|
- if ($tempRem >= $step) {
|
|
|
- $take = min(floor($tempRem / $step) * $step, floor($pMax / $step) * $step);
|
|
|
- // 如果计算出的 take 为 0(说明当前池子不够 30min),则跳过该池子
|
|
|
- if ($take <= 0) continue;
|
|
|
- } else {
|
|
|
- $take = min($tempRem, $pMax);
|
|
|
- }
|
|
|
-
|
|
|
- $realStart = (int)$p['s'];
|
|
|
- $realEnd = $realStart + $take;
|
|
|
-
|
|
|
- $previewList[] = [
|
|
|
- 'temp_main_id' => $currentTempMainId,
|
|
|
- 'order_time' => date('Y-m-d', $dayTs),
|
|
|
- 'order_timestamp' => $dayTs,
|
|
|
- 'item_id' => $itemId,
|
|
|
- 'item_title' => $itemTitle,
|
|
|
- 'employee_id' => $empId,
|
|
|
- 'employee_title' => $empNameMap[$empId] ?? '未知人员',
|
|
|
- 'start_time' => sprintf('%02d:%02d', floor($realStart / 60), $realStart % 60),
|
|
|
- 'end_time' => sprintf('%02d:%02d', floor($realEnd / 60), $realEnd % 60),
|
|
|
- 'start_hour' => (int)floor($realStart / 60),
|
|
|
- 'start_min' => (int)($realStart % 60),
|
|
|
- 'end_hour' => (int)floor($realEnd / 60),
|
|
|
- 'end_min' => (int)($realEnd % 60),
|
|
|
- 'total_work_min' => $take,
|
|
|
- ];
|
|
|
-
|
|
|
- $tempRem -= $take;
|
|
|
- $p['s'] = $realEnd;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return ['status' => true, 'data' => $previewList];
|
|
|
- }
|
|
|
-
|
|
|
public function dailyPwOrderSave($data, $user)
|
|
|
{
|
|
|
$list = $data['list'] ?? [];
|