You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

711 lines
30 KiB
PHP

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Http\Controllers\API\Third;
use App\Http\Controllers\API\His\HisController;
use App\Http\Controllers\Controller;
use DateTime;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class YiJiController extends Controller
{
//查询是否跳转医技
public function CheckAppointment()
{
try {
$cardNo = request('cardNo');//病人id
$visitSqNo = request('visitSqNo');//门诊挂号流水号/住院流水号
$requestNoList= request('requestNoList');//申请单号(数组)
$moOrderList = request('OrderNoList');//医嘱号列表(数组)
$visitTypeCode = request('visitTypeCode');// 01:门诊 02:急诊 03:住院 04:体检 05:互联网 09:其他
$dev = intval(request('dev', 0)); //调试模式
$patientTypeMapping = ['03' => 0, '01' => 1, '02' => 2, '04' => 3];
$patientType = $patientTypeMapping[$visitTypeCode] ?? 9;
$is_redirect = false;
$url = "";
$entrust_ids = [];
$termCodes = [];
$execDeptCodes = [];
if (!is_array($requestNoList)) {
return \Yz::JsonReturn(false, 'requestNoList 参数必须是数组', []);
}
//急诊患者直接返回不调ROC、不写库
if ($visitTypeCode === '02') {
return \Yz::JsonReturn(true, '查询成功', ['is_redirect' => false, 'url' => '', 'room_names' => []]);
}
foreach ($requestNoList as $requestNo) {
//1.查询his获取申请单全部检查项目
$res = HisController::GetApplyDetail($visitSqNo, $requestNo, $visitTypeCode, 'HIS');
$debug_hisResponse = $res;
if ($res['code'] == 200) {
$res_data = $res['data'];
foreach ($res_data as $data_k => $data_v) {
$date = DateTime::createFromFormat('YmdHis', $data_v['requestDate']);
if ($date) {
$entrust_datePart = $date->format('Y-m-d'); // 日期部分
$entrust_timePart = $date->format('H:i:s'); // 时间部分
} else {
$entrust_datePart = '';
$entrust_timePart = '';
}
$birthday_f = DateTime::createFromFormat('Ymd', $data_v['patientBirthDate']);
if ($birthday_f) {
$birthday = $birthday_f->format('Y-m-d');
}else{
$birthday='';
}
$mapping = [
'03' => 0, // 住院 -> 0
'01' => 1, // 门诊 -> 1
'02' => 2, // 急诊 -> 2
'04' => 3, // 体检 -> 3
];
$patientType = $mapping[$data_v['visitTypeCode'] ?? $visitTypeCode] ?? 9;
foreach ($data_v['itemList'] as $item_k => $item) {
// 检查科室是否参与预约
$entrust_ids[] = $item['orderNo'];
$termCodes[] = $item['termCode'];
$execDeptCodes[] = $item['execDeptCode'];
// UPSERT原子操作消除 SELECT + INSERT 之间的竞态
$params = [
'list_status' => 0,
'reg_num' => $data_v['cardNo'],
'user_name' =>$data_v['patientName'],
'user_sex' => $data_v['patientGenderName'] == '男' ? 1 : 2,
'entrust_code' => $item['termCode'],
'entrust' => $item['termName'],
'is_pay' => $data_v["chargeStatusName"] == '已收费' ? 1 : 0,
'reservation_department' =>$data_v["orderDeptName"],
'entrust_date' =>$entrust_datePart,
'entrust_time' =>$entrust_timePart,
'user_brithday' =>$birthday,
'docotr' => $data_v["orderPersonName"],
'patient_type' => $patientType,
'user_phone' => $data_v["mobile"],
'implement_department' =>$item['execDeptName'],
'entrust_id' => $item['orderNo'],
'episodeid' => $visitSqNo,
'RISRAcceptDeptCode' => $item["execDeptCode"],
'warddesc' => $data_v["areaName"],
'wardcode' => $data_v["areaCode"],
'bedname' => $data_v["bedName"],
'bedno' => $data_v["bedNo"],
'app_num' => $data_v["requestNo"],
'idCardNumber' => $data_v["idCardNumber"],
'medicalHistory' => $data_v["medicalHistory"],
'diagnosisName' => $data_v["diagnosisName"],
'his_is_emergency'=> intval($data_v["urgentFlag"]),
'reservation_department_code' =>$data_v["orderDeptCode"],
'doctor_code' => $data_v["orderPersonCode"],
'requestComment' => $data_v["requestComment"] ?? null,
];
$columns = '`' . implode('`, `', array_keys($params)) . '`';
$holders = implode(', ', array_fill(0, count($params), '?'));
$assigns = implode(', ', array_map(fn($k) => "`{\$k}` = VALUES(`{\$k}`)", array_keys($params)));
$sql = "INSERT INTO `s_list` ({$columns}) VALUES ({$holders}) ON DUPLICATE KEY UPDATE {$assigns}";
DB::statement($sql, array_values($params));
$rowCount = DB::select("SELECT ROW_COUNT() AS `affected`")[0]->affected;
$note = ($rowCount == 1) ? '创建记录' : 'MQ冲突更新';
$list_id = DB::table('s_list')->where('entrust_id', $item['orderNo'])->value('id');
DB::table('s_list_log')->insert([
'list_id' => $list_id,
'reg_num' => $data_v['cardNo'],
'old_status' => 0,
'new_status' => 0,
'create_user' => 'his',
'note' => $note,
'data' => json_encode($params),
]);
}
}
}else{
return \Yz::JsonError('Roc接口查询失败');
}
}
// ====== HIS 执行科室可预约性检查 ======
$deptCheckResult = $this->classifyCheckItemsByDept($termCodes);
if (empty($deptCheckResult['normal'])) {
return \Yz::JsonReturn(true, '查询成功', [
'is_redirect' => false,
'url' => '',
'room_names' => [],
]);
}
// 检查是否有诊室参与预约
$termCodes = array_unique($termCodes);
$execDeptCodes = array_unique($execDeptCodes);
// 检查 HIS 执行科室是否参与预约
$departmentEnabled = false;
if (!empty($execDeptCodes)) {
$enabledCount = DB::table("s_department")
->whereIn("department_number", $execDeptCodes)
->where("appointment_enabled", 1)
->count();
$departmentEnabled = ($enabledCount == count($execDeptCodes));
}
$hasEnabledRoom = 0;
if (!empty($termCodes)) {
$hasEnabledRoom = DB::table('s_check_item')
->whereIn('s_check_item.item_code', $termCodes)
->join('s_check_item_device', 's_check_item.id', '=', 's_check_item_device.item_id')
->join('s_source_roster_detail_device', 's_check_item_device.device_id', '=', 's_source_roster_detail_device.device_id')
->join('s_source_roster_detail', 's_source_roster_detail_device.roster_detail_id', '=', 's_source_roster_detail.id')
->join('s_department_resources', 's_source_roster_detail.resources_id', '=', 's_department_resources.id')
->where('s_source_roster_detail.status', 1)
->where('s_source_roster_detail.is_del', 0)
->where('s_department_resources.is_del', 0)
->where('s_department_resources.department_resources_status', 1)
->where('s_department_resources.appointment_enabled', 1)
->whereRaw("FIND_IN_SET(?, s_source_roster_detail.patient_type)", [$patientType])
->count();
}
if ($departmentEnabled && $hasEnabledRoom > 0 && !in_array($patientType, [2, 3])) {
$is_redirect = true;
$url = $this->build_yiji_url($cardNo, $entrust_ids, $visitSqNo);
} else {
$is_redirect = false;
$url = '';
}
// 查询执行诊室名称
$roomNames = [];
if (!empty($termCodes)) {
$roomNames = DB::table('s_check_item')
->whereIn('s_check_item.item_code', $termCodes)
->join('s_check_item_device', 's_check_item.id', '=', 's_check_item_device.item_id')
->join('s_source_roster_detail_device', 's_check_item_device.device_id', '=', 's_source_roster_detail_device.device_id')
->join('s_source_roster_detail', 's_source_roster_detail_device.roster_detail_id', '=', 's_source_roster_detail.id')
->join('s_department_resources', 's_source_roster_detail.resources_id', '=', 's_department_resources.id')
->where('s_source_roster_detail.status', 1)
->where('s_source_roster_detail.is_del', 0)
->where('s_department_resources.is_del', 0)
->where('s_department_resources.department_resources_status', 1)
->where('s_department_resources.appointment_enabled', 1)
->whereRaw("FIND_IN_SET(?, s_source_roster_detail.patient_type)", [$patientType])
->distinct()
->pluck('s_department_resources.department_resources_name')
->toArray();
}
$data = ['is_redirect' => $is_redirect, 'url' => $url, 'room_names' => $roomNames];
if ($dev === 1) {
$data['debug_termCodes'] = $termCodes;
$data['debug_hisResponse'] = $debug_hisResponse ?? [];
}
return \Yz::JsonReturn(true, '查询成功', $data);
} catch (\Exception $e) {
return \Yz::JsonReturn(false, '接口异常:' . $e->getMessage(), ['error_file' => $e->getFile(), 'error_line' => $e->getLine()]);
}
}
public function CheckAppointmentTest()
{
try {
$password = request('password');
$id = request('id');
// 密码校验
if ($password !== '609384AA-E90D-4BE7-8317-3D6D7DE0A442') {
return \Yz::JsonReturn(false, '密钥错误', []);
}
// 查询 s_list 记录
$sList = DB::table('s_list')->where('id', $id)->first();
if (!$sList) {
return \Yz::JsonReturn(false, '未找到该记录', []);
}
// 反向映射 patient_type → visitTypeCode0→03住院, 1→01门诊, 2→02急诊, 3→04体检
$patientTypeMapping = [0 => '03', 1 => '01', 2 => '02', 3 => '04'];
$visitTypeCode = $patientTypeMapping[$sList->patient_type] ?? '09';
$result = [
's_list_info' => [
'id' => $sList->id,
'entrust_id' => $sList->entrust_id,
'entrust_code' => $sList->entrust_code,
'entrust' => $sList->entrust,
'reg_num' => $sList->reg_num,
'episodeid' => $sList->episodeid,
'app_num' => $sList->app_num,
'RISRAcceptDeptCode' => $sList->RISRAcceptDeptCode,
'implement_department' => $sList->implement_department,
'patient_type' => $sList->patient_type,
'visitTypeCode' => $visitTypeCode,
],
];
// 1. 调用 HIS 接口查询申请单(走缓存)
$hisRes = HisController::GetApplyDetail($sList->episodeid, $sList->app_num, $sList->patient_type, '本地');
$result['his_query'] = [
'params' => [
'visitSqNo' => $sList->episodeid,
'requestNo' => $sList->app_num,
'visitTypeCode' => $visitTypeCode,
],
'response' => $hisRes,
'success' => ($hisRes['code'] == 200 && !empty($hisRes['data'])),
];
// 2. 检查科室是否参与预约
$dept = DB::table('s_department')
->where('department_number', $sList->RISRAcceptDeptCode)
->first();
$result['department_check'] = [
'department_number' => $sList->RISRAcceptDeptCode,
'department_name' => $dept->department_name ?? '未找到',
'found' => $dept ? true : false,
'appointment_enabled' => $dept ? ($dept->appointment_enabled == 1) : false,
];
// 3. 检查项目 → 设备 → 检查室链路
$item = DB::table('s_check_item')
->where('item_code', $sList->entrust_code)
->first();
$roomCheck = [];
if ($item) {
$devices = DB::table('s_check_item_device')
->where('item_id', $item->id)
->get();
foreach ($devices as $device) {
$rooms = DB::table('s_source_roster_detail_device')
->where('s_source_roster_detail_device.device_id', $device->device_id)
->join('s_source_roster_detail', 's_source_roster_detail_device.roster_detail_id', '=', 's_source_roster_detail.id')
->join('s_department_resources', 's_source_roster_detail.resources_id', '=', 's_department_resources.id')
->where('s_source_roster_detail.status', 1)
->where('s_source_roster_detail.is_del', 0)
->where('s_department_resources.is_del', 0)
->where('s_department_resources.department_resources_status', 1)
->whereRaw('FIND_IN_SET(?, s_source_roster_detail.patient_type)', [$sList->patient_type])
->select(
's_source_roster_detail.id as schedule_id',
's_source_roster_detail.date as schedule_date',
's_department_resources.id as room_id',
's_department_resources.department_resources_name as room_name',
's_department_resources.appointment_enabled as room_appointment_enabled'
)
->get();
foreach ($rooms as $room) {
$roomCheck[] = [
'device_id' => $device->device_id,
'room_id' => $room->room_id,
'room_name' => $room->room_name,
'room_appointment_enabled' => $room->room_appointment_enabled == 1,
'schedule_date' => $room->schedule_date,
];
}
}
}
$result['room_check'] = [
'item_found' => $item ? true : false,
'item_name' => $item->item_name ?? '未找到',
'device_count' => isset($devices) ? count($devices) : 0,
'room_count' => count($roomCheck),
'rooms' => $roomCheck,
];
// 综合结论
$hasEnabledRoom = false;
foreach ($roomCheck as $r) {
if ($r['room_appointment_enabled']) {
$hasEnabledRoom = true;
break;
}
}
$result['overall_result'] = [
'can_redirect' => $result['department_check']['appointment_enabled'] && $hasEnabledRoom,
'department_ok' => $result['department_check']['appointment_enabled'],
'room_ok' => $hasEnabledRoom,
];
return \Yz::JsonReturn(true, '诊断完成', $result);
} catch (\Exception $e) {
return \Yz::JsonReturn(false, '接口异常:' . $e->getMessage(), [
'error_file' => $e->getFile(),
'error_line' => $e->getLine()
]);
}
}
function QueryHisShenQingDan()
{
}
/**
* 测试 HIS 回写接口入参收集
* 根据 s_list ID 查询 HIS 申请单,组装回写所需参数并返回,不实际调用回写接口
*/
public function TestHisCallbackParams()
{
try {
$id = request('id');
if (empty($id)) {
return \Yz::JsonReturn(false, '参数 id 不能为空', []);
}
$sList = DB::table('s_list')->where('id', $id)->first();
if (!$sList) {
return \Yz::JsonReturn(false, '未找到该记录', []);
}
$result = [
's_list_info' => [
'id' => $sList->id,
'entrust_id' => $sList->entrust_id,
'entrust_code' => $sList->entrust_code,
'entrust' => $sList->entrust,
'reg_num' => $sList->reg_num,
'episodeid' => $sList->episodeid,
'app_num' => $sList->app_num,
'patient_type' => $sList->patient_type,
'reservation_sources' => $sList->reservation_sources,
'RISRAcceptDeptCode' => $sList->RISRAcceptDeptCode,
'implement_department' => $sList->implement_department,
],
];
// 1. 获取 execDeptCode / execDeptName通过排班→诊室资源→执行科室链路
$execDeptCode = '';
$execDeptName = '';
$execDeptInfo = [];
if (!empty($sList->reservation_sources)) {
$resource = DB::table('s_department_resources')
->where('id', $sList->reservation_sources)
->first();
if ($resource) {
$deptId = $resource->execute_department_id ?: $resource->department_id;
if ($deptId) {
$dept = DB::table('s_department')
->where('id', $deptId)
->first();
if ($dept) {
$execDeptCode = $dept->department_number;
$execDeptName = $dept->department_name;
$execDeptInfo = [
'resources_id' => $sList->reservation_sources,
'execute_department_id' => $resource->execute_department_id,
'department_id' => $resource->department_id,
'dept_id_used' => $deptId,
'department_number' => $dept->department_number,
'department_name' => $dept->department_name,
];
}
}
}
}
$result['exec_dept_info'] = $execDeptInfo;
// 2. 调 HIS 查询申请单接口
$patientHisTypeMap = [
0 => '03', // 住院
1 => '01', // 门诊
2 => '02', // 急诊
3 => '04', // 体检
];
$visitTypeCode = $patientHisTypeMap[$sList->patient_type] ?? '09';
$result['his_query'] = [
'params' => [
'visitSqNo' => $sList->episodeid,
'requestNo' => $sList->app_num,
'visitTypeCode' => $visitTypeCode,
],
];
try {
$hisRes = HisController::GetApplyDetail($sList->episodeid, $sList->app_num, $sList->patient_type, '本地');
$result['his_query']['response'] = $hisRes;
$result['his_query']['success'] = ($hisRes['code'] == 200 && !empty($hisRes['data']));
if ($hisRes['code'] == 200 && !empty($hisRes['data'])) {
$hisData = $hisRes['data'][0] ?? null;
if ($hisData) {
// 3. 提取申请单级数据
$comboNo = $hisData['requestNo'] ?? '';
// 住院取 episodeid门诊取 reg_num
$inpatientNo = $sList->patient_type == 0 ? $sList->episodeid : $sList->episodeid;
// 4. 匹配项目级数据
$moOrder = '';
$hisOrderNo = '';
$matchedItem = [];
if (!empty($hisData['itemList']) && is_array($hisData['itemList'])) {
foreach ($hisData['itemList'] as $item) {
if (($item['termCode'] ?? '') == $sList->entrust_code) {
$moOrder = $item['orderNo'] ?? '';
$hisOrderNo = $item['chargeList'][0]['hisOrderNo'] ?? '';
$matchedItem = [
'termCode' => $item['termCode'] ?? '',
'termName' => $item['termName'] ?? '',
'orderNo' => $item['orderNo'] ?? '',
'hisOrderNo' => $hisOrderNo,
];
break;
}
}
}
$result['matched_item'] = $matchedItem;
// 5. 组装回写参数
$result['callback_params'] = [
'moOrder' => $moOrder,
'execDeptCode' => $execDeptCode,
'execDeptName' => $execDeptName,
'inpatientNo' => $inpatientNo,
'hisOrderNo' => $hisOrderNo,
'comboNo' => $comboNo,
'itemCode' => $sList->entrust_code,
];
}
}
} catch (\Exception $e) {
$result['his_query']['response'] = null;
$result['his_query']['success'] = false;
$result['his_query']['error'] = $e->getMessage();
}
return \Yz::JsonReturn(true, '查询完成', $result);
} catch (\Exception $e) {
return \Yz::JsonReturn(false, '接口异常:' . $e->getMessage(), [
'error_file' => $e->getFile(),
'error_line' => $e->getLine()
]);
}
}
function build_yiji_url($regnum, $entrustid, $episodeid)
{
// 固定参数
$dotype = 1;
$appointment_type = 1;
// 判断 entrustid 是否为数组,如果是,则用逗号 , 拼接并分别进行 rawurlencode 编码
if (is_array($entrustid)) {
// 对数组中的每个元素进行 rawurlencode 编码后再拼接
$entrustid_str = implode(',', array_map('rawurlencode', $entrustid));
}
// 构造查询参数,并对 regnum 和 episodeid 使用 rawurlencode 编码
$params = [
'regnum' => rawurlencode($regnum),
'entrustid' => $entrustid_str,
'episodeid' => rawurlencode($episodeid),
'dotype' => $dotype,
'appointment_type' => $appointment_type,
];
// 使用 http_build_query 构建查询字符串,注意设置第四个参数为 PHP_QUERY_RFC3986
// 以确保生成的 URL 符合 RFC 3986 标准
$query = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
// 返回完整 URL
return "http://192.168.80.76/yiji?$query";
}
/**
* 根据项目编号数组,检查各项目对应的 HIS 执行科室是否可预约
* 存在至少一个满足条件的科室appointment_enabled=1, department_status=1, is_del=0
* 则该项目归入 normal 数组,否则归入 disabled 数组
* @param array $entrustCodes 项目编号数组
* @return array ['normal' => [...], 'disabled' => [...]]
*/
private function classifyCheckItemsByDept(array $entrustCodes)
{
$normal = [];
$disabled = [];
if (empty($entrustCodes)) {
return ['normal' => $normal, 'disabled' => $disabled];
}
// 去重
$entrustCodes = array_unique($entrustCodes);
// 批量查询检查项目
$items = DB::table('s_check_item')
->whereIn('item_code', $entrustCodes)
->select('item_code', 'item_name', 'hisExecDepts')
->get()
->keyBy('item_code');
// 收集所有需要查询的科室编号
$allDeptCodes = [];
$itemDeptMap = []; // item_code => ['item_name' => ..., 'dept_codes' => [...]]
foreach ($entrustCodes as $code) {
if (!isset($items[$code])) {
// 查不到记录 → 非预约
$disabled[] = [
'entrust_code' => $code,
'item_name' => '',
'depts' => [],
'has_normal_dept' => false,
];
continue;
}
$item = $items[$code];
$hisExecDepts = $item->hisExecDepts;
if (empty($hisExecDepts)) {
// hisExecDepts 为空或 null → 非预约
$disabled[] = [
'entrust_code' => $code,
'item_name' => $item->item_name,
'depts' => [],
'has_normal_dept' => false,
];
continue;
}
$deptCodes = json_decode($hisExecDepts, true);
if (empty($deptCodes) || !is_array($deptCodes)) {
// 解析失败或为空 → 非预约
$disabled[] = [
'entrust_code' => $code,
'item_name' => $item->item_name,
'depts' => [],
'has_normal_dept' => false,
];
continue;
}
$itemDeptMap[$code] = [
'item_name' => $item->item_name,
'dept_codes' => $deptCodes,
];
$allDeptCodes = array_merge($allDeptCodes, $deptCodes);
}
if (empty($allDeptCodes)) {
return ['normal' => $normal, 'disabled' => $disabled];
}
// 批量查询科室信息
$allDeptCodes = array_unique($allDeptCodes);
$departments = DB::table('s_department')
->whereIn('department_number', $allDeptCodes)
->select('department_number', 'department_name', 'appointment_enabled', 'department_status', 'is_del')
->get()
->keyBy('department_number');
// 遍历每个项目,判断科室状态
foreach ($itemDeptMap as $code => $info) {
$deptList = [];
$hasNormal = false;
foreach ($info['dept_codes'] as $deptCode) {
if (!isset($departments[$deptCode])) {
// 科室不存在 → 算非预约
$deptList[] = [
'dept_code' => $deptCode,
'dept_name' => '',
'status' => 'disabled',
'reason' => '科室不存在',
];
continue;
}
$dept = $departments[$deptCode];
$isNormal = $dept->appointment_enabled == 1
&& $dept->department_status == 1
&& $dept->is_del == 0;
$reasons = [];
if ($dept->appointment_enabled != 1) $reasons[] = 'appointment_enabled=' . $dept->appointment_enabled;
if ($dept->department_status != 1) $reasons[] = 'department_status=' . $dept->department_status;
if ($dept->is_del != 0) $reasons[] = 'is_del=' . $dept->is_del;
$deptList[] = [
'dept_code' => $deptCode,
'dept_name' => $dept->department_name,
'status' => $isNormal ? 'normal' : 'disabled',
'reason' => $isNormal ? '' : implode(', ', $reasons),
];
if ($isNormal) {
$hasNormal = true;
}
}
$entry = [
'entrust_code' => $code,
'item_name' => $info['item_name'],
'depts' => $deptList,
'has_normal_dept' => $hasNormal,
];
if ($hasNormal) {
$normal[] = $entry;
} else {
$disabled[] = $entry;
}
}
return ['normal' => $normal, 'disabled' => $disabled];
}
/**
* 测试获取申请单详情
* 入参: visitSqNo, requestNo, visitTypeCodeHIS 格式)
*/
public function TestGetApplyDetail()
{
try {
$visitSqNo = request('visitSqNo');
$requestNo = request('requestNo');
$visitTypeCode = request('visitTypeCode');
if (empty($visitSqNo) || empty($requestNo) || empty($visitTypeCode)) {
return response()->json([
'code' => 200,
'msg' => '参数 visitSqNo、requestNo、visitTypeCode 不能为空',
'data' => [],
])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
}
$res = HisController::GetApplyDetail($visitSqNo, $requestNo, $visitTypeCode, 'HIS');
return response()->json($res)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
} catch (\Exception $e) {
return response()->json([
'code' => 200,
'msg' => '接口异常:' . $e->getMessage(),
'data' => [],
])->setEncodingOptions(JSON_UNESCAPED_UNICODE);
}
}
}