diff --git a/Laravel/app/Http/Controllers/API/Admin/YeWu/WorkMainController.php b/Laravel/app/Http/Controllers/API/Admin/YeWu/WorkMainController.php index 915a3f7..22b9a4a 100644 --- a/Laravel/app/Http/Controllers/API/Admin/YeWu/WorkMainController.php +++ b/Laravel/app/Http/Controllers/API/Admin/YeWu/WorkMainController.php @@ -382,5 +382,117 @@ class WorkMainController extends Controller 'AppointmentCount' => $appointmentCount ]); } + //统计 + public function AllCountTongJi() + { + $searchInfo = request('searchInfo'); + // 基础查询 + $baseQuery = DB::table('s_list') + ->whereIn('list_status',[1,2,3])//0未预约 1预约 2预约后已经登记 3取消 + ->where(['s_list.is_del' => 0, 's_list.is_nullify' => 0]); + + // 日期范围条件(如果有) + if (isset($searchInfo['dateRange']) && !empty($searchInfo['dateRange'])) { + $startDate = $searchInfo['dateRange'][0] . ' 00:00:00'; + $endDate = $searchInfo['dateRange'][1] . ' 23:59:59'; + $baseQuery->whereBetween('s_list.reservation_date', [$startDate, $endDate]); + } + //执行科室分布统计 + $departmentCount = clone $baseQuery; + $departmentCount = $departmentCount + ->select('s_department.department_name', DB::raw('count(*) as count')) + ->leftJoin('s_department', 's_list.RISRAcceptDeptCode', '=', 's_department.department_number') + ->groupBy('s_department.department_name') + ->get(); + //根据检查项目分类 统计 + // 检查项目分类统计:克隆基础查询 + $checkItemTypeCount = clone $baseQuery; + $checkItemTypeCount = $checkItemTypeCount + ->join('s_check_item', 's_list.entrust_code', '=', 's_check_item.item_code') + ->join('s_check_item_class', 's_check_item.item_class_id', '=', 's_check_item_class.id') + ->select('s_check_item_class.id as class_id', 's_check_item_class.item_class_name as class_name', DB::raw('COUNT(*) as count')) + ->groupBy('s_check_item_class.id', 's_check_item_class.item_class_name') + ->get(); + //时段统计 + //分时间段统计 预约数量 预约率 空闲数量 空闲率 爽约数量 爽约率 (爽约判断状态为1,且超过预约时间) + //s_list 里的roster_id 关联s_source_roster_detail里的id,s_source_roster_detail_count里的roster_detail_id是s_source_roster_detail的id, + //s_source_roster_detail_count里的max_total是该时间段最大预约人数,appointment_type_id是预约类型id,count是各个类型的最大可预约人数,used_count是各个类型已预约人数 +// ===== 时段统计:按小时,包含空闲,正确处理 max_total 和 appointment_count ===== + +// 步骤1:对 s_source_roster_detail_count 按 roster_detail_id 去重(取任意一条 max_total) + $uniqueCapacity = DB::table('s_source_roster_detail_count') + ->select( + 'roster_detail_id', + DB::raw('MAX(max_total) as total_max_capacity') // 所有行值相同,MAX 即可 + ) + ->groupBy('roster_detail_id'); + +// 步骤2:主查询 + $hourlyStats = DB::table('s_source_roster_detail as rd') + ->joinSub($uniqueCapacity, 'capacity', function ($join) { + $join->on('rd.id', '=', 'capacity.roster_detail_id'); + }) + ->leftJoin('s_list', function ($join) use ($searchInfo) { + $join->on('s_list.roster_id', '=', 'rd.id') + ->where('s_list.is_del', '=', 0) + ->where('s_list.is_nullify', '=', 0) + ->whereIn('s_list.list_status', [1, 2, 3]); + + // 限制 s_list 的预约日期范围 + if (isset($searchInfo['dateRange']) && !empty($searchInfo['dateRange'])) { + $startDateTime = $searchInfo['dateRange'][0] . ' 00:00:00'; + $endDateTime = $searchInfo['dateRange'][1] . ' 23:59:59'; + $join->whereBetween('s_list.reservation_date', [$startDateTime, $endDateTime]); + } + }); + +// 筛选排班日期(基于 rd.date) + if (isset($searchInfo['dateRange']) && !empty($searchInfo['dateRange'])) { + $startDate = $searchInfo['dateRange'][0]; + $endDate = $searchInfo['dateRange'][1]; + $hourlyStats->whereBetween('rd.date', [$startDate, $endDate]); + } + +// 按小时分组统计 + $hourlyStats = $hourlyStats + ->select( + DB::raw('HOUR(rd.begin_time) as hour_start'), + DB::raw('COUNT(s_list.id) as appointment_count'), + DB::raw('SUM(CASE WHEN s_list.list_status = 1 AND s_list.reservation_date < NOW() THEN 1 ELSE 0 END) as no_show_count'), + DB::raw('SUM(capacity.total_max_capacity) as total_max_capacity') + ) + ->groupBy(DB::raw('HOUR(rd.begin_time)')) + ->orderBy(DB::raw('HOUR(rd.begin_time)')) + ->get(); + +// 步骤3:构建最终结果数组 + $finalTimeSlotStats = []; + foreach ($hourlyStats as $stat) { + $hour = (int)$stat->hour_start; + $appointmentCount = (int)$stat->appointment_count; + $noShowCount = (int)$stat->no_show_count; + $maxTotal = (int)$stat->total_max_capacity; + + // 防止除零 + $appointmentRate = $maxTotal > 0 ? round($appointmentCount / $maxTotal, 2) : 0; + $idleCount = max(0, $maxTotal - $appointmentCount); + $idleRate = $maxTotal > 0 ? round($idleCount / $maxTotal, 2) : 0; + $noShowRate = $appointmentCount > 0 ? round($noShowCount / $appointmentCount, 2) : 0; + + $finalTimeSlotStats[] = [ + 'hour' => $hour, + 'time_slot' => sprintf('%02d:00-%02d:00', $hour, $hour + 1), + 'appointment_count' => $appointmentCount, + 'appointment_rate' => $appointmentRate, + 'idle_count' => $idleCount, + 'idle_rate' => $idleRate, + 'no_show_count' => $noShowCount, + 'no_show_rate' => $noShowRate, + 'max_total' => $maxTotal, + ]; + } + + return \Yz::Return(true, '查询成功', ['department_count' => $departmentCount, 'check_item_type_count' => $checkItemTypeCount, 'time_slot_stats' => $finalTimeSlotStats]); + } } diff --git a/Laravel/routes/api.php b/Laravel/routes/api.php index 8c9c620..c87024c 100644 --- a/Laravel/routes/api.php +++ b/Laravel/routes/api.php @@ -104,6 +104,7 @@ Route::group(['middleware'=>['checktoken','log'],'prefix'=>'v1'],function () { Route::post('admin/PlanTongJi','App\Http\Controllers\API\Admin\YeWu\PlanListController@TongJi');//计划统计 Route::post('admin/BlackListGetList','App\Http\Controllers\API\Admin\YeWu\BlackListController@GetList'); Route::post('admin/BlackListDelete','App\Http\Controllers\API\Admin\YeWu\BlackListController@Delete'); + Route::post('admin/AllCountTongJi','App\Http\Controllers\API\Admin\YeWu\WorkMainController@AllCountTongJi'); }); //暂时不加权限 diff --git a/YiJi-admin/src/api/api.js b/YiJi-admin/src/api/api.js index f0d54ea..fe7e762 100644 --- a/YiJi-admin/src/api/api.js +++ b/YiJi-admin/src/api/api.js @@ -369,4 +369,7 @@ export const adminBlackListDelete = (data = {}) => { export const adminBlackListGetList = (data = {}) => { return axios({ url: import.meta.env.VITE_APP_API + 'v1/admin/BlackListGetList', data: data }) +} +export const AdminAllCountTongJi = (data = {}) => { + return axios({ url: import.meta.env.VITE_APP_API + 'v1/admin/AllCountTongJi', data: data }) } \ No newline at end of file diff --git a/YiJi-admin/src/views/YeWu/baobiao_yanshi.vue b/YiJi-admin/src/views/YeWu/baobiao_yanshi.vue index fb00847..c7038cb 100644 --- a/YiJi-admin/src/views/YeWu/baobiao_yanshi.vue +++ b/YiJi-admin/src/views/YeWu/baobiao_yanshi.vue @@ -1,5 +1,5 @@