This commit is contained in:
2026-05-05 16:16:55 +08:00
parent 19bfeef98f
commit 49d0fed14e
8 changed files with 241 additions and 139 deletions
@@ -138,6 +138,25 @@ class DiagnosisController extends BaseAdminController
return $this->data($result);
}
/**
* @notes 跟踪信息(血糖血压 / 饮食 / 运动)—— 按日期区间 lazy load
*
* 路由:GET /tcm.diagnosis/trackingWindow?id=:diagnosisId&start_date=&end_date=
* 权限:tcm.diagnosis/readonlyDetail(与只读病例页同档;接诊台亦复用)
*
* @return \think\response\Json
*/
public function trackingWindow()
{
$params = (new DiagnosisValidate())->goCheck('trackingWindow');
$result = DiagnosisLogic::fetchTrackingWindow(
(int) $params['id'],
(string) ($params['start_date'] ?? ''),
(string) ($params['end_date'] ?? '')
);
return $this->data($result);
}
/**
* @notes 诊单挂号 / 取消挂号 操作日志(谁在何时操作)
*/
@@ -516,10 +516,8 @@ class AppointmentLogic extends BaseLogic
? DiagnosisLogic::detail(['id' => $diagnosisId])
: [];
// 3) 血糖血压记录
$bloodRecords = $diagnosisId > 0
? BloodRecordLogic::getRecordsByPatient(['diagnosis_id' => $diagnosisId])
: [];
// 3) 跟踪信息(血糖血压 / 饮食 / 运动)改为前端按窗口 lazy load,
// 详见 DiagnosisController::trackingWindow。此处不再一次性返回。
// 4) 补全医助姓名(detail() 未关联 admin 助理表)
$assistantName = '';
@@ -554,7 +552,6 @@ class AppointmentLogic extends BaseLogic
return [
'appointment' => $appointment,
'diagnosis' => $diagnosis,
'blood_records' => $bloodRecords,
'doctor_notes' => $doctorNotes,
];
}
@@ -3397,14 +3397,8 @@ class DiagnosisLogic extends BaseLogic
// 3) 最近一条挂号(PatientInfoCard 显示用,无挂号则给默认空对象)
$appointment = self::buildLatestAppointmentForReadonly((int) ($diagnosis['id'] ?? $diagnosisId), $diagnosis);
// 4) 最近 30 天的跟踪记录(一次性 join 出三类,前端透视为矩阵)
$windowDays = 30;
$sinceTs = strtotime('-' . $windowDays . ' days');
$sinceTs = $sinceTs > 0 ? $sinceTs : 0;
$bloodRecords = self::fetchBloodRecordsForReadonly($diagnosisId, $sinceTs);
$dietRecords = self::fetchDietRecordsForReadonly($diagnosisId, $sinceTs);
$exerciseRecords = self::fetchExerciseRecordsForReadonly($diagnosisId, $sinceTs);
// 4) 跟踪信息(血糖血压 / 饮食 / 运动)改为前端按窗口 lazy load,
// 详见 DiagnosisController::trackingWindow。此处不再一次性返回。
// 5) 医生备注
$doctorNotes = DoctorNoteLogic::getByDiagnosis($diagnosisId);
@@ -3419,13 +3413,39 @@ class DiagnosisLogic extends BaseLogic
return [
'appointment' => $appointment,
'diagnosis' => $diagnosis,
'blood_records' => $bloodRecords,
'diet_records' => $dietRecords,
'exercise_records' => $exerciseRecords,
'doctor_notes' => $doctorNotes,
'unserved_days' => $unservedDays,
'last_blood_record_at' => $lastBloodRecordAt,
'window_days' => $windowDays,
];
}
/**
* 取指定日期区间内的三类跟踪记录(血糖血压 / 饮食 / 运动),供 readonlyDetail 与
* 医生接诊台 reception 通过独立接口 lazy load。
*
* 区间语义:闭区间 [startDate, endDate]Y-m-d),均不传则不限。
*
* @return array{
* blood_records: array<int,array<string,mixed>>,
* diet_records: array<int,array<string,mixed>>,
* exercise_records: array<int,array<string,mixed>>,
* start_date: string,
* end_date: string,
* }
*/
public static function fetchTrackingWindow(int $diagnosisId, string $startDate = '', string $endDate = ''): array
{
$sinceTs = $startDate !== '' ? (int) strtotime($startDate . ' 00:00:00') : 0;
$untilTs = $endDate !== '' ? (int) strtotime($endDate . ' 23:59:59') : 0;
$sinceTs = $sinceTs > 0 ? $sinceTs : 0;
$untilTs = $untilTs > 0 ? $untilTs : 0;
return [
'blood_records' => self::fetchBloodRecordsForReadonly($diagnosisId, $sinceTs, $untilTs),
'diet_records' => self::fetchDietRecordsForReadonly($diagnosisId, $sinceTs, $untilTs),
'exercise_records' => self::fetchExerciseRecordsForReadonly($diagnosisId, $sinceTs, $untilTs),
'start_date' => $startDate,
'end_date' => $endDate,
];
}
@@ -3502,12 +3522,15 @@ class DiagnosisLogic extends BaseLogic
/**
* @return array<int,array<string,mixed>>
*/
private static function fetchBloodRecordsForReadonly(int $diagnosisId, int $sinceTs): array
private static function fetchBloodRecordsForReadonly(int $diagnosisId, int $sinceTs, int $untilTs = 0): array
{
$query = BloodRecord::where('diagnosis_id', $diagnosisId);
if ($sinceTs > 0) {
$query->where('record_date', '>=', $sinceTs);
}
if ($untilTs > 0) {
$query->where('record_date', '<=', $untilTs);
}
$rows = $query->order('record_date', 'desc')
->order('record_time', 'desc')
->select()
@@ -3526,12 +3549,15 @@ class DiagnosisLogic extends BaseLogic
/**
* @return array<int,array<string,mixed>>
*/
private static function fetchDietRecordsForReadonly(int $diagnosisId, int $sinceTs): array
private static function fetchDietRecordsForReadonly(int $diagnosisId, int $sinceTs, int $untilTs = 0): array
{
$query = DietRecord::where('diagnosis_id', $diagnosisId);
if ($sinceTs > 0) {
$query->where('record_date', '>=', $sinceTs);
}
if ($untilTs > 0) {
$query->where('record_date', '<=', $untilTs);
}
$rows = $query->order('record_date', 'desc')->select()->toArray();
foreach ($rows as &$row) {
@@ -3546,12 +3572,15 @@ class DiagnosisLogic extends BaseLogic
/**
* @return array<int,array<string,mixed>>
*/
private static function fetchExerciseRecordsForReadonly(int $diagnosisId, int $sinceTs): array
private static function fetchExerciseRecordsForReadonly(int $diagnosisId, int $sinceTs, int $untilTs = 0): array
{
$query = ExerciseRecord::where('diagnosis_id', $diagnosisId);
if ($sinceTs > 0) {
$query->where('record_date', '>=', $sinceTs);
}
if ($untilTs > 0) {
$query->where('record_date', '<=', $untilTs);
}
$rows = $query->order('record_date', 'desc')
->append(['intensity_text'])
->select()
@@ -37,6 +37,8 @@ class DiagnosisValidate extends BaseValidate
'tongue_images' => 'array',
'report_files' => 'array',
'diabetes_discovery_year' => 'max:50',
'start_date' => 'date',
'end_date' => 'date|checkDateRange',
];
protected $message = [
@@ -55,6 +57,8 @@ class DiagnosisValidate extends BaseValidate
'status.in' => '状态参数错误',
'current_medications.max' => '在用药物最多2000个字符',
'diabetes_discovery_year.max' => '发现糖尿病患病史最多50个字符',
'start_date.date' => '开始日期格式不正确',
'end_date.date' => '结束日期格式不正确',
];
public function sceneAdd()
@@ -76,7 +80,12 @@ class DiagnosisValidate extends BaseValidate
{
return $this->only(['id']);
}
public function sceneTrackingWindow()
{
return $this->only(['id', 'start_date', 'end_date']);
}
public function sceneGenerateQrcode()
{
return $this->only(['diagnosis_id', 'doctor_id', 'patient_id', 'share_user_id', 'mini_program_path'])
@@ -112,6 +121,16 @@ class DiagnosisValidate extends BaseValidate
return true;
}
/** end_date 不能早于 start_date */
protected function checkDateRange($value, $rule, $data = [])
{
$start = $data['start_date'] ?? '';
if ($start && $value && strtotime($value) < strtotime($start)) {
return '结束日期不能早于开始日期';
}
return true;
}
/** 视频场景需 doctor_id,确认诊单需 diagnosis_id */
protected function checkQrcodeIds($value, $rule, $data = [])
{