|
|
|
|
@ -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]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|