Files
zyt/server/app/common/service/tcm/RevisitDueHook.php
T
2026-10-15 11:03:54 +08:00

144 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}