This commit is contained in:
gr
2026-10-15 11:03:54 +08:00
parent 70ddc1a70a
commit bb28d93cec
64 changed files with 12747 additions and 420 deletions
@@ -0,0 +1,167 @@
<?php
declare(strict_types=1);
namespace app\common\model\tcm;
use app\common\model\BaseModel;
/**
* 诊单复诊到期快照模型(每诊单一行,当前周期 = 最新有效业务订单)
*
* 写入方:RevisitDueService::refreshDiagnoses(cron / 钩子 / 列表自愈)与需求 4 的延迟/已联系/关闭接口。
* 时间相关状态(到期/预警/超期/过号/已约)不落列,由 RevisitDueCalculator::deriveState 按事实列 + today 推导。
*
* @package app\common\model\tcm
*/
class DiagnosisRevisitDue extends BaseModel
{
protected $name = 'tcm_diagnosis_revisit_due';
// 自动时间戳类型设置为整型(表无 delete_time 列)
protected $autoWriteTimestamp = true;
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
protected $deleteTime = false;
// 取出字段保持整型,前端按需要再格式化
protected $dateFormat = false;
/** 周期状态:进行中 */
public const CLOSED_OPEN = 0;
/** 周期状态:已挂号(自动关闭,待面诊) */
public const CLOSED_BOOKED = 2;
/** 周期状态:已面诊(自动关闭) */
public const CLOSED_VISITED = 3;
/** 周期状态:人工关闭 */
public const CLOSED_MANUAL = 4;
/** 周期状态:失效(无医助 / 诊单删除或禁用 / 无有效订单) */
public const CLOSED_INVALID = 5;
/** @var array<int,string> */
public const CLOSED_STATE_TEXT_MAP = [
self::CLOSED_OPEN => '进行中',
self::CLOSED_BOOKED => '已挂号',
self::CLOSED_VISITED => '已面诊',
self::CLOSED_MANUAL => '人工关闭',
self::CLOSED_INVALID => '失效',
];
/** 用药起算来源:无 */
public const ANCHOR_NONE = 0;
/** 用药起算来源:物流签收 */
public const ANCHOR_SIGN = 1;
/** 用药起算来源:人工发货日志 */
public const ANCHOR_SHIP = 2;
/** 用药起算来源:下单时间 */
public const ANCHOR_CREATE = 3;
/** @var array<int,string> */
public const ANCHOR_SRC_TEXT_MAP = [
self::ANCHOR_NONE => '',
self::ANCHOR_SIGN => '签收起',
self::ANCHOR_SHIP => '发货起',
self::ANCHOR_CREATE => '下单起',
];
/** 天数来源:缺失(或配置兜底) */
public const DAYS_SRC_NONE = 0;
/** 天数来源:订单 medication_days */
public const DAYS_SRC_ORDER = 1;
/** 天数来源:处方 usage_days */
public const DAYS_SRC_RX = 2;
/** @var array<int,string> */
public const DAYS_SRC_TEXT_MAP = [
self::DAYS_SRC_NONE => '缺开药天数',
self::DAYS_SRC_ORDER => '订单',
self::DAYS_SRC_RX => '处方',
];
/** 锚点订单之后最新有效挂号状态:无 */
public const APPT_NONE = 0;
/** 已约(doctor_appointment.status=1) */
public const APPT_BOOKED = 1;
/** 已面诊(status=3) */
public const APPT_VISITED = 3;
/** 已过号(status=4) */
public const APPT_MISSED = 4;
/** @var array<int,string> */
public const APPOINTMENT_STATE_TEXT_MAP = [
self::APPT_NONE => '未挂号',
self::APPT_BOOKED => '已约',
self::APPT_VISITED => '已面诊',
self::APPT_MISSED => '已过号',
];
/**
* @notes 周期状态文本
*/
public function getClosedStateTextAttr($value, $data): string
{
$v = (int) ($data['closed_state'] ?? 0);
return self::CLOSED_STATE_TEXT_MAP[$v] ?? '未知';
}
/**
* @notes 用药起算来源文本
*/
public function getAnchorSrcTextAttr($value, $data): string
{
$v = (int) ($data['anchor_src'] ?? 0);
return self::ANCHOR_SRC_TEXT_MAP[$v] ?? '';
}
/**
* @notes 开药天数来源文本
*/
public function getDaysSrcTextAttr($value, $data): string
{
$v = (int) ($data['days_src'] ?? 0);
return self::DAYS_SRC_TEXT_MAP[$v] ?? '';
}
/**
* @notes 挂号事实状态文本
*/
public function getAppointmentStateTextAttr($value, $data): string
{
$v = (int) ($data['appointment_state'] ?? 0);
return self::APPOINTMENT_STATE_TEXT_MAP[$v] ?? '未知';
}
/**
* @notes 最近重算时间格式化(Y-m-d H:i)
*/
public function getComputedAtTextAttr($value, $data): string
{
$ts = (int) ($data['computed_at'] ?? 0);
return $ts > 0 ? date('Y-m-d H:i', $ts) : '';
}
/**
* @notes 下次提醒时间格式化(Y-m-d H:i)
*/
public function getNextRemindAtTextAttr($value, $data): string
{
$ts = (int) ($data['next_remind_at'] ?? 0);
return $ts > 0 ? date('Y-m-d H:i', $ts) : '';
}
/**
* @notes 用药起算日(Y-m-d)
*/
public function getAnchorDateAttr($value, $data): string
{
$ts = (int) ($data['anchor_ts'] ?? 0);
return $ts > 0 ? date('Y-m-d', $ts) : '';
}
}
@@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
namespace app\common\model\tcm;
use app\common\model\BaseModel;
/**
* 诊单复诊到期事件流水模型(审计与「越点越上心」统计)
*
* 注意:弹窗轮询不写流水(只更新 first/last_shown_at),避免日志膨胀。
*
* @package app\common\model\tcm
*/
class DiagnosisRevisitDueLog extends BaseModel
{
protected $name = 'tcm_diagnosis_revisit_due_log';
// 仅有 create_time,整型时间戳
protected $autoWriteTimestamp = true;
protected $createTime = 'create_time';
protected $updateTime = false;
protected $deleteTime = false;
protected $dateFormat = false;
/** 事件:延迟 */
public const EVENT_SNOOZE = 1;
/** 事件:已联系(填承诺日) */
public const EVENT_CONTACT = 2;
/** 事件:人工关闭 */
public const EVENT_MANUAL_CLOSE = 3;
/** 事件:自动关闭-已挂号 */
public const EVENT_AUTO_CLOSE_BOOKED = 4;
/** 事件:自动关闭-已面诊 */
public const EVENT_AUTO_CLOSE_VISITED = 5;
/** 事件:周期重置(新有效订单成为锚点) */
public const EVENT_CYCLE_RESET = 6;
/** 事件:重新打开(挂号取消/过号) */
public const EVENT_REOPEN = 7;
/** 事件:企微推送 */
public const EVENT_WECOM_PUSH = 8;
/** 事件:医助变更(含继承),延迟字段清零 */
public const EVENT_ASSISTANT_CHANGED = 9;
/** 事件:形态升级(escalation_level 变化) */
public const EVENT_ESCALATED = 10;
/** 事件:首次弹出 */
public const EVENT_FIRST_SHOWN = 11;
/** @var array<int,string> */
public const EVENT_TEXT_MAP = [
self::EVENT_SNOOZE => '延迟',
self::EVENT_CONTACT => '已联系',
self::EVENT_MANUAL_CLOSE => '人工关闭',
self::EVENT_AUTO_CLOSE_BOOKED => '自动关闭-已挂号',
self::EVENT_AUTO_CLOSE_VISITED => '自动关闭-已面诊',
self::EVENT_CYCLE_RESET => '周期重置',
self::EVENT_REOPEN => '重新打开',
self::EVENT_WECOM_PUSH => '企微推送',
self::EVENT_ASSISTANT_CHANGED => '医助变更',
self::EVENT_ESCALATED => '形态升级',
self::EVENT_FIRST_SHOWN => '首次弹出',
];
/**
* @notes 事件文本
*/
public function getEventTextAttr($value, $data): string
{
$v = (int) ($data['event'] ?? 0);
return self::EVENT_TEXT_MAP[$v] ?? '未知';
}
/**
* @notes 事件时间格式化(Y-m-d H:i:s)
*/
public function getCreateTimeTextAttr($value, $data): string
{
$ts = (int) ($data['create_time'] ?? 0);
return $ts > 0 ? date('Y-m-d H:i:s', $ts) : '';
}
/**
* @notes payload JSON 解码为数组(解码失败返回空数组)
*
* @return array<string,mixed>
*/
public function getPayloadArrAttr($value, $data): array
{
$raw = (string) ($data['payload'] ?? '');
if ($raw === '') {
return [];
}
$decoded = json_decode($raw, true);
return is_array($decoded) ? $decoded : [];
}
}