|
|
@@ -1086,32 +1086,38 @@ class PersonWorkService extends Service
|
|
|
$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.*')
|
|
|
+ ->select('d.*', 'e.title as employee_title') // 获取人员姓名
|
|
|
->get();
|
|
|
|
|
|
if ($monthlyOrder->isEmpty()) return ['status' => false, 'msg' => '未找到该月份的月度工时明细'];
|
|
|
|
|
|
- $empIds = $monthlyOrder->pluck('employee_id')->unique()->toArray();
|
|
|
+ // 建立人员 ID -> 姓名的映射,方便后续取用
|
|
|
+ $empNameMap = $monthlyOrder->pluck('employee_title', 'employee_id')->toArray();
|
|
|
+ $empIds = array_keys($empNameMap);
|
|
|
|
|
|
- // 加载员工/标准班次
|
|
|
- $empWorkRanges = DB::table('employee_work_range')
|
|
|
- ->whereIn('employee_id', $empIds)
|
|
|
- ->where('top_depart_id', $topDepartId)
|
|
|
- ->get()
|
|
|
- ->groupBy('employee_id');
|
|
|
+ // 加载项目信息,用于获取项目名称
|
|
|
+ // 假设项目表名为 items,请根据你实际的表名修改
|
|
|
+ $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();
|
|
|
|
|
|
- $standardWorkRanges = DB::table('work_range_details')
|
|
|
- ->where('top_depart_id', $topDepartId)
|
|
|
- ->where('del_time', 0)
|
|
|
- ->get();
|
|
|
+ $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)
|
|
|
@@ -1122,21 +1128,13 @@ class PersonWorkService extends Service
|
|
|
->get()
|
|
|
->groupBy('data_id');
|
|
|
|
|
|
- // 加载日历
|
|
|
- $allDays = DB::table('calendar_details')
|
|
|
- ->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('m.del_time', 0)
|
|
|
- ->select('d.*', 'm.order_time', 'm.type as main_type')
|
|
|
- ->get()
|
|
|
- ->groupBy(['employee_id', 'order_time']);
|
|
|
+ // 加载员工/标准班次、日历、请假加班数据 (逻辑同前)
|
|
|
+ $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('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('m.del_time', 0)
|
|
|
+ ->select('d.*', 'm.order_time', 'm.type as main_type')->get()->groupBy(['employee_id', 'order_time']);
|
|
|
|
|
|
// --- 2. 阶段一:计算每个人每天在每个项目上应分配的整数分钟数 ---
|
|
|
$finalAlloc = [];
|
|
|
@@ -1145,43 +1143,28 @@ class PersonWorkService extends Service
|
|
|
$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;
|
|
|
-
|
|
|
- // 获取当天可用时间池段落(此处调用你原来的 buildAvailablePool)
|
|
|
$tempPool = $this->buildAvailablePool($empId, $dayTs, $allDays, $empWorkRanges, $standardWorkRanges, $leaveOverData);
|
|
|
-
|
|
|
- // 计算当天总可用整数分钟
|
|
|
$dayAvailableMin = 0;
|
|
|
- foreach ($tempPool as $p) {
|
|
|
- $dayAvailableMin += (int)($p['e'] - $p['s']);
|
|
|
- }
|
|
|
-
|
|
|
+ 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;
|
|
|
@@ -1192,29 +1175,25 @@ class PersonWorkService extends Service
|
|
|
}
|
|
|
|
|
|
// --- 3. 阶段二:打散到具体时间点并生成预览行 ---
|
|
|
-
|
|
|
$previewList = [];
|
|
|
$dailyEmpTimePools = [];
|
|
|
$tempMainIdCounter = 1;
|
|
|
|
|
|
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;
|
|
|
-
|
|
|
$pMax = (int)($p['e'] - $p['s']);
|
|
|
if ($pMax <= 0) continue;
|
|
|
|
|
|
@@ -1222,13 +1201,15 @@ class PersonWorkService extends Service
|
|
|
$realStart = (int)$p['s'];
|
|
|
$realEnd = $realStart + $take;
|
|
|
|
|
|
- // 构造预览行(全部字段已处理为整数)
|
|
|
+ // 写入带 Title 的结果
|
|
|
$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),
|
|
|
@@ -1239,7 +1220,7 @@ class PersonWorkService extends Service
|
|
|
];
|
|
|
|
|
|
$tempRem -= $take;
|
|
|
- $p['s'] = $realEnd; // 消耗池子
|
|
|
+ $p['s'] = $realEnd;
|
|
|
}
|
|
|
}
|
|
|
}
|