From e035ea2cb30eedbc14deacab792e69917a4e7308 Mon Sep 17 00:00:00 2001 From: sa0ChunLuyu Date: Tue, 28 Jul 2026 01:04:51 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E6=8E=92?= =?UTF-8?q?=E7=8F=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../API/Admin/YeWu/PlanListController.php | 39 ++++- .../app/Services/Admin/YeWu/RosterService.php | 137 ++++++++---------- 2 files changed, 93 insertions(+), 83 deletions(-) diff --git a/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php b/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php index 615836e..67b485f 100644 --- a/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php +++ b/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php @@ -433,6 +433,8 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster $allResults = []; $allTotal = 0; + $allGeneratedDates = []; + $allSkippedDates = []; foreach ($depts as $dept) { $today = date('Y-m-d'); @@ -455,6 +457,8 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster $allResults = array_merge($allResults, $res['details']); $allTotal += $res['total_count']; + $allGeneratedDates = array_merge($allGeneratedDates, $res['generated_dates']); + $allSkippedDates = array_merge($allSkippedDates, $res['skipped_dates']); } $successCount = collect($allResults)->where('status', 'success')->count(); @@ -462,11 +466,15 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster return \Yz::Return( true, - "自动生成完成,共 {$allTotal} 条 (成功: {$successCount} 资源, 失败: {$failedCount} 资源)", + "自动生成完成,生成 " . count($allGeneratedDates) . " 条,跳过 " . count($allSkippedDates) . " 条,共 {$allTotal} 条 (成功: {$successCount} 资源, 失败: {$failedCount} 资源)", [ 'total_count' => $allTotal, 'success_count' => $successCount, 'failed_count' => $failedCount, + 'generated_count' => count($allGeneratedDates), + 'skipped_count' => count($allSkippedDates), + 'generated_dates' => $allGeneratedDates, + 'skipped_dates' => $allSkippedDates, 'details' => $allResults ] ); @@ -483,7 +491,7 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster return \Yz::Return( true, - "批量生成完成,共 {$res['total_count']} 条 (成功: {$res['success_count']} 资源, 失败: {$res['failed_count']} 资源)", + "批量生成完成,生成 {$res['generated_count']} 条,跳过 {$res['skipped_count']} 条,共 {$res['total_count']} 条 (成功: {$res['success_count']} 资源, 失败: {$res['failed_count']} 资源)", $res ); } @@ -558,6 +566,8 @@ private function generateBatchForResources($resources, $dateRange, $HolidayEnabl foreach ($groupedByResource as $resourcesId => $models) { $groupedByDateType = $models->groupBy('date_type'); $resourceCount = 0; + $resourceGeneratedDates = []; + $resourceSkippedDates = []; try { foreach ($groupedByDateType as $dateType => $typeModels) { @@ -571,13 +581,17 @@ private function generateBatchForResources($resources, $dateRange, $HolidayEnabl $HolidayEnable ); $resourceCount += $result['count']; + $resourceGeneratedDates = array_merge($resourceGeneratedDates, $result['generated_dates']); + $resourceSkippedDates = array_merge($resourceSkippedDates, $result['skipped_dates']); } $results[] = [ 'resources_id' => $resourcesId, 'resources_name' => $models->first()->department_resources_name ?? '', 'status' => 'success', - 'count' => $resourceCount + 'count' => $resourceCount, + 'generated_dates' => $resourceGeneratedDates, + 'skipped_dates' => $resourceSkippedDates, ]; $totalCount += $resourceCount; @@ -587,7 +601,9 @@ private function generateBatchForResources($resources, $dateRange, $HolidayEnabl 'resources_name' => $models->first()->department_resources_name ?? '', 'status' => 'failed', 'error' => $e->getMessage(), - 'count' => 0 + 'count' => 0, + 'generated_dates' => [], + 'skipped_dates' => [], ]; } } @@ -596,10 +612,25 @@ private function generateBatchForResources($resources, $dateRange, $HolidayEnabl $successCount = collect($results)->where('status', 'success')->count(); $failedCount = collect($results)->where('status', 'failed')->count(); + $allGeneratedDates = []; + $allSkippedDates = []; + foreach ($results as $r) { + if (isset($r['generated_dates'])) { + $allGeneratedDates = array_merge($allGeneratedDates, $r['generated_dates']); + } + if (isset($r['skipped_dates'])) { + $allSkippedDates = array_merge($allSkippedDates, $r['skipped_dates']); + } + } + return [ 'total_count' => $totalCount, 'success_count' => $successCount, 'failed_count' => $failedCount, + 'generated_count' => count($allGeneratedDates), + 'skipped_count' => count($allSkippedDates), + 'generated_dates' => $allGeneratedDates, + 'skipped_dates' => $allSkippedDates, 'details' => $results ]; } diff --git a/Laravel/app/Services/Admin/YeWu/RosterService.php b/Laravel/app/Services/Admin/YeWu/RosterService.php index 9098aa1..ff1e24d 100644 --- a/Laravel/app/Services/Admin/YeWu/RosterService.php +++ b/Laravel/app/Services/Admin/YeWu/RosterService.php @@ -35,45 +35,31 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1, } } - // 获取部门ID (用于查重,取第一个模板的部门ID,假设批量操作通常针对同一部门) - // 如果业务允许跨部门混合勾选,这里可能需要调整查重逻辑(按部门分组查) - $department_id = $models->first()->department_id; - $start_date = new DateTime($dateRange[0]); $end_date = new DateTime($dateRange[1]); // ========================================== - // 【新增】1. 整体校验:模板与资源时令配置匹配 + // 1. 整体校验:模板与资源时令配置匹配 // ========================================== $this->validateTemplates($models); // ========================================== - // 【新增】2. 整体校验:资源时段冲突检测 + // 2. 整体校验:资源时段冲突检测 // ========================================== $this->checkResourceTimeConflict($models, $start_date, $end_date); - // ========================================== - // 【核心】3. 重复性检测 (在事务外执行,提高性能) - // ========================================== - $this->checkDuplicateRecords( - $department_id, - $planModelIds, - $start_date, - $end_date, - $models - ); - // 如果上面没抛异常,说明没有重复,继续往下执行 - - // 4. 获取节假日列表 + // 3. 获取节假日列表 $holiday_list = DB::table('s_holiday') ->whereBetween('date', $dateRange) ->where(['type' => 2]) ->pluck('date') ->toArray(); + $generatedDates = []; + $skippedDates = []; $success_count = 0; - // 5. 开启事务 + // 4. 开启事务 DB::beginTransaction(); try { $current_date = clone $start_date; @@ -85,12 +71,26 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1, // 如果是"仅节假日"模式 (date_type == 2),且当天不是节假日 -> 跳过 if ($dateType == 2 && !in_array($current_date_str, $holiday_list)) { + foreach ($models as $model) { + $skippedDates[] = [ + 'date' => $current_date_str, + 'template_id' => $model->id, + 'reason' => '非节假日,跳过', + ]; + } $current_date->modify('+1 day'); continue; } // 如果"节假日不可用" (HolidayEnable == 0),且当天是节假日 -> 跳过 if ($holidayEnable == 0 && in_array($current_date_str, $holiday_list)) { + foreach ($models as $model) { + $skippedDates[] = [ + 'date' => $current_date_str, + 'template_id' => $model->id, + 'reason' => '节假日不可用,跳过', + ]; + } $current_date->modify('+1 day'); continue; } @@ -108,10 +108,31 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1, } } - // 【新增】时令校验:跳过不在时令范围内的日期 + // 时令校验:跳过不在时令范围内的日期 $resource = $this->getCachedResource($model->resources_id); if (!$this->isDateInSeasonalRange($current_date, $model->type, $resource)) { - continue; // 跳过该模板在此日期的生成 + $skippedDates[] = [ + 'date' => $current_date_str, + 'template_id' => $model->id, + 'reason' => '不在时令范围', + ]; + continue; + } + + // 检查当天该模板是否已有号源明细(存在即跳过) + $exists = DB::table('s_source_roster_detail') + ->where('roster_id', $model->id) + ->where('date', $current_date_str) + ->where('is_del', 0) + ->exists(); + + if ($exists) { + $skippedDates[] = [ + 'date' => $current_date_str, + 'template_id' => $model->id, + 'reason' => '已存在', + ]; + continue; } // --- 构造插入数据 --- @@ -141,26 +162,36 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1, if (!$plan_id) { throw new Exception("号源明细插入失败,日期:{$current_date_str}, 模板ID:{$model->id}"); } + + $generatedDates[] = [ + 'date' => $current_date_str, + 'template_id' => $model->id, + 'detail_id' => $plan_id, + ]; $success_count++; // --- 插入关联表:数量配置 --- $this->insertCountInfo($plan_id, $model->id); // --- 插入关联表:设备配置 --- - // 注意:原逻辑如果 device_id 为空会报错,这里保持原逻辑 $this->insertDeviceInfo($plan_id, $model->device_id, $model->id); } $current_date->modify('+1 day'); } - // 6. 提交事务 + // 5. 提交事务 DB::commit(); - return ['success' => true, 'count' => $success_count]; + return [ + 'success' => true, + 'count' => $success_count, + 'generated_dates' => $generatedDates, + 'skipped_dates' => $skippedDates, + ]; } catch (Exception $e) { - // 7. 异常回滚 + // 6. 异常回滚 DB::rollBack(); // 记录日志 Log::error('Roster Generation Failed: ' . $e->getMessage(), [ @@ -326,58 +357,6 @@ private function getTemplateDate($model) return null; } - /** - * 独立的重复检测方法 - * 如果发现重复,直接抛出包含详细信息的异常 - */ - private function checkDuplicateRecords($department_id, $planModelIds, $startDate, $endDate, $models) - { - $startStr = $startDate->format('Y-m-d'); - $endStr = $endDate->format('Y-m-d'); - - // 查询已存在的记录 - $checkList = DB::table('s_source_roster_detail') - ->where('department_id', $department_id) - ->whereIn('roster_id', $planModelIds) - ->where('date', '>=', $startStr) - ->where('date', '<=', $endStr) - ->where('is_del', 0) - ->get(); - - if ($checkList->isNotEmpty()) { - // 构造详细的错误提示信息 (完全还原你原代码的逻辑) - $msg = '已有重复的计划明细,禁止创建!当前选中的'; - $msglist = ''; - $msgIds = ''; - - // 优化:将检查结果转为映射数组,避免双重循环 O(N*M) - // key: roster_id, value: array of items - $checkMap = []; - foreach ($checkList as $item) { - if (!isset($checkMap[$item->roster_id])) { - $checkMap[$item->roster_id] = []; - } - $checkMap[$item->roster_id][] = $item; - } - - foreach ($models as $model) { - if (isset($checkMap[$model->id])) { - foreach ($checkMap[$model->id] as $item) { - $msglist .= $item->date . ' '; - $msgIds .= $item->id . ' '; - // 拼接模板信息 - $msg .= "" . $model->weekname . $model->begin_time . '-' . $model->end_time . " "; - } - } - } - - $fullErrorMessage = $msg . '已存在相同记录,
存在于:
' . $msglist . '
对应记录Id为:' . $msgIds . '
请先删除后再操作'; - - // 抛出异常,中断流程 - throw new Exception($fullErrorMessage); - } - } - private function getWeekName($weekday) { $map = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; return $map[$weekday] ?? ''; @@ -429,4 +408,4 @@ private function insertDeviceInfo($detailId, $deviceIdStr, $modelId) { } } } -} +} \ No newline at end of file