更新功能
This commit is contained in:
@@ -15,7 +15,10 @@
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\adminapi\logic\tcm\DiagnosisLogic;
|
||||
use app\adminapi\logic\tcm\TrackingNoteLogic;
|
||||
use app\adminapi\logic\ConfigLogic;
|
||||
use app\common\model\tcm\Diagnosis;
|
||||
use app\common\model\tcm\BloodRecord;
|
||||
|
||||
/**
|
||||
* 中医诊断控制器(供小程序调用)
|
||||
@@ -28,7 +31,7 @@ class TcmController extends BaseApiController
|
||||
* @notes 不需要登录的方法
|
||||
* @var array
|
||||
*/
|
||||
public array $notNeedLogin = ['getPatientSignature', 'diagnosisDetail', 'getDict', 'confirmDiagnosis', 'getCardList', 'getOrderByNo', 'patientHangupVideo'];
|
||||
public array $notNeedLogin = ['getPatientSignature', 'diagnosisDetail', 'getDict', 'confirmDiagnosis', 'getCardList', 'getOrderByNo', 'patientHangupVideo', 'dailyTrackingWindow', 'dailyTrackingNotes'];
|
||||
|
||||
/**
|
||||
* @notes 获取患者签名(供小程序调用)
|
||||
@@ -332,6 +335,301 @@ class TcmController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 日常记录窗口数据(血糖血压 / 饮食 / 运动)—— 患者端
|
||||
*
|
||||
* 路由:GET /api/tcm/dailyTrackingWindow?diagnosis_id=:id&patient_id=:pid&start_date=&end_date=
|
||||
* 说明:供小程序「日常记录」页面拉取一段时间内的跟踪数据,复用后台 fetchTrackingWindow。
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function dailyTrackingWindow()
|
||||
{
|
||||
$diagnosisId = (int) $this->request->get('diagnosis_id', 0);
|
||||
$patientId = (int) $this->request->get('patient_id', 0);
|
||||
$startDate = (string) $this->request->get('start_date', '');
|
||||
$endDate = (string) $this->request->get('end_date', '');
|
||||
|
||||
if ($diagnosisId <= 0) {
|
||||
return $this->fail('诊单ID不能为空');
|
||||
}
|
||||
|
||||
try {
|
||||
// 患者端越权校验:诊单必须存在;如传入 patient_id 则须与诊单匹配
|
||||
$diagnosis = Diagnosis::where('id', $diagnosisId)->find();
|
||||
if (!$diagnosis) {
|
||||
return $this->fail('诊单不存在');
|
||||
}
|
||||
if ($patientId > 0 && (int) $diagnosis['patient_id'] !== $patientId) {
|
||||
return $this->fail('无权查看该诊单的日常记录');
|
||||
}
|
||||
|
||||
$data = DiagnosisLogic::fetchTrackingWindow($diagnosisId, $startDate, $endDate);
|
||||
|
||||
// 把诊断的基础信息一并返回,便于小程序展示头部摘要
|
||||
$data['diagnosis'] = [
|
||||
'id' => (int) $diagnosis['id'],
|
||||
'patient_id' => (int) $diagnosis['patient_id'],
|
||||
'patient_name' => (string) ($diagnosis['patient_name'] ?? ''),
|
||||
'age' => (int) ($diagnosis['age'] ?? 0),
|
||||
'gender' => (int) ($diagnosis['gender'] ?? 0),
|
||||
];
|
||||
|
||||
return $this->data($data);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 日常记录-跟踪备注列表(患者端)
|
||||
*
|
||||
* 路由:GET /api/tcm/dailyTrackingNotes?diagnosis_id=:id&patient_id=:pid
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function dailyTrackingNotes()
|
||||
{
|
||||
$diagnosisId = (int) $this->request->get('diagnosis_id', 0);
|
||||
$patientId = (int) $this->request->get('patient_id', 0);
|
||||
|
||||
if ($diagnosisId <= 0) {
|
||||
return $this->fail('诊单ID不能为空');
|
||||
}
|
||||
|
||||
try {
|
||||
$diagnosis = Diagnosis::where('id', $diagnosisId)->find();
|
||||
if (!$diagnosis) {
|
||||
return $this->fail('诊单不存在');
|
||||
}
|
||||
if ($patientId > 0 && (int) $diagnosis['patient_id'] !== $patientId) {
|
||||
return $this->fail('无权查看该诊单的跟踪备注');
|
||||
}
|
||||
|
||||
$notes = TrackingNoteLogic::getByDiagnosis($diagnosisId);
|
||||
return $this->data($notes);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 校验当前登录患者是否拥有指定诊单(通过 diagnosis_view_records 关联)
|
||||
* @param int $diagnosisId
|
||||
* @return array{ok:bool,diagnosis?:\app\common\model\tcm\Diagnosis,error?:string}
|
||||
*/
|
||||
private function ensurePatientOwnsDiagnosis(int $diagnosisId): array
|
||||
{
|
||||
if (!$this->userId) {
|
||||
return ['ok' => false, 'error' => '请先登录'];
|
||||
}
|
||||
if ($diagnosisId <= 0) {
|
||||
return ['ok' => false, 'error' => '诊单ID不能为空'];
|
||||
}
|
||||
|
||||
$diagnosis = Diagnosis::where('id', $diagnosisId)->find();
|
||||
if (!$diagnosis) {
|
||||
return ['ok' => false, 'error' => '诊单不存在'];
|
||||
}
|
||||
|
||||
// 通过 diagnosis_view_records 校验当前小程序用户与该诊单的归属关系
|
||||
// 该表是「就诊卡列表」的来源(参考 DiagnosisLogic::getCardList)
|
||||
$owned = \think\facade\Db::name('diagnosis_view_records')
|
||||
->where('user_id', $this->userId)
|
||||
->where('diagnosis_id', $diagnosisId)
|
||||
->where('delete_time', null)
|
||||
->find();
|
||||
|
||||
if (!$owned) {
|
||||
return ['ok' => false, 'error' => '无权操作该诊单'];
|
||||
}
|
||||
|
||||
return ['ok' => true, 'diagnosis' => $diagnosis];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 日常记录-获取今日已录入的血糖血压记录(患者端)
|
||||
*
|
||||
* 路由:GET /api/tcm/dailyTodayBloodRecord?diagnosis_id=:id
|
||||
*
|
||||
* 用于「日常记录」页打开「录入今日」表单时预填数据;只返回 source=1 的当天记录。
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function dailyTodayBloodRecord()
|
||||
{
|
||||
$diagnosisId = (int) $this->request->get('diagnosis_id', 0);
|
||||
$check = $this->ensurePatientOwnsDiagnosis($diagnosisId);
|
||||
if (!$check['ok']) {
|
||||
return $this->fail($check['error']);
|
||||
}
|
||||
|
||||
try {
|
||||
$todayStart = strtotime(date('Y-m-d 00:00:00'));
|
||||
$todayEnd = strtotime(date('Y-m-d 23:59:59'));
|
||||
|
||||
$record = BloodRecord::where('diagnosis_id', $diagnosisId)
|
||||
->where('source', 1)
|
||||
->where('record_date', '>=', $todayStart)
|
||||
->where('record_date', '<=', $todayEnd)
|
||||
->order('id', 'desc')
|
||||
->find();
|
||||
|
||||
if (!$record) {
|
||||
return $this->data(['record' => null, 'today' => date('Y-m-d')]);
|
||||
}
|
||||
|
||||
$data = $record->toArray();
|
||||
$data['record_date'] = date('Y-m-d', (int) $data['record_date']);
|
||||
return $this->data(['record' => $data, 'today' => date('Y-m-d')]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 日常记录-保存今日的血糖血压记录(患者端)
|
||||
*
|
||||
* 路由:POST /api/tcm/dailySaveBloodRecord
|
||||
* 必填:diagnosis_id
|
||||
* 可选数值:fasting_blood_sugar, postprandial_blood_sugar, other_blood_sugar,
|
||||
* systolic_pressure, diastolic_pressure
|
||||
* 可选字符串:remark
|
||||
*
|
||||
* 语义:同一天同一诊单只有一条 source=1 的记录;存在则 update,不存在则 create。
|
||||
* 日期强制为「今天」;任何 record_date 入参被忽略,避免补录历史。
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function dailySaveBloodRecord()
|
||||
{
|
||||
$diagnosisId = (int) $this->request->post('diagnosis_id', 0);
|
||||
$check = $this->ensurePatientOwnsDiagnosis($diagnosisId);
|
||||
if (!$check['ok']) {
|
||||
return $this->fail($check['error']);
|
||||
}
|
||||
$diagnosis = $check['diagnosis'];
|
||||
|
||||
// 解析并校验数值字段;空字符串当 null 处理
|
||||
$parseDecimal = function ($v) {
|
||||
if ($v === null || $v === '' || $v === '0' || $v === 0) return null;
|
||||
if (!is_numeric($v)) return null;
|
||||
$f = (float) $v;
|
||||
return $f > 0 ? $f : null;
|
||||
};
|
||||
$parseInt = function ($v) {
|
||||
if ($v === null || $v === '') return null;
|
||||
if (!is_numeric($v)) return null;
|
||||
$i = (int) $v;
|
||||
return $i > 0 ? $i : null;
|
||||
};
|
||||
|
||||
$fasting = $parseDecimal($this->request->post('fasting_blood_sugar'));
|
||||
$postprandial = $parseDecimal($this->request->post('postprandial_blood_sugar'));
|
||||
$other = $parseDecimal($this->request->post('other_blood_sugar'));
|
||||
$systolic = $parseInt($this->request->post('systolic_pressure'));
|
||||
$diastolic = $parseInt($this->request->post('diastolic_pressure'));
|
||||
$remark = trim((string) $this->request->post('remark', ''));
|
||||
|
||||
// 至少要填一个有效字段
|
||||
if ($fasting === null && $postprandial === null && $other === null &&
|
||||
$systolic === null && $diastolic === null && $remark === '') {
|
||||
return $this->fail('请至少填写一项血糖或血压数据');
|
||||
}
|
||||
|
||||
// 边界校验,避免误录天文数字
|
||||
if ($fasting !== null && ($fasting < 0.1 || $fasting > 50)) return $this->fail('空腹血糖数值异常');
|
||||
if ($postprandial !== null && ($postprandial < 0.1 || $postprandial > 50)) return $this->fail('餐后血糖数值异常');
|
||||
if ($other !== null && ($other < 0.1 || $other > 50)) return $this->fail('其他血糖数值异常');
|
||||
if ($systolic !== null && ($systolic < 40 || $systolic > 300)) return $this->fail('收缩压数值异常');
|
||||
if ($diastolic !== null && ($diastolic < 20 || $diastolic > 200)) return $this->fail('舒张压数值异常');
|
||||
|
||||
try {
|
||||
$todayStart = strtotime(date('Y-m-d 00:00:00'));
|
||||
$todayEnd = strtotime(date('Y-m-d 23:59:59'));
|
||||
|
||||
$existing = BloodRecord::where('diagnosis_id', $diagnosisId)
|
||||
->where('source', 1)
|
||||
->where('record_date', '>=', $todayStart)
|
||||
->where('record_date', '<=', $todayEnd)
|
||||
->order('id', 'desc')
|
||||
->find();
|
||||
|
||||
$payload = [
|
||||
'diagnosis_id' => $diagnosisId,
|
||||
'patient_id' => (int) $diagnosis['patient_id'],
|
||||
'record_date' => $todayStart,
|
||||
'record_time' => date('H:i'),
|
||||
'fasting_blood_sugar' => $fasting,
|
||||
'postprandial_blood_sugar' => $postprandial,
|
||||
'other_blood_sugar' => $other,
|
||||
'systolic_pressure' => $systolic,
|
||||
'diastolic_pressure' => $diastolic,
|
||||
'remark' => $remark,
|
||||
'source' => 1,
|
||||
];
|
||||
|
||||
if ($existing) {
|
||||
$payload['id'] = $existing['id'];
|
||||
BloodRecord::update($payload);
|
||||
return $this->success('已更新今日记录', ['id' => $existing['id']]);
|
||||
}
|
||||
|
||||
$created = BloodRecord::create($payload);
|
||||
return $this->success('录入成功', ['id' => $created->id]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 日常记录-删除今日的血糖血压记录(患者端)
|
||||
*
|
||||
* 路由:POST /api/tcm/dailyDeleteBloodRecord
|
||||
* 必填:diagnosis_id, id
|
||||
*
|
||||
* 只允许删除当前用户拥有的诊单 + 当天 + source=1 的记录;其他情况一律拒绝。
|
||||
*
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function dailyDeleteBloodRecord()
|
||||
{
|
||||
$diagnosisId = (int) $this->request->post('diagnosis_id', 0);
|
||||
$recordId = (int) $this->request->post('id', 0);
|
||||
$check = $this->ensurePatientOwnsDiagnosis($diagnosisId);
|
||||
if (!$check['ok']) {
|
||||
return $this->fail($check['error']);
|
||||
}
|
||||
|
||||
if ($recordId <= 0) {
|
||||
return $this->fail('记录ID不能为空');
|
||||
}
|
||||
|
||||
try {
|
||||
$todayStart = strtotime(date('Y-m-d 00:00:00'));
|
||||
$todayEnd = strtotime(date('Y-m-d 23:59:59'));
|
||||
|
||||
$record = BloodRecord::where('id', $recordId)
|
||||
->where('diagnosis_id', $diagnosisId)
|
||||
->where('source', 1)
|
||||
->find();
|
||||
|
||||
if (!$record) {
|
||||
return $this->fail('记录不存在或无权删除');
|
||||
}
|
||||
|
||||
$ts = (int) $record['record_date'];
|
||||
if ($ts < $todayStart || $ts > $todayEnd) {
|
||||
return $this->fail('只能删除当天的记录');
|
||||
}
|
||||
|
||||
BloodRecord::destroy($recordId);
|
||||
return $this->success('已删除');
|
||||
} catch (\Exception $e) {
|
||||
return $this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 根据订单号获取订单详情(供小程序支付页调用)
|
||||
* @return \think\response\Json
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
-- 为「血糖血压记录表」增加来源字段
|
||||
-- 0 = 医生 / 助理在管理后台录入(历史数据默认 0)
|
||||
-- 1 = 患者在小程序「日常记录」页自录
|
||||
-- 该字段用于:1) 后台 DailyMatrix 上展示「患者自录」徽章;2) 限制患者只能编辑/删除自己当天的记录
|
||||
|
||||
ALTER TABLE `zyt_tcm_blood_record`
|
||||
ADD COLUMN `source` tinyint(1) NOT NULL DEFAULT 0 COMMENT '来源:0-医生录入 1-患者自录' AFTER `remark`;
|
||||
|
||||
-- 加索引方便按来源过滤
|
||||
ALTER TABLE `zyt_tcm_blood_record`
|
||||
ADD KEY `idx_source` (`source`);
|
||||
Reference in New Issue
Block a user