adminId)->column('role_id'); // 处理患者姓名搜索 if (!empty($this->params['patient_name'])) { $this->searchWhere[] = ['u.patient_name', 'like', '%' . $this->params['patient_name'] . '%']; } // 处理医生姓名搜索 if (!empty($this->params['doctor_name'])) { $this->searchWhere[] = ['ad.name', 'like', '%' . $this->params['doctor_name'] . '%']; } // 处理状态搜索 if (isset($this->params['status']) && $this->params['status'] !== '') { $this->searchWhere[] = ['a.status', '=', $this->params['status']]; } // 处理日期范围搜索 if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) { $this->searchWhere[] = ['a.appointment_date', 'between', [$this->params['start_date'], $this->params['end_date']]]; } elseif (!empty($this->params['start_date'])) { $this->searchWhere[] = ['a.appointment_date', '>=', $this->params['start_date']]; } elseif (!empty($this->params['end_date'])) { $this->searchWhere[] = ['a.appointment_date', '<=', $this->params['end_date']]; } // 诊单维度患者(挂号表 patient_id 存诊单 id) if (!empty($this->params['patient_id'])) { $this->searchWhere[] = ['a.patient_id', '=', (int) $this->params['patient_id']]; } // 按接诊医生筛选(管理端医生进度看板等) if (!empty($this->params['doctor_id'])) { $this->searchWhere[] = ['a.doctor_id', '=', (int) $this->params['doctor_id']]; } // 排除已取消挂号 status=2(医生进度看板等;未显式筛选「已取消」时生效) if ((int) ($this->params['exclude_cancelled'] ?? 0) === 1) { $sf = $this->params['status'] ?? ''; if ($sf === '' || (int) $sf !== 2) { $this->searchWhere[] = ['a.status', '<>', 2]; } } // 构建查询(searchWhere 为空时避免部分环境下 where([]) 异常) $query = Appointment::alias('a') ->with('diagnosis') ->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id') ->leftJoin('admin ad', 'a.doctor_id = ad.id') ->leftJoin('admin asst', 'u.assistant_id = asst.id') ->field('a.*, u.patient_name as patient_name, u.phone as patient_phone, u.gender as gender, u.age as age, u.weight as weight, u.height as height, u.assistant_id as assistant_id, ad.name as doctor_name, asst.name as assistant_name, u.id as diagnosis_id'); if ($this->searchWhere !== []) { $query->where($this->searchWhere); } // 是否确认诊单:1=已确认 0=未确认 if (isset($this->params['diagnosis_confirmed']) && $this->params['diagnosis_confirmed'] !== '') { $confirmed = (int)$this->params['diagnosis_confirmed']; $tbl = (new DiagnosisViewRecord())->getTable(); $subSql = "SELECT 1 FROM {$tbl} dvr WHERE dvr.diagnosis_id = u.id AND dvr.is_confirmed = 1 AND dvr.delete_time IS NULL"; if ($confirmed === 1) { $query->whereExists($subSql); } else { $query->whereNotExists($subSql); } } // 面诊进度看板:可切换查看各医生挂号,不按当前账号角色收窄 $progressBoard = (int) ($this->params['progress_board'] ?? 0) === 1; if (!$progressBoard) { // 如果是医生角色(role_id=1),只显示挂自己号的预约 if (in_array(1, $roleIds)) { $query->where('a.doctor_id', $this->adminId); } // 如果是医助角色(role_id=2),只显示自己添加的患者的预约 if (in_array(2, $roleIds)) { $query->where('u.assistant_id', $this->adminId); } } // 诊单软删除后不再展示对应挂号(leftJoin 时无诊单或诊单未删) $query->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)'); $lists = $query ->order('a.status', 'asc') ->order('a.appointment_date', 'asc') ->order('a.appointment_time', 'asc') ->limit($this->limitOffset, $this->limitLength) ->select() ->toArray(); // 添加状态、类型描述及确认诊单状态 $diagnosisIds = array_filter(array_unique(array_column($lists, 'diagnosis_id'))); $confirmedMap = []; if (!empty($diagnosisIds)) { $confirmedIds = \think\facade\Db::name('diagnosis_view_records') ->whereIn('diagnosis_id', $diagnosisIds) ->where('is_confirmed', 1) ->whereNull('delete_time') ->column('diagnosis_id'); $confirmedMap = array_flip($confirmedIds ?: []); } // 开方状态:诊单是否有处方(按 diagnosis_id 查) // prescription_today_only=1:仅统计「今日创建」的处方(医生进度看板用,与历史处方区分) $rxTodayOnly = (int) ($this->params['prescription_today_only'] ?? 0) === 1; $prescribedDiagnosisIds = []; if (!empty($diagnosisIds)) { $rxQ = Prescription::whereIn('diagnosis_id', $diagnosisIds) ->whereNull('delete_time') ->where('void_status', 0); if ($rxTodayOnly) { $dayStart = strtotime(date('Y-m-d 00:00:00')); $dayEnd = strtotime(date('Y-m-d 23:59:59')); $rxQ->whereBetween('create_time', [$dayStart, $dayEnd]); } $prescribedDiagnosisIds = $rxQ->column('diagnosis_id'); $prescribedDiagnosisIds = array_flip($prescribedDiagnosisIds ?: []); } // 当前页预约关联的处方(按 appointment_id,取最新一条):用于「开方/查看」与审核状态 $appointmentIds = array_filter(array_map('intval', array_column($lists, 'id'))); $rxByAppointmentId = []; if (!empty($appointmentIds)) { $rxRows = Prescription::whereIn('appointment_id', $appointmentIds) ->whereNull('delete_time') ->where('void_status', 0) ->order('id', 'desc') ->field(['id', 'appointment_id', 'audit_status', 'void_status', 'is_system_auto']) ->select() ->toArray(); foreach ($rxRows as $rx) { $aid = (int) ($rx['appointment_id'] ?? 0); if ($aid > 0 && !isset($rxByAppointmentId[$aid])) { $rxByAppointmentId[$aid] = $rx; } } } foreach ($lists as &$item) { $statusMap = [ 1 => '已预约', 2 => '已取消', 3 => '已完成', 4 => '已过号', ]; $item['status_desc'] = $statusMap[$item['status']] ?? '未知'; $typeMap = [ 'video' => '视频问诊', 'text' => '图文问诊', 'phone' => '电话问诊', ]; $item['appointment_type_desc'] = $typeMap[$item['appointment_type']] ?? '未知'; $item['diagnosis_confirmed'] = isset($confirmedMap[$item['diagnosis_id'] ?? 0]) ? 1 : 0; $item['has_prescription'] = isset($prescribedDiagnosisIds[$item['diagnosis_id'] ?? 0]) ? 1 : 0; $apptId = (int) ($item['id'] ?? 0); $apptRx = $rxByAppointmentId[$apptId] ?? null; $item['prescription_audit_status'] = $apptRx !== null ? (int) ($apptRx['audit_status'] ?? -1) : -1; $item['prescription_void_status'] = $apptRx !== null ? (int) ($apptRx['void_status'] ?? 0) : 0; $item['prescription_is_system_auto'] = $apptRx !== null ? (int) ($apptRx['is_system_auto'] ?? 0) : 0; // 格式化时间戳为日期时间 if (isset($item['create_time']) && is_numeric($item['create_time'])) { $item['create_time'] = date('Y-m-d H:i:s', $item['create_time']); } if (isset($item['update_time']) && is_numeric($item['update_time'])) { $item['update_time'] = date('Y-m-d H:i:s', $item['update_time']); } } return $lists; } /** * 列表 count / Tab 角标统计共用的过滤条件(不依赖 lists() 对 searchWhere 的副作用) * @param mixed $query * @param bool $applyStatusFilter 为 false 时按状态分组统计各 Tab 数量 */ private function applyAppointmentCountFilters($query, bool $applyStatusFilter): void { $roleIds = AdminRole::where('admin_id', $this->adminId)->column('role_id'); if (!empty($this->params['patient_name'])) { $query->where('u.patient_name', 'like', '%' . $this->params['patient_name'] . '%'); } if (!empty($this->params['doctor_name'])) { $query->where('ad.name', 'like', '%' . $this->params['doctor_name'] . '%'); } if ($applyStatusFilter && isset($this->params['status']) && $this->params['status'] !== '') { $query->where('a.status', '=', $this->params['status']); } if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) { $query->whereBetween('a.appointment_date', [$this->params['start_date'], $this->params['end_date']]); } elseif (!empty($this->params['start_date'])) { $query->where('a.appointment_date', '>=', $this->params['start_date']); } elseif (!empty($this->params['end_date'])) { $query->where('a.appointment_date', '<=', $this->params['end_date']); } if (!empty($this->params['patient_id'])) { $query->where('a.patient_id', '=', (int) $this->params['patient_id']); } if (!empty($this->params['doctor_id'])) { $query->where('a.doctor_id', '=', (int) $this->params['doctor_id']); } if ((int) ($this->params['exclude_cancelled'] ?? 0) === 1) { $sf = $this->params['status'] ?? ''; if ($sf === '' || (int) $sf !== 2) { $query->where('a.status', '<>', 2); } } if (isset($this->params['diagnosis_confirmed']) && $this->params['diagnosis_confirmed'] !== '') { $confirmed = (int)$this->params['diagnosis_confirmed']; $tbl = (new DiagnosisViewRecord())->getTable(); $subSql = "SELECT 1 FROM {$tbl} dvr WHERE dvr.diagnosis_id = u.id AND dvr.is_confirmed = 1 AND dvr.delete_time IS NULL"; if ($confirmed === 1) { $query->whereExists($subSql); } else { $query->whereNotExists($subSql); } } $progressBoard = (int) ($this->params['progress_board'] ?? 0) === 1; if (!$progressBoard) { if (in_array(1, $roleIds)) { $query->where('a.doctor_id', $this->adminId); } if (in_array(2, $roleIds)) { $query->where('u.assistant_id', $this->adminId); } } $query->whereRaw('(u.id IS NULL OR u.delete_time IS NULL)'); } /** * @notes 获取数量 * @return int */ public function count(): int { $query = Appointment::alias('a') ->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id') ->leftJoin('admin ad', 'a.doctor_id = ad.id'); $this->applyAppointmentCountFilters($query, true); return (int)$query->count(); } /** * @notes 扩展字段:按需返回各状态数量(一次 GROUP BY,替代前端 4 次列表请求) * @return array */ public function extend(): array { if (empty($this->params['include_status_counts'])) { return []; } $query = Appointment::alias('a') ->leftJoin('tcm_diagnosis u', 'a.patient_id = u.id') ->leftJoin('admin ad', 'a.doctor_id = ad.id'); $this->applyAppointmentCountFilters($query, false); $rows = $query->field('a.status, COUNT(*) AS cnt') ->group('a.status') ->select() ->toArray(); $out = [1 => 0, 2 => 0, 3 => 0, 4 => 0]; foreach ($rows as $r) { $s = (int)($r['status'] ?? 0); if (array_key_exists($s, $out)) { $out[$s] = (int)($r['cnt'] ?? 0); } } return ['status_count' => $out]; } }