|
|
@@ -1238,27 +1238,24 @@ class PersonWorkService extends Service
|
|
|
$month = $data['month'];
|
|
|
$now = time();
|
|
|
|
|
|
- // 1. 预加载员工姓名,用于精准报错
|
|
|
+ // 1. 预加载员工姓名 (注意字段名,如果是 employee 表通常用 title 或 name)
|
|
|
$empIds = collect($list)->pluck('employee_id')->unique()->toArray();
|
|
|
- $empMap = DB::table('employee')
|
|
|
- ->whereIn('id', $empIds)
|
|
|
- ->pluck('title', 'id')
|
|
|
- ->toArray();
|
|
|
+ $empMap = DB::table('employee')->whereIn('id', $empIds)->pluck('title', 'id')->toArray();
|
|
|
|
|
|
- // --- 2. 重新分组:在分组的同时,利用原始索引记录行号 ---
|
|
|
+ // --- 2. 重新分组并记录行号 ---
|
|
|
$groupedByOrder = [];
|
|
|
foreach ($list as $index => $item) {
|
|
|
- $item['_line'] = $index + 1; // 记录原始行号(从1开始)
|
|
|
+ $item['_line'] = $index + 1;
|
|
|
+ // 确保使用日期字符串作为分组 Key
|
|
|
$groupKey = $item['order_time'] . '_' . $item['item_id'];
|
|
|
$groupedByOrder[$groupKey][] = $item;
|
|
|
}
|
|
|
|
|
|
- // 3. 跨单据冲突校验器:记录 [员工ID][日期] 的时间轴
|
|
|
$empTimeline = [];
|
|
|
|
|
|
DB::beginTransaction();
|
|
|
try {
|
|
|
- // A. 清理该月份旧数据 (is_create = 1 表示自动生成的)
|
|
|
+ // A. 清理该月份旧数据
|
|
|
$monthStart = $this->changeDateToDate($month);
|
|
|
$monthEnd = strtotime('+1 month', $monthStart) - 1;
|
|
|
|
|
|
@@ -1273,17 +1270,17 @@ class PersonWorkService extends Service
|
|
|
DB::table('daily_pw_order_details')->whereIn('main_id', $oldOrderIds)->update(['del_time' => $now]);
|
|
|
}
|
|
|
|
|
|
- // B. 遍历重组后的分组写入
|
|
|
+ // B. 遍历分组写入
|
|
|
foreach ($groupedByOrder as $details) {
|
|
|
$first = $details[0];
|
|
|
- $orderTime = $first['order_timestamp'];
|
|
|
+ // 【修正】统一将前端 order_time 日期字符串转为时间戳
|
|
|
+ $orderTimestamp = strtotime($first['order_time']);
|
|
|
$itemId = $first['item_id'];
|
|
|
|
|
|
- // 写入主表
|
|
|
$mainId = DB::table('daily_pw_order')->insertGetId([
|
|
|
'code' => '',
|
|
|
'item_id' => $itemId,
|
|
|
- 'order_time' => $orderTime,
|
|
|
+ 'order_time' => $orderTimestamp,
|
|
|
'top_depart_id' => $topDepartId,
|
|
|
'is_create' => 1,
|
|
|
'crt_id' => $user['id'],
|
|
|
@@ -1292,31 +1289,30 @@ class PersonWorkService extends Service
|
|
|
|
|
|
$insertDetails = [];
|
|
|
foreach ($details as $d) {
|
|
|
- $rowNum = $d['_line']; // 获取原始行号
|
|
|
+ $rowNum = $d['_line'];
|
|
|
$empId = $d['employee_id'];
|
|
|
- $empName = $empMap[$empId] ?? "未知人员(ID:{$empId})";
|
|
|
+ $empName = $empMap[$empId] ?? "人员(ID:{$empId})";
|
|
|
|
|
|
- // 计算分钟数
|
|
|
+ // 【修正】强制由后端计算分钟数,防止前端篡改
|
|
|
$s = (int)$d['start_hour'] * 60 + (int)$d['start_min'];
|
|
|
$e = (int)$d['end_hour'] * 60 + (int)$d['end_min'];
|
|
|
-
|
|
|
- // --- 校验逻辑:精准提示行号 ---
|
|
|
+ $calcTotalMin = $e - $s;
|
|
|
|
|
|
// 校验1:逻辑合法性
|
|
|
- if ($e <= $s) {
|
|
|
- return [false, "第 {$rowNum} 行:人员[{$empName}]在[{$d['order_time']}]的时间段无效:结束时间应晚于开始时间"];
|
|
|
+ if ($calcTotalMin <= 0) {
|
|
|
+ return [false, "第 {$rowNum} 行:人员[{$empName}]的结束时间必须晚于开始时间"];
|
|
|
}
|
|
|
|
|
|
- // 校验2:跨单据时间重叠校验
|
|
|
- if (isset($empTimeline[$empId][$orderTime])) {
|
|
|
- foreach ($empTimeline[$empId][$orderTime] as $exist) {
|
|
|
- // 碰撞判断: Max(S1, S2) < Min(E1, E2) 则重叠
|
|
|
+ // 校验2:跨单据时间重叠校验 (使用 order_time 字符串作为 Timeline Key 即可)
|
|
|
+ $dateStr = $d['order_time'];
|
|
|
+ if (isset($empTimeline[$empId][$dateStr])) {
|
|
|
+ foreach ($empTimeline[$empId][$dateStr] as $exist) {
|
|
|
if ($s < $exist['e'] && $e > $exist['s']) {
|
|
|
- return [false, "第 {$rowNum} 行:人员[{$empName}]在[{$d['order_time']}]存在时间重叠({$d['start_time']}-{$d['end_time']}),请检查!"];
|
|
|
+ return [false, "第 {$rowNum} 行:人员[{$empName}]在[{$dateStr}]存在时间重叠({$d['start_time']}-{$d['end_time']}),请检查!"];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- $empTimeline[$empId][$orderTime][] = ['s' => $s, 'e' => $e];
|
|
|
+ $empTimeline[$empId][$dateStr][] = ['s' => $s, 'e' => $e];
|
|
|
|
|
|
$insertDetails[] = [
|
|
|
'main_id' => $mainId,
|
|
|
@@ -1326,25 +1322,24 @@ class PersonWorkService extends Service
|
|
|
'start_time_min' => $d['start_min'],
|
|
|
'end_time_hour' => $d['end_hour'],
|
|
|
'end_time_min' => $d['end_min'],
|
|
|
- 'total_work_min' => $d['total_work_min'],
|
|
|
+ 'total_work_min' => $calcTotalMin, // 使用计算出的分钟数
|
|
|
'crt_time' => $now,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
- // 批量写入明细
|
|
|
DB::table('daily_pw_order_details')->insert($insertDetails);
|
|
|
|
|
|
// C. 回填单号
|
|
|
$code = $this->generateBillNo([
|
|
|
'top_depart_id' => $topDepartId,
|
|
|
'type' => DailyPwOrder::Order_type,
|
|
|
- 'period' => date("Ym", $orderTime)
|
|
|
+ 'period' => date("Ym", $orderTimestamp)
|
|
|
]);
|
|
|
DB::table('daily_pw_order')->where('id', $mainId)->update(['code' => $code]);
|
|
|
}
|
|
|
|
|
|
DB::commit();
|
|
|
- return [true, ''];
|
|
|
+ return [true, '保存成功'];
|
|
|
} catch (\Exception $e) {
|
|
|
DB::rollBack();
|
|
|
return [false, "保存失败:" . $e->getMessage()];
|