144 lines
5.8 KiB
PHP
144 lines
5.8 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\common\service\tcm;
|
||
|
||
use think\facade\Db;
|
||
use think\facade\Log;
|
||
|
||
/**
|
||
* 复诊到期快照业务钩子(订单 / 挂号 / 指派 / 诊单变更 / 过号 cron)。
|
||
*
|
||
* 所有方法整体 try/catch 并 Log::warning,绝不向调用方抛异常、不改变主流程返回值;
|
||
* 任一钩子漏接由 30 分钟增量 cron(tcm:revisit-due-scan --mode=incremental)与列表自愈兜底。
|
||
*
|
||
* 接入点(由其它代理在业务 Logic 的事务提交之后调用):
|
||
* - PrescriptionOrderLogic create/editTime/withdraw/complete(9,10)/refund、GancaoCallbackController case 91/92 → onOrderChanged
|
||
* - AppointmentLogic create/cancel/complete/adminEdit → onAppointmentChanged
|
||
* - DiagnosisLogic::assign、AutoAssignPendingDiagnosis、AutoAssignLogLogic 回退 → onAssistantChanged
|
||
* - DiagnosisLogic::setRevisitSlotStartOffset 等诊单字段变更 → onDiagnosisChanged
|
||
* - UpdateAppointmentStatus 两条 Db::execute 之后 → onAppointmentStatusCronDone
|
||
*/
|
||
final class RevisitDueHook
|
||
{
|
||
/**
|
||
* 业务订单变化(新建 / 改下单时间 / 撤回 / 完成为 9,10 / 退款 / 甘草回调置 4)。
|
||
* diagnosisId 为 0 时按 orderId 反查诊单。
|
||
*/
|
||
public static function onOrderChanged(int $diagnosisId, int $orderId = 0, string $reason = ''): void
|
||
{
|
||
try {
|
||
if ($diagnosisId <= 0 && $orderId > 0) {
|
||
$diagnosisId = (int) Db::name('tcm_prescription_order')->where('id', $orderId)->value('diagnosis_id');
|
||
}
|
||
if ($diagnosisId <= 0) {
|
||
return;
|
||
}
|
||
RevisitDueService::refreshDiagnoses([$diagnosisId], [
|
||
'reason' => self::reasonTag('order', $reason),
|
||
'operator_id' => self::currentAdminId(),
|
||
]);
|
||
} catch (\Throwable $e) {
|
||
Log::warning(sprintf('复诊到期钩子 onOrderChanged 失败 diagnosis_id=%d order_id=%d: %s', $diagnosisId, $orderId, $e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 挂号变化(创建 / 取消 / 完成 / 后台编辑)。diagnosisId 为 0 时按 appointmentId 反查(patient_id 存诊单 id)。
|
||
*/
|
||
public static function onAppointmentChanged(int $diagnosisId, int $appointmentId = 0, string $reason = ''): void
|
||
{
|
||
try {
|
||
if ($diagnosisId <= 0 && $appointmentId > 0) {
|
||
$diagnosisId = (int) Db::name('doctor_appointment')->where('id', $appointmentId)->value('patient_id');
|
||
}
|
||
if ($diagnosisId <= 0) {
|
||
return;
|
||
}
|
||
RevisitDueService::refreshDiagnoses([$diagnosisId], [
|
||
'reason' => self::reasonTag('appointment', $reason),
|
||
'operator_id' => self::currentAdminId(),
|
||
]);
|
||
} catch (\Throwable $e) {
|
||
Log::warning(sprintf('复诊到期钩子 onAppointmentChanged 失败 diagnosis_id=%d appointment_id=%d: %s', $diagnosisId, $appointmentId, $e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 医助变更(指派 / 继承 / 释放 to=0 / 自动分配 / 回退)。toAssistantId 仅用于流水 payload,实际以库内 tcm_diagnosis.assistant_id 为准。
|
||
*/
|
||
public static function onAssistantChanged(int $diagnosisId, int $toAssistantId, string $reason = ''): void
|
||
{
|
||
try {
|
||
if ($diagnosisId <= 0) {
|
||
return;
|
||
}
|
||
$tag = self::reasonTag('assign', $reason);
|
||
if ($toAssistantId >= 0) {
|
||
$tag .= ':to=' . $toAssistantId;
|
||
}
|
||
RevisitDueService::refreshDiagnoses([$diagnosisId], [
|
||
'reason' => $tag,
|
||
'operator_id' => self::currentAdminId(),
|
||
]);
|
||
} catch (\Throwable $e) {
|
||
Log::warning(sprintf('复诊到期钩子 onAssistantChanged 失败 diagnosis_id=%d to=%d: %s', $diagnosisId, $toAssistantId, $e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 诊单其它字段变更(如 revisit_slot_start_offset、status 禁用/启用、软删)。
|
||
*/
|
||
public static function onDiagnosisChanged(int $diagnosisId, string $reason = ''): void
|
||
{
|
||
try {
|
||
if ($diagnosisId <= 0) {
|
||
return;
|
||
}
|
||
RevisitDueService::refreshDiagnoses([$diagnosisId], [
|
||
'reason' => self::reasonTag('diagnosis', $reason),
|
||
'operator_id' => self::currentAdminId(),
|
||
]);
|
||
} catch (\Throwable $e) {
|
||
Log::warning(sprintf('复诊到期钩子 onDiagnosisChanged 失败 diagnosis_id=%d: %s', $diagnosisId, $e->getMessage()));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 过号 cron(update_appointment_status)执行之后:重评 closed_state=2 / appointment_state=1 的行,使当天过号即进标红/弹窗。
|
||
*/
|
||
public static function onAppointmentStatusCronDone(): void
|
||
{
|
||
try {
|
||
RevisitDueService::reevaluateBookedRows();
|
||
} catch (\Throwable $e) {
|
||
Log::warning('复诊到期钩子 onAppointmentStatusCronDone 失败: ' . $e->getMessage());
|
||
}
|
||
}
|
||
|
||
/** 流水 payload 的 reason 标签:<来源>[:<说明>],限 64 字符 */
|
||
private static function reasonTag(string $source, string $reason): string
|
||
{
|
||
$reason = trim($reason);
|
||
|
||
return mb_substr($reason !== '' ? $source . ':' . $reason : $source, 0, 64);
|
||
}
|
||
|
||
/** 当前登录管理员 id(CLI / 回调无登录态时为 0),任何异常均视为 0 */
|
||
private static function currentAdminId(): int
|
||
{
|
||
try {
|
||
$req = request();
|
||
$admin = $req->adminInfo ?? null;
|
||
if (is_array($admin)) {
|
||
return (int) ($admin['admin_id'] ?? 0);
|
||
}
|
||
} catch (\Throwable $e) {
|
||
// CLI 场景无请求上下文,忽略
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
}
|