From 29574ce5266edb1e09f141d80b71cb3be325ae93 Mon Sep 17 00:00:00 2001 From: sa0ChunLuyu Date: Sat, 1 Aug 2026 15:12:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E6=A0=A1=E6=AD=A3=E5=8F=B7?= =?UTF-8?q?=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../API/Admin/YeWu/PlanListController.php | 13 ++ .../Services/Admin/YeWu/PlanListService.php | 178 ++++++++++++++++++ .../migrations/create_s_dept_check_item.sql | 22 +++ Laravel/routes/api.php | 1 + 4 files changed, 214 insertions(+) create mode 100644 Laravel/database/migrations/create_s_dept_check_item.sql diff --git a/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php b/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php index 69afb93..8c7ecc3 100644 --- a/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php +++ b/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php @@ -1228,4 +1228,17 @@ public function BatchChangeLocked(Request $request) return \Yz::echoError1('批量占位失败'); } } + + //测试校正号源(只读,不更新数据库) + public function CorrectUsedCountTest(Request $request, PlanListService $planListService) + { + $rosterId = request('roster_id'); + $result = $planListService->calculateUsedCount($rosterId); + + // calculateUsedCount 返回数组(成功)或 Yz::echoError1 的响应 + if (is_array($result)) { + return \Yz::Return(true, '计算完成', $result); + } + return $result; + } } diff --git a/Laravel/app/Services/Admin/YeWu/PlanListService.php b/Laravel/app/Services/Admin/YeWu/PlanListService.php index 1da3d6b..ab4ee33 100644 --- a/Laravel/app/Services/Admin/YeWu/PlanListService.php +++ b/Laravel/app/Services/Admin/YeWu/PlanListService.php @@ -1873,6 +1873,184 @@ public function correctUsedCount($rosterId) ]); } + /** + * 测试校正号源:只读计算,不更新数据库 + * 返回当前排班号源占用详情与校正后应占数的对比 + */ + public function calculateUsedCount($rosterId) + { + if (!$rosterId) { + return \Yz::echoError1('参数错误:roster_id 不能为空'); + } + + // 排班基本信息 + $rosterInfo = DB::table('s_source_roster_detail') + ->leftJoin('s_department_resources', 's_source_roster_detail.resources_id', '=', 's_department_resources.id') + ->leftJoin('s_department', 's_source_roster_detail.department_id', '=', 's_department.id') + ->where('s_source_roster_detail.id', $rosterId) + ->select( + 's_source_roster_detail.*', + 's_department_resources.department_resources_name', + 's_department.department_name' + ) + ->first(); + + if (!$rosterInfo) { + return \Yz::echoError1('排班不存在'); + } + + // 渠道当前信息 + $channels = DB::table('s_source_roster_detail_count') + ->leftJoin('s_appointment_type', 's_source_roster_detail_count.appointment_type_id', '=', 's_appointment_type.id') + ->where('s_source_roster_detail_count.roster_detail_id', $rosterId) + ->select( + 's_source_roster_detail_count.*', + 's_appointment_type.name as appointment_type_name', + 's_appointment_type.jiancheng' + ) + ->get(); + + // 获取该排班上所有活跃项目及其配置 + $activeItems = DB::table('s_list') + ->join('s_check_item', 's_list.entrust_code', '=', 's_check_item.item_code') + ->where('s_list.roster_id', $rosterId) + ->whereIn('s_list.list_status', [1, 2, 3]) + ->where('s_list.is_nullify', 0) + ->where('s_check_item.status', 1) + ->where('s_check_item.is_del', 0) + ->select('s_list.*', 's_check_item.use_seats', 's_check_item.is_share_slot') + ->get(); + + // 按患者分组计算占位 + $grouped = []; + $firstDetail = null; + + foreach ($activeItems as $item) { + $reg = $item->reg_num; + if (!isset($grouped[$reg])) { + $grouped[$reg] = [ + 'sharedMax' => 0, + 'nonSharedSum' => 0, + 'items' => [], + ]; + } + + $seats = (int)($item->use_seats ?? 1); + if (!empty($item->is_share_slot)) { + $grouped[$reg]['sharedMax'] = max($grouped[$reg]['sharedMax'], $seats); + $grouped[$reg]['items'][] = [ + 'id' => $item->id, + 'entrust' => $item->entrust, + 'entrust_code' => $item->entrust_code, + 'list_status' => $item->list_status, + 'type' => '共享', + 'use_seats' => $seats, + ]; + } else { + $grouped[$reg]['nonSharedSum'] += $seats; + $grouped[$reg]['items'][] = [ + 'id' => $item->id, + 'entrust' => $item->entrust, + 'entrust_code' => $item->entrust_code, + 'list_status' => $item->list_status, + 'type' => '非共享', + 'use_seats' => $seats, + ]; + } + + // 记录第一个有 detail 的渠道 + if ($firstDetail === null) { + $details = json_decode($item->appointment_use_plan_detail, true) ?: []; + if (!empty($details)) { + $firstDetail = $details; + } + } + } + + // 计算总占位 + $patientOccupancy = []; + $totalUsed = 0; + foreach ($grouped as $reg => $g) { + $patientTotal = $g['sharedMax'] + $g['nonSharedSum']; + $totalUsed += $patientTotal; + $patientOccupancy[] = [ + 'reg_num' => $reg, + 'shared_max' => $g['sharedMax'], + 'non_shared_sum' => $g['nonSharedSum'], + 'patient_total' => $patientTotal, + 'items' => $g['items'], + ]; + } + + // 按渠道分配计算 + $channelCalculated = []; + $hasDiff = false; + if ($firstDetail && $totalUsed > 0) { + $totalDetailCount = array_sum(array_column($firstDetail, 'count')); + foreach ($firstDetail as $d) { + $cid = $d['roster_detail_count_id'] ?? null; + if (!$cid) continue; + $ratio = $totalDetailCount > 0 ? ($d['count'] / $totalDetailCount) : 0; + $channelUsed = (int)round($totalUsed * $ratio); + + $current = $channels->firstWhere('id', $cid); + $currentUsed = $current ? (int)$current->used_count : 0; + $diff = $channelUsed - $currentUsed; + + $channelCalculated[] = [ + 'id' => $cid, + 'appointment_type_id' => $current->appointment_type_id ?? null, + 'appointment_type_name' => $current->appointment_type_name ?? null, + 'count' => $current ? (int)$current->count : 0, + 'current_used_count' => $currentUsed, + 'calculated_used_count' => $channelUsed, + 'locked_count' => $current ? (int)$current->locked_count : 0, + 'diff' => $diff, + ]; + if ($diff !== 0) { + $hasDiff = true; + } + } + } else { + // 无 detail 时,各渠道直接取 totalUsed + foreach ($channels as $ch) { + $currentUsed = (int)$ch->used_count; + $diff = $totalUsed - $currentUsed; + $channelCalculated[] = [ + 'id' => $ch->id, + 'appointment_type_id' => $ch->appointment_type_id, + 'appointment_type_name' => $ch->appointment_type_name, + 'count' => (int)$ch->count, + 'current_used_count' => $currentUsed, + 'calculated_used_count' => $totalUsed, + 'locked_count' => (int)$ch->locked_count, + 'diff' => $diff, + ]; + if ($diff !== 0) { + $hasDiff = true; + } + } + } + + return [ + 'roster_id' => (int)$rosterId, + 'roster_info' => [ + 'date' => $rosterInfo->date, + 'begin_time' => $rosterInfo->begin_time, + 'end_time' => $rosterInfo->end_time, + 'weekname' => $rosterInfo->weekname, + 'patient_type' => $rosterInfo->patient_type, + 'department_name' => $rosterInfo->department_name, + 'resources_name' => $rosterInfo->department_resources_name, + ], + 'active_item_count' => $activeItems->count(), + 'patient_occupancy' => $patientOccupancy, + 'total_used' => $totalUsed, + 'channels' => $channelCalculated, + 'has_diff' => $hasDiff, + ]; + } + /** * 预约完成后通知 HIS 回写执行科室 * 在事务提交后调用,异常不影响主流程 diff --git a/Laravel/database/migrations/create_s_dept_check_item.sql b/Laravel/database/migrations/create_s_dept_check_item.sql new file mode 100644 index 0000000..4bdc00d --- /dev/null +++ b/Laravel/database/migrations/create_s_dept_check_item.sql @@ -0,0 +1,22 @@ +-- 科室检查项目配置表 +-- 覆盖表模式:存储科室级别的检查项目个性化配置,查询时 LEFT JOIN s_check_item 用 COALESCE 取值 +-- 一个检查项目在一个科室只存一条覆盖记录 + +CREATE TABLE `s_dept_check_item` ( + `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', + `check_item_id` int(10) UNSIGNED NOT NULL COMMENT '关联 s_check_item.id', + `department_id` int(10) UNSIGNED NOT NULL COMMENT '关联 s_department.id,当前科室', + `reservation_method` varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '预约方式,逗号分隔的ID串', + `limosis` tinyint(4) NULL DEFAULT NULL COMMENT '是否空腹 1是 0否', + `check_time` int(11) NULL DEFAULT NULL COMMENT '检查时长,单位分钟', + `check_begin_time` int(11) NULL DEFAULT NULL COMMENT '医嘱开具后等待时间,单位分钟', + `check_notice` varchar(8000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '检查须知', + `warm_tips` varchar(8000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '温馨提示', + `use_seats` int(10) NULL DEFAULT 1 COMMENT '占用号源数,默认1', + `is_share_slot` tinyint(1) NULL DEFAULT 0 COMMENT '是否共享号源 0否 1是', + `created_at` timestamp(0) NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '创建时间', + `updated_at` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE KEY `uk_check_item_dept` (`check_item_id`, `department_id`) USING BTREE, + INDEX `idx_department_id` (`department_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '科室检查项目配置表' ROW_FORMAT = Dynamic; diff --git a/Laravel/routes/api.php b/Laravel/routes/api.php index df38366..bce9a3c 100644 --- a/Laravel/routes/api.php +++ b/Laravel/routes/api.php @@ -143,6 +143,7 @@ Route::post('admin/PlanListBatchChangeCount','App\Http\Controllers\API\Admin\YeWu\PlanListController@BatchChangeCount');//批量修改号源数量(不修改占位) Route::post('admin/PlanListBatchChangeLocked','App\Http\Controllers\API\Admin\YeWu\PlanListController@BatchChangeLocked');//批量修改号源占位(不修改数量) Route::post('admin/SaveLockedCount','App\Http\Controllers\API\Admin\YeWu\PlanListController@SaveLockedCount');//保存占位数量 + Route::post('admin/PlanListCorrectUsedCountTest','App\Http\Controllers\API\Admin\YeWu\PlanListController@CorrectUsedCountTest');//测试校正号源(只读) Route::post('admin/GetMainList','App\Http\Controllers\API\Admin\YeWu\WorkMainController@GetList');//获取主表列表 Route::post('admin/GetMainListByDept','App\Http\Controllers\API\Admin\YeWu\WorkMainController@GetListByDept');//管理员获取主表列表(支持科室切换) Route::post('admin/GetLoglist','App\Http\Controllers\API\Admin\YeWu\WorkMainController@GetLoglist');//获取日志