更新
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\common\enum\AppointmentTypeEnum;
|
||||
use app\common\model\doctor\Appointment;
|
||||
use RuntimeException;
|
||||
|
||||
/** 按本次挂号决定通话权限;Appointment.patient_id 存的是诊单 ID。 */
|
||||
class AppointmentCallPolicy
|
||||
{
|
||||
/** @return array{appointment_id:int,appointment_type:?string,appointment_type_desc:string,can_video_call:bool,can_audio_call:bool,call_disabled_reason:string} */
|
||||
public static function resolve(int $diagnosisId, int $appointmentId = 0): array
|
||||
{
|
||||
if ($diagnosisId <= 0) {
|
||||
throw new RuntimeException('诊单 ID 无效');
|
||||
}
|
||||
$appointments = Appointment::where('patient_id', $diagnosisId)
|
||||
->field(['id', 'appointment_type', 'status', 'appointment_date', 'appointment_time'])
|
||||
->select()->toArray();
|
||||
|
||||
return self::resolveFromAppointments($appointments, $appointmentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* $appointments 必须仅包含当前诊单的挂号;未知显式 ID 不可回退到其他挂号。
|
||||
*
|
||||
* @param list<array<string,mixed>> $appointments
|
||||
* @return array{appointment_id:int,appointment_type:?string,appointment_type_desc:string,can_video_call:bool,can_audio_call:bool,call_disabled_reason:string}
|
||||
*/
|
||||
public static function resolveFromAppointments(array $appointments, int $appointmentId = 0): array
|
||||
{
|
||||
if ($appointmentId !== 0) {
|
||||
foreach ($appointments as $appointment) {
|
||||
if ($appointmentId > 0 && (int) ($appointment['id'] ?? 0) === $appointmentId) {
|
||||
return self::policyForAppointment($appointment);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException('指定挂号不存在或不属于当前诊单');
|
||||
}
|
||||
|
||||
$active = array_values(array_filter($appointments, static fn (array $row): bool => (int) ($row['status'] ?? 0) === 1));
|
||||
if (count($active) === 1) {
|
||||
return self::policyForAppointment($active[0]);
|
||||
}
|
||||
if (count($active) > 1) {
|
||||
return array_replace(self::policyForAppointment(null), [
|
||||
'appointment_type_desc' => '待指定挂号',
|
||||
'call_disabled_reason' => '请指定本次挂号',
|
||||
]);
|
||||
}
|
||||
|
||||
$historical = array_values(array_filter($appointments, static fn (array $row): bool => in_array((int) ($row['status'] ?? 0), [3, 4], true)));
|
||||
usort($historical, static function (array $left, array $right): int {
|
||||
return [
|
||||
(string) ($right['appointment_date'] ?? ''),
|
||||
self::sortableTime($right['appointment_time'] ?? ''),
|
||||
(int) ($right['id'] ?? 0),
|
||||
] <=> [
|
||||
(string) ($left['appointment_date'] ?? ''),
|
||||
self::sortableTime($left['appointment_time'] ?? ''),
|
||||
(int) ($left['id'] ?? 0),
|
||||
];
|
||||
});
|
||||
|
||||
return self::policyForAppointment($historical[0] ?? null);
|
||||
}
|
||||
|
||||
/** @return array{appointment_id:int,appointment_type:?string,appointment_type_desc:string,can_video_call:bool,can_audio_call:bool,call_disabled_reason:string} */
|
||||
public static function policyForAppointment(?array $appointment): array
|
||||
{
|
||||
if ($appointment === null) {
|
||||
return [
|
||||
'appointment_id' => 0,
|
||||
'appointment_type' => null,
|
||||
'appointment_type_desc' => '未挂号',
|
||||
'can_video_call' => false,
|
||||
'can_audio_call' => false,
|
||||
'call_disabled_reason' => '未挂号,不能发起通话',
|
||||
];
|
||||
}
|
||||
|
||||
// 空类型仅对确实存在的历史挂号应用旧视频默认值。
|
||||
$type = AppointmentTypeEnum::normalizeStored($appointment['appointment_type'] ?? null);
|
||||
$status = (int) ($appointment['status'] ?? 0);
|
||||
$callableStatus = in_array($status, [1, 3, 4], true);
|
||||
$video = $callableStatus && $type === AppointmentTypeEnum::VIDEO;
|
||||
$audio = $callableStatus && in_array($type, [AppointmentTypeEnum::VIDEO, 'phone'], true);
|
||||
$reason = match (true) {
|
||||
$status === 2 => '本次挂号已取消,不能发起通话',
|
||||
!$callableStatus => '本次挂号状态不支持通话',
|
||||
$type === AppointmentTypeEnum::TEXT => '图文问诊不支持音视频通话',
|
||||
$type === 'phone' => '电话问诊仅支持语音通话',
|
||||
!$video && !$audio => '本次挂号问诊方式不支持音视频通话',
|
||||
default => '',
|
||||
};
|
||||
|
||||
return [
|
||||
'appointment_id' => (int) ($appointment['id'] ?? 0),
|
||||
'appointment_type' => $type,
|
||||
'appointment_type_desc' => AppointmentTypeEnum::description($type),
|
||||
'can_video_call' => $video,
|
||||
'can_audio_call' => $audio,
|
||||
'call_disabled_reason' => $reason,
|
||||
];
|
||||
}
|
||||
|
||||
private static function sortableTime($value): string
|
||||
{
|
||||
$time = (string) $value;
|
||||
if (preg_match('/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/', $time, $matches) === 1) {
|
||||
return sprintf('%02d:%02d:%02d', (int) $matches[1], (int) $matches[2], (int) ($matches[3] ?? 0));
|
||||
}
|
||||
|
||||
return $time;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user