feat: 修改建档流程,修改HIS出参, 科室列表使用表数据返回

fix:  修复若干BUG
master
Rmiku 3 days ago
parent 6754669e36
commit 4518acb3a8
  1. 1
      .gitignore
  2. 26
      app/Console/Bat/SendAppointmentReminders.bat
  3. 13
      app/Console/Commands/SendAppointmentReminders.php
  4. 8
      app/Dictionary/Order/Type.php
  5. 3
      app/Dictionary/WeChat/MiniProgram/OpenApi.php
  6. 1
      app/Http/Controllers/Health/RecordController.php
  7. 18
      app/Http/Controllers/Hospital/IntroduceController.php
  8. 1
      app/Http/Controllers/Notify/NotifyController.php
  9. 5
      app/Http/Controllers/Outpatient/PaymentController.php
  10. 4
      app/Http/Controllers/Patient/PatientController.php
  11. 5
      app/Http/Controllers/Registration/ScheduleController.php
  12. 25
      app/Http/Controllers/Test/TestController.php
  13. 28
      app/Http/Logics/Health/RecordLogic.php
  14. 24
      app/Http/Logics/Notify/NotifyLogic.php
  15. 89
      app/Http/Logics/Outpatient/PaymentLogic.php
  16. 76
      app/Http/Logics/Outpatient/PendingLogic.php
  17. 14
      app/Http/Logics/Outpatient/RecordLogic.php
  18. 83
      app/Http/Logics/Patient/PatientLogic.php
  19. 32
      app/Http/Logics/Registration/RecordLogic.php
  20. 16
      app/Http/Logics/Registration/RegisterLogic.php
  21. 5
      app/Http/Logics/Registration/ScheduleLogic.php
  22. 2
      app/Http/Middleware/RecordApiLog.php
  23. 18
      app/Http/Resources/Dictionary/ItemDetailsResource.php
  24. 4
      app/Http/Resources/Dictionary/ItemListsResource.php
  25. 8
      app/Http/Resources/Outpatient/Pending/PendingDetailsResource.php
  26. 26
      app/Http/Resources/Outpatient/Pending/PendingListsResource.php
  27. 11
      app/Http/Resources/Outpatient/Record/RecordDetailsResource.php
  28. 4
      app/Http/Resources/Outpatient/Record/RecordListsResource.php
  29. 4
      app/Http/Resources/Patient/PatientListsResource.php
  30. 7
      app/Http/Resources/Registration/Record/RecordListsResource.php
  31. 28
      app/Http/Resources/Registration/Schedule/DeptListsResource.php
  32. 18
      app/Http/Resources/Registration/Schedule/DoctorListsResource.php
  33. 3
      app/Models/Admin/Department.php
  34. 28
      app/Models/Order.php
  35. 14
      app/Models/Patient.php
  36. 4
      app/Providers/AppServiceProvider.php
  37. 64
      app/Providers/TelescopeServiceProvider.php
  38. 170
      app/Services/HealthRecordAuth/Client.php
  39. 22
      app/Services/HisHttp/Client.php
  40. 7
      app/Utils/Helpers.php
  41. 30
      app/Utils/Traits/BuildCacheKeyName.php
  42. 6
      app/Utils/Traits/SendSubscribeMessage.php
  43. 11
      app/Utils/Transfer/HisHttpClient/ClientHttpTransfer.php
  44. 24
      app/Utils/Transfer/HisHttpClient/ClientMockHttpTransfer.php
  45. 5
      app/Utils/Transfer/HisSoapClient/ClientSoapTransfer.php
  46. 17
      app/Utils/Transfer/HttpTransferAbstract.php
  47. 5
      app/Utils/Transfer/SoapTransferAbstract.php
  48. 6
      bootstrap/app.php
  49. 3
      bootstrap/providers.php
  50. 2
      composer.json
  51. 237
      composer.lock
  52. 4
      config/custom.php
  53. 206
      config/telescope.php
  54. 70
      database/migrations/2025_03_12_131223_create_telescope_entries_table.php
  55. 10
      packagist/unify_payment/src/Cores/BasicClient.php
  56. BIN
      public/images.lnk
  57. 8
      public/vendor/telescope/app-dark.css
  58. 7
      public/vendor/telescope/app.css
  59. 2
      public/vendor/telescope/app.js
  60. BIN
      public/vendor/telescope/favicon.ico
  61. 5
      public/vendor/telescope/mix-manifest.json
  62. 2
      routes/api.php
  63. 2
      storage/debugbar/.gitignore

1
.gitignore vendored

@ -22,3 +22,4 @@ yarn-error.log
/.nova /.nova
/.vscode /.vscode
/.zed /.zed
*.bak

@ -0,0 +1,26 @@
@echo off
REM 设置输出文件夹路径
set "output_folder=D:\Web\www\mini_xzey\storage\logs\RemindersLog\"
REM 创建输出文件夹(如果不存在)
if not exist "%output_folder%" (
mkdir "%output_folder%"
)
REM 生成按日期命名的文件名(格式为 yyyymmdd)
for /f "tokens=2 delims==" %%a in ('"wmic os get localdatetime /value"') do set "datetime=%%a"
set "current_date=%datetime:~0,8%"
set "output_file=%output_folder%\appointment_%current_date%.log"
REM 进入项目根目录
cd /d "D:\Web\www\mini_xzey"
REM 插入换行和当前时间到日志文件
echo. >> "%output_file%"
echo [%date% %time%] Running php artisan app:send-appointment-reminders >> "%output_file%"
REM 运行php artisan命令并将输出重定向到文件
php artisan app:send-appointment-reminders >> "%output_file%"
REM 提示完成
echo Command output has been saved to %output_file%

@ -2,11 +2,8 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Dictionary\SendMessage\Type; use App\Dictionary\Order\Status;
use App\Dictionary\WeChat\MiniProgram\SubscribeId;
use App\Jobs\SendWeChatMessageJob;
use App\Models\RegistrationRecord; use App\Models\RegistrationRecord;
use App\Models\SendMessageJob;
use App\Utils\Traits\SendSubscribeMessage; use App\Utils\Traits\SendSubscribeMessage;
use Exception; use Exception;
use Illuminate\Console\Command; use Illuminate\Console\Command;
@ -45,7 +42,7 @@ class SendAppointmentReminders extends Command
// 查询即将到期的预约记录(8小时后的预约) // 查询即将到期的预约记录(8小时后的预约)
$appointments = RegistrationRecord::where('visit_date', now()->toDate()) $appointments = RegistrationRecord::where('visit_date', now()->toDate())
->where('begin_date', now()->subHours(8)) ->where('begin_time', now()->subHours(8))
->where('reminder_sent', 0) ->where('reminder_sent', 0)
->get(); ->get();
@ -54,9 +51,13 @@ class SendAppointmentReminders extends Command
return BaseCommand::SUCCESS; return BaseCommand::SUCCESS;
} }
$message = new SendMessageJob();
$success_records = []; $success_records = [];
foreach ($appointments as $appointment) { foreach ($appointments as $appointment) {
// 状态不为成功直接跳过
if ($appointment->order->status !== Status::SUCCESS->value) {
continue;
}
try { try {
$this->sendAppointmentReminderMessage($appointment); $this->sendAppointmentReminderMessage($appointment);

@ -50,13 +50,13 @@ enum Type: int
{ {
return match ($this) { return match ($this) {
self::TODAY_REGISTRATION => 'A', self::TODAY_REGISTRATION => 'A',
self::APPOINTMENT_REGISTRATION => 'F', self::APPOINTMENT_REGISTRATION => 'B',
self::OUTPATIENT_PAYMENT => 'B', self::OUTPATIENT_PAYMENT => 'C',
self::INPATIENT_RECHARGE => 'E', self::INPATIENT_RECHARGE => 'D',
self::OUTPATIENT_PREPAID_CARD_RECHARGE, self::OUTPATIENT_PREPAID_CARD_RECHARGE,
self::INPATIENT_PREPAID_CARD_RECHARGE, self::INPATIENT_PREPAID_CARD_RECHARGE,
self::OUTPATIENT_PREPAID_CARD_REFUND, self::OUTPATIENT_PREPAID_CARD_REFUND,
self::INPATIENT_PREPAID_CARD_REFUND => 'H' self::INPATIENT_PREPAID_CARD_REFUND => 'E'
}; };
} }
} }

@ -33,4 +33,7 @@ enum OpenApi: string
// 推送消息 // 推送消息
case SEND_SUBSCRIBE_MESSAGE = 'cgi-bin/message/subscribe/send'; case SEND_SUBSCRIBE_MESSAGE = 'cgi-bin/message/subscribe/send';
// 创建二维码
case CREATE_QR_CODE = '/cgi-bin/wxaapp/createwxaqrcode';
} }

@ -16,6 +16,7 @@ use App\Models\Admin\Navigation;
use App\Models\Admin\News; use App\Models\Admin\News;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redis;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
class IntroduceController extends Controller class IntroduceController extends Controller
@ -27,6 +28,16 @@ class IntroduceController extends Controller
*/ */
public function deptLists(): JsonResponse public function deptLists(): JsonResponse
{ {
$cache_key = 'hospital.dept_lists';
if (Redis::exists($cache_key)) {
$lists = Redis::get($cache_key);
$lists = json_decode($lists, true);
if (!empty($lists)) {
return jsonResponse(Response::HTTP_OK, 'success.', $lists);
}
}
$category_lists = DepartmentCategory::select('id as category_id', 'name as category_name') $category_lists = DepartmentCategory::select('id as category_id', 'name as category_name')
->orderBy('sort', 'DESC') ->orderBy('sort', 'DESC')
->orderBy('id', 'ASC') ->orderBy('id', 'ASC')
@ -47,7 +58,10 @@ class IntroduceController extends Controller
]; ];
} }
return jsonResponse(Response::HTTP_OK, 'success.', array_values($category_lists)); $category_lists = array_values($category_lists);
Redis::setex($cache_key, 4 * 3600, json_encode($category_lists, JSON_UNESCAPED_UNICODE));
return jsonResponse(Response::HTTP_OK, 'success.', $category_lists);
} }
/** /**
@ -126,7 +140,7 @@ class IntroduceController extends Controller
'doctor_name' => $doctor_details->doctor_name, 'doctor_name' => $doctor_details->doctor_name,
'doctor_title' => $doctor_details->doctor_title, 'doctor_title' => $doctor_details->doctor_title,
'doctor_specialty' => $doctor_details->doctor_specialty, 'doctor_specialty' => $doctor_details->doctor_specialty,
'avatar' => getAdminUploadImageUrl((string) $doctor_details->avatar), 'avatar' => getAdminUploadImageUrl((string) $doctor_details->avatar, 'doctor_avatar'),
'introduction' => $doctor_details->introduction ?: '', 'introduction' => $doctor_details->introduction ?: '',
'is_expert' => $doctor_details->is_expert, 'is_expert' => $doctor_details->is_expert,
]; ];

@ -44,6 +44,7 @@ class NotifyController extends Controller
$server = $app->getServer(); $server = $app->getServer();
$message = $server->getRequestMessage(); $message = $server->getRequestMessage();
$server->serve()->getBody()->rewind();
$this->info('接收回调消息', $message->toArray()); $this->info('接收回调消息', $message->toArray());
try { try {

@ -26,10 +26,11 @@ class PaymentController
* 缴费 * 缴费
* @param Request $request * @param Request $request
* @param string $patient_id * @param string $patient_id
* @param string $serial_no
* @return JsonResponse * @return JsonResponse
* @throws GeneralException * @throws GeneralException
*/ */
public function payment(Request $request, string $patient_id): JsonResponse public function payment(Request $request, string $patient_id, string $serial_no): JsonResponse
{ {
$validated = $request->validate([ $validated = $request->validate([
'prescription_ids' => 'required', 'prescription_ids' => 'required',
@ -37,7 +38,7 @@ class PaymentController
'prescription_ids.required' => '请选择要缴纳的处方', 'prescription_ids.required' => '请选择要缴纳的处方',
]); ]);
$response = $this->payment_logic->payment($patient_id, $validated['prescription_ids']); $response = $this->payment_logic->payment($patient_id, $serial_no, $validated['prescription_ids']);
return jsonResponse(Response::HTTP_OK, 'success', $response); return jsonResponse(Response::HTTP_OK, 'success', $response);
} }

@ -60,7 +60,7 @@ class PatientController
{ {
$patient_id = $this->patient_logic->createPatient($request->safe()->all()); $patient_id = $this->patient_logic->createPatient($request->safe()->all());
return jsonResponse(Response::HTTP_CREATED, 'success', ['patient_id' => $patient_id]); return jsonResponse(Response::HTTP_OK, '建档成功', ['patient_id' => $patient_id]);
} }
/** /**
@ -73,7 +73,7 @@ class PatientController
{ {
$patient_id = $this->patient_logic->bindPatient($request->safe()->all()); $patient_id = $this->patient_logic->bindPatient($request->safe()->all());
return jsonResponse(Response::HTTP_CREATED, 'success', ['patient_id' => $patient_id]); return jsonResponse(Response::HTTP_OK, '绑定成功', ['patient_id' => $patient_id]);
} }
/** /**

@ -41,9 +41,10 @@ class ScheduleController
'date.after_or_equal' => '日期不能小于今天' 'date.after_or_equal' => '日期不能小于今天'
]); ]);
$response = $this->schedule_logic->getDeptLists($validated['date']); // 2025-03-26 科室列表取消接入HIS
// $response = $this->schedule_logic->getDeptLists($validated['date']);
return jsonResponse(Response::HTTP_OK, 'success', DeptListsResource::make($response)->toArray()); return jsonResponse(Response::HTTP_OK, 'success', DeptListsResource::make([])->toArray());
} }
/** /**

@ -3,17 +3,38 @@ declare(strict_types = 1);
namespace App\Http\Controllers\Test; namespace App\Http\Controllers\Test;
use App\Dictionary\WeChat\MiniProgram\OpenApi;
use App\Models\Order;
use App\Utils\Traits\HttpRequest;
use App\Utils\Traits\SendSubscribeMessage; use App\Utils\Traits\SendSubscribeMessage;
use Illuminate\Support\Facades\Redis;
use UnifyPayment\Cores\Struct\RefundOrder; use UnifyPayment\Cores\Struct\RefundOrder;
use UnifyPayment\Unify; use UnifyPayment\Unify;
class TestController class TestController
{ {
use SendSubscribeMessage; use SendSubscribeMessage;
public function test(): void public function test(): void
{ {
$app = getWeChatMiniProgramApp(); $mini = getWeChatMiniProgramApp();
dd($app->getAccessToken()->getToken()); $response = $mini->getClient()->postJson(OpenApi::CREATE_QR_CODE->value, [
'path' => 'pagesA/register/notice?ed=show',
]);
dd($response->toArray());
//dd(json_decode('', true));
// $response = '1';
// $order = Order::where('order_id', 'WXM20250207151636790')->first();
// $record = $order->outpatientPaymentRecord;
//
// foreach ($record as $v) {
// $extra_info = json_decode($v->extra_info, true);
// $extra_info['confirm_response'] = $response;
// $v->update(['extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]);
// }
// $app = getWeChatMiniProgramApp();
// dd($app->getAccessToken()->getToken());
// $refund = new RefundOrder('WXM20250208110845293', 'WXM20250208110845293_R123', '0.01', '人工退费'); // $refund = new RefundOrder('WXM20250208110845293', 'WXM20250208110845293_R123', '0.01', '人工退费');
// $response = Unify::common(config('unify'))->order->refund($refund); // $response = Unify::common(config('unify'))->order->refund($refund);

@ -0,0 +1,28 @@
<?php
declare(strict_types = 1);
namespace App\Http\Logics\Health;
use App\Services\HisHttp\Client;
use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth;
use Illuminate\Auth\AuthenticationException;
class RecordLogic
{
use Logger;
use MiniProgramAuth;
private Client $his_client;
/**
* ItemLogic Construct
* @throws AuthenticationException
*/
public function __construct()
{
$this->authInitialize();
$this->his_client = app('HisHttpService');
}
}

@ -111,7 +111,7 @@ class NotifyLogic
} }
} catch (GeneralException|Exception $e) { } catch (GeneralException|Exception $e) {
$err_msg = $e->getMessage().' ON '. $e->getFile(). ':'. $e->getLine(); $err_msg = $e->getMessage().' ON '. $e->getFile(). ':'. $e->getLine();
$this->error('挂号流程错误:'. $err_msg); $this->error('挂号/缴费流程错误:'. $err_msg);
$this->unlockOrder($notify->out_trade_no, $lock_id); $this->unlockOrder($notify->out_trade_no, $lock_id);
return false; return false;
} }
@ -140,12 +140,13 @@ class NotifyLogic
$record->doctor_id, $record->doctor_id,
$record->reg_id, $record->reg_id,
$extra['scheduleInfo']['rankId'], $extra['scheduleInfo']['rankId'],
$record->visit_date, //$record->visit_date,
date('Y-m-d H:i:s'),
PayType::WECHAT_PAY->hisCode(), PayType::WECHAT_PAY->hisCode(),
$order_info->order_id, $order_info->order_id,
'', '',
'', date('Y-m-d'),
'', date('H:i:s'),
'', '',
(string) ($notify->total_fee / 100), (string) ($notify->total_fee / 100),
'' ''
@ -187,29 +188,26 @@ class NotifyLogic
{ {
// 缴费确认 // 缴费确认
$record = $order_info->outpatientPaymentRecord; $record = $order_info->outpatientPaymentRecord;
$extra_info = json_decode($record->extra_info, true);
foreach ($record as $v) { $prescription_ids = &$extra_info['prescription_ids'];
$extra_info = json_decode($v->extra_info, true);
$prescription_ids[] = $extra_info['prescriptionId'];
}
// 如果没查到对应的缴费处方记录,直接跳出 // 如果没查到对应的缴费处方记录,直接跳出
if (empty($extra_info) || empty($prescription_ids)) { if (empty($extra_info) || empty($prescription_ids)) {
return; return;
} }
$this->info('处方记录信息:'.$order_info->order_id, [$prescription_ids]); $this->info('处方记录信息:'.$order_info->order_id, ['prescription_ids' => $prescription_ids]);
$data = [ $data = [
$order_info->patient_id, $order_info->patient_id,
'0', '0',
$extra_info['strVisitDate'], date('Y-m-d H:i:s'),
implode(',', $prescription_ids), $prescription_ids,
$extra_info['visitNumber'], $extra_info['visitNumber'],
'', '',
$order_info->order_id, $order_info->order_id,
PayType::WECHAT_PAY->hisCode(), PayType::WECHAT_PAY->hisCode(),
(string) ($order_info['total_fee'] / 100), (string) ($order_info['fee'] / 100),
(string) ($order_info['self_fee'] / 100) (string) ($order_info['self_fee'] / 100)
]; ];
$response = $this->his_client->confirmOutpatient(... $data); $response = $this->his_client->confirmOutpatient(... $data);

@ -8,12 +8,15 @@ use App\Dictionary\Order\SourceId;
use App\Dictionary\Order\Type; use App\Dictionary\Order\Type;
use App\Dictionary\Patient\CardType; use App\Dictionary\Patient\CardType;
use App\Exceptions\GeneralException; use App\Exceptions\GeneralException;
use App\Http\Resources\Outpatient\Pending\PendingListsResource;
use App\Models\Order; use App\Models\Order;
use App\Models\Patient; use App\Models\Patient;
use App\Services\HisHttp\Client; use App\Services\HisHttp\Client;
use App\Utils\Traits\BuildCacheKeyName;
use App\Utils\Traits\Logger; use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth; use App\Utils\Traits\MiniProgramAuth;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Support\Facades\Redis;
use ReflectionException; use ReflectionException;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use UnifyPayment\Cores\Exceptions\InvalidConfigException; use UnifyPayment\Cores\Exceptions\InvalidConfigException;
@ -26,6 +29,7 @@ class PaymentLogic
{ {
use Logger; use Logger;
use MiniProgramAuth; use MiniProgramAuth;
use BuildCacheKeyName;
private Client $his_client; private Client $his_client;
@ -49,21 +53,22 @@ class PaymentLogic
/** /**
* 支付 * 支付
* @param string $patient_number * @param string $patient_number
* @param string $serial_no
* @param string $prescription_ids * @param string $prescription_ids
* @return array * @return array
* @throws GeneralException * @throws GeneralException
*/ */
public function payment(string $patient_number, string $prescription_ids): array public function payment(string $patient_number, string $serial_no, string $prescription_ids): array
{ {
// 基础信息 // 基础信息
$patient_info = $this->getPatientInfo($this->open_id, $patient_number); $patient_info = $this->getPatientInfo($this->open_id, $patient_number);
$pending_info = $this->getPendingPrescriptionDetails($patient_info['patientId'], $prescription_ids); $pending_info = $this->getPendingPrescriptionDetails($patient_info['patientId'], $serial_no, $prescription_ids);
// 创建订单 // 创建订单
$order_type = Type::OUTPATIENT_PAYMENT; $order_type = Type::OUTPATIENT_PAYMENT;
$pay_type = PayType::WECHAT_PAY; $pay_type = PayType::WECHAT_PAY;
$order_id = $this->order_model->getOrderId($pay_type, 'M'); $order_id = $this->order_model->getOrderId($pay_type, 'M');
$total_fee = (float)(string) array_sum(array_column($pending_info, 'prescriptionAmount')); $total_fee = (float)(string) $pending_info['prescriptionAmount'];
$order = $this->createOrder($order_id, $pay_type, $total_fee, $order_type, $patient_info, $pending_info); $order = $this->createOrder($order_id, $pay_type, $total_fee, $order_type, $patient_info, $pending_info);
@ -90,7 +95,7 @@ class PaymentLogic
throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST); throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST);
} }
$response = $this->his_client->getPatientInfo($info['patient_id'], CardType::OUTPATIENT_NO, $info['name']); $response = $this->his_client->getPatientInfo($info['patient_number'], CardType::OUTPATIENT_NO, '');
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException($response['msg'] ?? '找不到患者信息,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '找不到患者信息,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
@ -106,40 +111,74 @@ class PaymentLogic
/** /**
* 获取缴费处方详情 * 获取缴费处方详情
* @param string $patient_id * @param string $patient_id
* @param string $serial_no
* @param string $prescription_ids * @param string $prescription_ids
* @return array * @return array
* @
* @throws GeneralException * @throws GeneralException
*/ */
protected function getPendingPrescriptionDetails(string $patient_id, string $prescription_ids): array protected function getPendingPrescriptionDetails(string $patient_id, string $serial_no, string $prescription_ids): array
{ {
// 缓存键值
$pending_lists_cache_key = $this->getOutpatientPendingListsKey($this->open_id, $patient_id);
$pending_details_cache_key = $this->getOutpatientPendingDetailsKey($this->open_id, $patient_id, $serial_no);
// 获取缓存
if (Redis::exists($pending_lists_cache_key)) {
$response = Redis::get($pending_lists_cache_key);
$response = json_decode($response, true);
}
// 如果缓存数据有问题
if (empty($response)) {
$response = $this->his_client->getPendingLists($patient_id); $response = $this->his_client->getPendingLists($patient_id);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
}
// 获取具体的缴费详情 // 获取具体缴费详情
$lists = [];
foreach ($response['response'] as $v) { foreach ($response['response'] as $v) {
if (str_contains($prescription_ids, $v['prescriptionId'])) { if (
$lists[] = $v; str_contains($prescription_ids, $v['prescriptionId']) &&
$serial_no == $v['visitNumber']
) {
if (empty($lists)) {
$lists = $v;
$lists['prescription_ids'] = $v['prescriptionId'];
$lists['prescription_numbers'] = $v['nrescriptionNumber'];
// 去除无用信息
unset($lists['idCardNo'], $lists['singleAmount'], $lists['prescriptionId'], $lists['nrescriptionNumber']);
} else {
// 拼接处方号
$lists['prescription_ids'] .= ','. $v['prescriptionId'];
$lists['prescription_numbers'] .= ','. $v['nrescriptionNumber'];
}
} }
} }
if (empty($lists)) { if (empty($lists) || array_diff(explode(',', $lists['prescription_ids']), explode(',', $prescription_ids))) {
throw new GeneralException('查询不到待缴费处方,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException('查询不到待缴费处方,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
// 获取缓存
if (Redis::exists($pending_details_cache_key)) {
$response = Redis::get($pending_details_cache_key);
$response = json_decode($response, true);
}
// 如果缓存数据有问题
if (empty($response)) {
$response = $this->his_client->getPendingDetails($prescription_ids, $serial_no, $lists['regId'] ?: '');
foreach ($lists as $k => $v) {
$response = $this->his_client->getPendingDetails($v['prescriptionId'], $v['visitNumber'], $v['regId'] ?: '');
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
$lists[$k]['prescription_lists'] = $response['response'];
} }
$lists['prescription_lists'] = $response['response'];
$this->info('缴费处方信息', $lists); $this->info('缴费处方信息', $lists);
return $lists; return $lists;
} }
@ -157,22 +196,18 @@ class PaymentLogic
*/ */
protected function createOrder(string $order_id, PayType $pay_type, float $total_fee, Type $order_type, array $patient_info, array $pending_info): mixed protected function createOrder(string $order_id, PayType $pay_type, float $total_fee, Type $order_type, array $patient_info, array $pending_info): mixed
{ {
// 挂号记录表 // 挂号记录表
$pay_record_data = []; $pay_record_data = [
foreach ($pending_info as $v) {
$pay_record_data[] = [
'relate_patient_id' => $patient_info['id'], 'relate_patient_id' => $patient_info['id'],
'dept_id' => $v['treatmentDepartment'], 'dept_id' => $pending_info['treatmentDepartment'],
'dept_name' => $v['departmentName'], 'dept_name' => $pending_info['departmentName'],
'doctor_id' => reset($v['prescription_lists'])['doctorNumber'] ?? '', 'doctor_id' => $pending_info['doctorId'],
'doctor_name' => $v['doctorName'], 'doctor_name' => $pending_info['doctorName'],
'visit_date' => date('Y-m-d', strtotime($v['visitDate'])), 'visit_date' => date('Y-m-d', strtotime($pending_info['visitDate'])),
'total_amount' => $v['prescriptionAmount'] * 100, 'total_amount' => $pending_info['prescriptionAmount'] * 100,
'pre_settle_status' => 0, 'pre_settle_status' => 0,
'extra_info' => json_encode($v, JSON_UNESCAPED_UNICODE), 'extra_info' => json_encode($pending_info, JSON_UNESCAPED_UNICODE),
]; ];
}
$order = $this->order_model->createOrder( $order = $this->order_model->createOrder(
$patient_info['id'], $patient_info['id'],
@ -216,7 +251,7 @@ class PaymentLogic
$patient_id. '|'. $patient_name, $patient_id. '|'. $patient_name,
$order_type->unifyOrderType(), $order_type->unifyOrderType(),
$this->open_id, $this->open_id,
url('/Api/Notify', [], true) config('custom.payment_notify_url')
); );
$response = Unify::pay(config('unify'))->mini->jsapi($order_obj); $response = Unify::pay(config('unify'))->mini->jsapi($order_obj);

@ -4,20 +4,26 @@ declare(strict_types = 1);
namespace App\Http\Logics\Outpatient; namespace App\Http\Logics\Outpatient;
use App\Exceptions\GeneralException; use App\Exceptions\GeneralException;
use App\Models\Patient;
use App\Services\HisHttp\Client; use App\Services\HisHttp\Client;
use App\Utils\Traits\BuildCacheKeyName;
use App\Utils\Traits\Logger; use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth; use App\Utils\Traits\MiniProgramAuth;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
class PendingLogic class PendingLogic
{ {
use Logger; use Logger;
use MiniProgramAuth; use MiniProgramAuth;
use BuildCacheKeyName;
private Client $his_client; private Client $his_client;
private Patient $patient_model;
/** /**
* RecordLogic Construct * RecordLogic Construct
* @throws AuthenticationException * @throws AuthenticationException
@ -26,38 +32,50 @@ class PendingLogic
{ {
$this->authInitialize(); $this->authInitialize();
$this->his_client = app('HisHttpService'); $this->his_client = app('HisHttpService');
$this->patient_model = new Patient();
} }
/** /**
* 获取挂号记录列表 * 获取待缴费记录列表
* @param string $patient_id * @param string $patient_number
* @return array * @return array
* @throws GeneralException * @throws GeneralException
*/ */
public function getLists(string $patient_id,): array public function getLists(string $patient_number): array
{ {
$patient_info = $this->getPatientInfo($this->open_id, $patient_number);
$patient_id = $patient_info->patient_id;
$response = $this->his_client->getPendingLists($patient_id); $response = $this->his_client->getPendingLists($patient_id);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
// 如果未查询到信息,则返回空数组数据
if ($response['msg'] === '查询就诊记录失败:查询结果没记录') {
return [];
}
throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
// 缓存2小时 // 缓存2小时
Cache::set('outpatient.pending.'. $this->open_id.'.'. $patient_id, json_encode($response, JSON_UNESCAPED_UNICODE), 2 * 60 * 60); Redis::setnx($this->getOutpatientPendingListsKey($this->open_id, $patient_id), 7200, json_encode($response, JSON_UNESCAPED_UNICODE));
return $response; return $response;
} }
/** /**
* 获取缴费记录详情 * 获取缴费记录详情
* @param string $patient_id * @param string $patient_number
* @param string $serial_no * @param string $serial_no
* @param string $prescription_ids * @param string $prescription_ids
* @param string $reg_id * @param string $reg_id
* @return array * @return array
* @throws GeneralException * @throws GeneralException
*/ */
public function getDetails(string $patient_id, string $serial_no, string $prescription_ids, string $reg_id): array public function getDetails(string $patient_number, string $serial_no, string $prescription_ids, string $reg_id): array
{ {
$patient_info = $this->getPatientInfo($this->open_id, $patient_number);
$patient_id = $patient_info->patient_id;
$this->getCachePendingLists($patient_id, $serial_no); $this->getCachePendingLists($patient_id, $serial_no);
$response = $this->his_client->getPendingDetails($prescription_ids, $serial_no, $reg_id); $response = $this->his_client->getPendingDetails($prescription_ids, $serial_no, $reg_id);
@ -66,6 +84,8 @@ class PendingLogic
throw new GeneralException($response['msg'] ?? '暂无相关缴费详情!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '暂无相关缴费详情!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
// 缓存2小时
Redis::setnx($this->getOutpatientPendingDetailsKey($this->open_id, $patient_id, $serial_no), 7200, json_encode($response, JSON_UNESCAPED_UNICODE));
return $response; return $response;
} }
@ -78,19 +98,28 @@ class PendingLogic
*/ */
protected function getCachePendingLists(string $patient_id, string $serial_no): mixed protected function getCachePendingLists(string $patient_id, string $serial_no): mixed
{ {
$cache_key = 'outpatient.pending.'. $this->open_id.'.'. $patient_id; // 缓存键值
$cache_key = $this->getOutpatientPendingListsKey($this->open_id, $patient_id);
$pending_lists = Cache::get($cache_key); // 获取缓存
if (empty($pending_lists)) { if (Redis::exists($cache_key)) {
throw new GeneralException('查询不到缴费记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); $response = Redis::get($cache_key);
$response = json_decode($response, true);
}
// 如果缓存数据有问题
if (empty($response)) {
$response = $this->his_client->getPendingLists($patient_id);
if (!isset($response['success']) || !$response['success']) {
throw new GeneralException($response['msg'] ?? '查询不到缴费记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE);
}
} }
$pending_lists = json_decode($pending_lists, true);
// 获取具体的缴费详情 // 获取具体的缴费详情
foreach ($pending_lists['response'] as $v) { foreach ($response['response'] as $v) {
if ($v['visitNumber'] === $serial_no) { if ($v['visitNumber'] === $serial_no) {
$info = $v; $info[] = $v;
break;
} }
} }
@ -100,4 +129,21 @@ class PendingLogic
return $info; return $info;
} }
/**
* 获取患者信息
* @param string $open_id
* @param string $patient_number
* @return mixed
* @throws GeneralException
*/
protected function getPatientInfo(string $open_id, string $patient_number): mixed
{
$info = $this->patient_model->getBindPatientInfoByPatientNumber($open_id, $patient_number);
if (empty($info)) {
throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST);
}
return $info;
}
} }

@ -6,6 +6,7 @@ namespace App\Http\Logics\Outpatient;
use App\Exceptions\GeneralException; use App\Exceptions\GeneralException;
use App\Models\Patient; use App\Models\Patient;
use App\Services\HisHttp\Client; use App\Services\HisHttp\Client;
use App\Utils\Traits\BuildCacheKeyName;
use App\Utils\Traits\Logger; use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth; use App\Utils\Traits\MiniProgramAuth;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
@ -16,6 +17,7 @@ class RecordLogic
{ {
use Logger; use Logger;
use MiniProgramAuth; use MiniProgramAuth;
use BuildCacheKeyName;
private Patient $patient_model; private Patient $patient_model;
@ -48,6 +50,11 @@ class RecordLogic
$response = $this->his_client->getPaidLists($patient_id, $start_date, $end_date); $response = $this->his_client->getPaidLists($patient_id, $start_date, $end_date);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
// 如果未查询到信息,则返回空数组数据
if ($response['msg'] === '门诊费用记录查询失败:查询结果没记录') {
return [];
}
throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '暂无相关缴费记录!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
@ -59,7 +66,8 @@ class RecordLogic
} }
// 缓存2小时 // 缓存2小时
Redis::setex('Outpatient.Record.'. $this->open_id.'.'. $patient_id, 2 * 60 * 60, json_encode($response, JSON_UNESCAPED_UNICODE)); $cache_key = $this->getOutpatientPendingListsKey($this->open_id, $patient_id);
Redis::setex($cache_key, 2 * 60 * 60, json_encode($response, JSON_UNESCAPED_UNICODE));
return $response; return $response;
} }
@ -95,9 +103,9 @@ class RecordLogic
*/ */
protected function getCacheRecordInfo(string $patient_id, string $serial_no): mixed protected function getCacheRecordInfo(string $patient_id, string $serial_no): mixed
{ {
$cache_key = 'Outpatient.Record.'. $this->open_id.'.'. $patient_id; $cache_key = $this->getOutpatientPendingDetailsKey($this->open_id, $patient_id, $serial_no);
$record_info = Redis::get($cache_key); $record_info = Redis::get($cache_key);
if (empty($record_info)) { if (empty($record_info)) {
throw new GeneralException($response['msg'] ?? '查询不到缴费记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '查询不到缴费记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE);
} }

@ -62,7 +62,7 @@ class PatientLogic
} }
// 获取患者信息 // 获取患者信息
$response = $this->his_client->getPatientInfo($info['patient_number'], CardType::OUTPATIENT_NO, $info['name']); $response = $this->his_client->getPatientInfo($info['patient_number'], CardType::OUTPATIENT_NO, '');
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException($response['msg'] ?? '找不到该就诊卡!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '找不到该就诊卡!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
@ -115,30 +115,13 @@ class PatientLogic
throw new GeneralException('该微信达到绑定卡上限!'); throw new GeneralException('该微信达到绑定卡上限!');
} }
// 查询患者信息 // 建档 (已建档的情况下,返回的是患者已建档案里最新的档案)
$response = $this->his_client->getPatientInfo($data['card_no'], $card_type, $data['name']);
$this->info('查询患者信息:', $response);
if (!isset($response['success']) || !$response['success']) {
$patient_id = &$response['response']['patientNumber'];
// 查询是否已绑定
$result = $this->patient_model->getPatientInfoByPatientId($patient_id);
if ($result && $result['open_id'] == $this->open_id) {
throw new GeneralException('您已绑定该就诊卡号!');
}
if ($result && $result['open_id'] != $this->open_id) {
throw new GeneralException('该卡号已被其他微信用户绑定!');
}
} else {
// 查询失败,走建档
$response = $this->his_client->registerCard( $response = $this->his_client->registerCard(
$data['card_no'], $data['card_no'],
$card_type, $card_type,
$data['name'], $data['name'],
$sex, $sex,
$birthday, date('Ymd', strtotime($birthday)),
$data['card_no'], $data['card_no'],
$data['phone'], $data['phone'],
$data['address'] $data['address']
@ -148,10 +131,21 @@ class PatientLogic
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException('建档失败,失败原因:'. $response['msg'] ?? '未知错误', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException('建档失败,失败原因:'. $response['msg'] ?? '未知错误', Response::HTTP_SERVICE_UNAVAILABLE);
} }
$patient_number = $response['response']['patientNumber'];
// 查询是否已绑定
$result = $this->patient_model->getPatientInfoByPatientNumber($patient_number);
if ($result && $result['open_id'] == $this->open_id) {
throw new GeneralException('您已绑定该就诊卡号!');
}
if ($result && $result['open_id'] != $this->open_id) {
throw new GeneralException('该卡号已被其他微信用户绑定!');
} }
// 再查一遍接口 获取患者信息 // 再查一遍接口 获取患者信息
$response = $this->his_client->getPatientInfo($data['card_no'], $card_type, $data['name']); $response = $this->his_client->getPatientInfo($data['card_no'], $card_type, $data['name'], $patient_number);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException('建档失败,失败原因:'. $response['msg'] ?? '未知错误', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException('建档失败,失败原因:'. $response['msg'] ?? '未知错误', Response::HTTP_SERVICE_UNAVAILABLE);
} }
@ -188,40 +182,33 @@ class PatientLogic
throw new GeneralException('该微信达到绑定卡上限!'); throw new GeneralException('该微信达到绑定卡上限!');
} }
// 查询是否已绑定
$result = $this->patient_model->getPatientInfoByPatientNumber($data['patient_id']);
if ($result && $result['open_id'] == $this->open_id) {
throw new GeneralException('您已绑定该就诊卡号!');
}
if ($result && $result['open_id'] != $this->open_id) {
throw new GeneralException('该卡号已被其他微信用户绑定!');
}
// 查询患者信息 // 查询患者信息
$response = $this->his_client->getPatientInfo($data['card_no'], $card_type, $data['name']); $response = $this->his_client->getPatientInfo($data['card_no'], $card_type, $data['name'], $data['patient_id']);
$this->info('查询患者信息:', $response); $this->info('查询患者信息:', $response);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
// 修改提示语句
if ($response['msg'] === '获取病人信息失败,查询记录为空') {
$response['msg'] = '该证件号码未建档或就诊卡号不存在!';
}
throw new GeneralException($response['msg'] ?? '未知错误'); throw new GeneralException($response['msg'] ?? '未知错误');
} }
$patient_info = &$response['response']; $patient_info = &$response['response'];
$patient_id = &$patient_info['patientId']; $patient_id = &$patient_info['patientId'];
$patient_number = &$patient_info['patientNumber']; $patient_number = &$patient_info['patientNumber'];
$sex = Sex::from((int) $patient_info['sex']); $sex = Sex::tryFrom((int) $patient_info['sex']) ?: Sex::UNKNOWN;
if ($patient_info['patientNumber'] != $data['patient_id']) {
throw new GeneralException('该证件号已建档,但就诊卡号不匹配!');
}
if ($patient_info['name'] != $data['name']) {
throw new GeneralException('该证件号已建档,但姓名不匹配!');
}
if ($patient_info['cardNo'] != $data['card_no']) {
throw new GeneralException('该就诊号已建档,但证件号码不匹配!');
}
// 查询是否已绑定
$result = $this->patient_model->getPatientInfoByPatientId($data['patient_id']);
if ($result && $result['openid'] == $this->open_id) {
throw new GeneralException('您已绑定该就诊卡号!');
}
if ($result && $result['openid'] != $this->open_id) {
throw new GeneralException('该卡号已被其他微信用户绑定!');
}
// 写入数据库 // 写入数据库
$result = $this->patient_model->createPatient($this->union_id, $this->open_id, $patient_id, $patient_number, $data['name'], $sex); $result = $this->patient_model->createPatient($this->union_id, $this->open_id, $patient_id, $patient_number, $data['name'], $sex);
@ -273,6 +260,12 @@ class PatientLogic
throw new GeneralException('解绑失败,请稍后再试!', Response::HTTP_INTERNAL_SERVER_ERROR); throw new GeneralException('解绑失败,请稍后再试!', Response::HTTP_INTERNAL_SERVER_ERROR);
} }
// 如果删除了默认卡,那么重新设置默认卡
$default = $this->patient_model->getBindDefaultPatientInfo($this->open_id);
if (!empty($default) && $default->def_status == 0) {
$this->patient_model->setDefaultPatient($this->open_id, $default->patient_id);
}
$this->sendUnbindPatientSubscribeMessage($this->open_id, $info->id, $info['name'], ' ', $patient_number); $this->sendUnbindPatientSubscribeMessage($this->open_id, $info->id, $info['name'], ' ', $patient_number);
return true; return true;
} }

@ -14,6 +14,7 @@ use App\Models\RegistrationRecord;
use App\Services\HisHttp\Client; use App\Services\HisHttp\Client;
use App\Utils\Traits\Logger; use App\Utils\Traits\Logger;
use App\Utils\Traits\MiniProgramAuth; use App\Utils\Traits\MiniProgramAuth;
use App\Utils\Traits\SendSubscribeMessage;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use ReflectionException; use ReflectionException;
@ -24,6 +25,7 @@ use UnifyPayment\Unify;
class RecordLogic class RecordLogic
{ {
use Logger; use Logger;
use SendSubscribeMessage;
use MiniProgramAuth; use MiniProgramAuth;
private Client $his_client; private Client $his_client;
@ -64,6 +66,11 @@ class RecordLogic
$response = $this->his_client->getRegisterRecordLists($patient_id, $start_date, $end_date); $response = $this->his_client->getRegisterRecordLists($patient_id, $start_date, $end_date);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
// 如果未查询到信息,则返回空数组数据
if ($response['msg'] === '查询挂号记录信息失败,查询结果没记录') {
return [];
}
throw new GeneralException($response['msg'] ?? '暂无相关挂号记录!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '暂无相关挂号记录!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
@ -115,16 +122,19 @@ class RecordLogic
$this->info('患者需退号的挂号记录', $info); $this->info('患者需退号的挂号记录', $info);
// 查询小程序上的挂号记录 // 查询小程序上的挂号记录
$reg_record = $this->reg_record_model->getRecordByRegID($reg_serial_no); $order_info = $this->order_model->getOrderInfoByHisOrderId($reg_serial_no);
if (empty($reg_record) || empty($reg_record->order()->order_id)) { if (empty($order_info)) {
throw new GeneralException('非小程序渠道挂号,请在人工窗口退号退费处理', Response::HTTP_SERVICE_UNAVAILABLE);
}
if ($this->open_id !== $order_info->open_id) {
throw new GeneralException('非小程序渠道挂号,请在人工窗口退号退费处理', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException('非小程序渠道挂号,请在人工窗口退号退费处理', Response::HTTP_SERVICE_UNAVAILABLE);
} }
$order_info = &$reg_record->order(); $order_id = $order_info->order_id;
$order_id = &$order_info->order_id; $fee = $order_info->self_fee;
$fee = &$order_info->self_fee;
$this->info('患者需退号的数据库挂号记录', $reg_record->toArray()); $this->info('患者需退号的数据库挂号记录', $order_info->toArray());
// 检查是否可以退号 // 检查是否可以退号
$response = $this->his_client->checkRefundRegisterStatus($reg_serial_no); $response = $this->his_client->checkRefundRegisterStatus($reg_serial_no);
@ -153,20 +163,20 @@ class RecordLogic
$this->open_id, $this->open_id,
$patient_id, $patient_id,
$order_info->patient_name, $order_info->patient_name,
Type::from($order_info->order_type), Type::from($order_info->type),
SourceId::from($order_info->source_id) SourceId::from($order_info->source_id)
); );
$this->info('创建退款订单', ['id' => $refund_order_info->id]); $this->info('创建退款订单', ['id' => $refund_order_info->id]);
if (empty($refund_order_info)) { if (empty($refund_order_info)) {
throw new GeneralException($response['msg'] ?? '退号成功,退费失败,请重新再试!', Response::HTTP_BAD_REQUEST); throw new GeneralException('退号成功,退费失败,请重新再试!', Response::HTTP_BAD_REQUEST);
} }
// 非免费号,需要退费 // 非免费号,需要退费
if ($fee > 0) { if ($fee > 0) {
// 退款 // 退款
try { try {
$refund_order_obj = new RefundOrder($order_id, $refund_order_id, $fee, '患者自行退号退费'); $refund_order_obj = new RefundOrder($order_id, $refund_order_id, (string) ($fee / 100), '患者自行退号退费');
$response = Unify::common(config('unify'))->order->refund($refund_order_obj); $response = Unify::common(config('unify'))->order->refund($refund_order_obj);
$this->info('退号退费结果', $response); $this->info('退号退费结果', $response);
@ -184,6 +194,10 @@ class RecordLogic
} }
$this->order_model->reverseOrderOpera($refund_order_id, $fee, true); $this->order_model->reverseOrderOpera($refund_order_id, $fee, true);
// 推送挂号取消记录
$this->sendRegistrationCancelMessage($this->order_model);
return true; return true;
} }

@ -8,6 +8,7 @@ use App\Dictionary\Order\SourceId;
use App\Dictionary\Order\Type; use App\Dictionary\Order\Type;
use App\Dictionary\Patient\CardType; use App\Dictionary\Patient\CardType;
use App\Exceptions\GeneralException; use App\Exceptions\GeneralException;
use App\Models\Admin\Department;
use App\Models\Order; use App\Models\Order;
use App\Models\Patient; use App\Models\Patient;
use App\Services\HisHttp\Client; use App\Services\HisHttp\Client;
@ -101,7 +102,7 @@ class RegisterLogic
throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST); throw new GeneralException('找不到患者信息,请重新再试!', Response::HTTP_BAD_REQUEST);
} }
$response = $this->his_client->getPatientInfo($info['patient_id'], CardType::OUTPATIENT_NO, $info['name']); $response = $this->his_client->getPatientInfo($info['patient_number'], CardType::OUTPATIENT_NO, '');
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
throw new GeneralException($response['msg'] ?? '找不到患者信息,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '找不到患者信息,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
@ -154,7 +155,7 @@ class RegisterLogic
} }
// 获取科室名称 // 获取科室名称
if (Redis::exists('departments.'. $date)) { /*if (Redis::exists('departments.'. $date)) {
$dept_lists = Redis::get('departments.'. $date); $dept_lists = Redis::get('departments.'. $date);
$dept_lists = json_decode($dept_lists, true); $dept_lists = json_decode($dept_lists, true);
} else { } else {
@ -170,8 +171,17 @@ class RegisterLogic
$info['dept_id'] = $v['typeId']; $info['dept_id'] = $v['typeId'];
$info['dept_name'] = $v['typeName']; $info['dept_name'] = $v['typeName'];
} }
}*/
// 获取科室名称
$department_info = Department::where('dept_id', $dept_id)->where('is_enable', 1)->first();
if ($department_info->isEmpty()){
throw new GeneralException($schedule_info['msg'] ?? '找不到该号源,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE);
} }
$info['dept_id'] = $department_info['dept_id'];
$info['dept_name'] = $department_info['dept_name'];
$this->info('挂号排班信息', $info); $this->info('挂号排班信息', $info);
return $info; return $info;
} }
@ -299,7 +309,7 @@ class RegisterLogic
$patient_id. '|'. $patient_name, $patient_id. '|'. $patient_name,
$order_type->unifyOrderType(), $order_type->unifyOrderType(),
$this->open_id, $this->open_id,
url('/Api/Notify', [], true) config('custom.payment_notify_url')
); );
$response = Unify::pay(config('unify'))->mini->jsapi($order_obj); $response = Unify::pay(config('unify'))->mini->jsapi($order_obj);

@ -55,6 +55,11 @@ class ScheduleLogic
$response = $this->his_client->getDoctorLists($dept_id, $type, '', $date); $response = $this->his_client->getDoctorLists($dept_id, $type, '', $date);
if (!isset($response['success']) || !$response['success']) { if (!isset($response['success']) || !$response['success']) {
// 如果未查询到信息,则返回空数组
if ($response['msg'] == '查询医生排班失败,查询结果没记录ORA-0000: NORMAL, SUCCESSFUL COMPLETION') {
return [];
}
throw new GeneralException($response['msg'] ?? '该科室暂无医生排班!', Response::HTTP_SERVICE_UNAVAILABLE); throw new GeneralException($response['msg'] ?? '该科室暂无医生排班!', Response::HTTP_SERVICE_UNAVAILABLE);
} }

@ -42,7 +42,7 @@ class RecordApiLog
// 回调消息获取request_data // 回调消息获取request_data
if (stripos($request->url, 'notify') !== false) { if (stripos($request->url, 'notify') !== false) {
$request_data = file_get_contents('php://input') ?: file_get_contents('php://temp'); $request_data = $request->getContent();
} else { } else {
$request_data = request()->all(); $request_data = request()->all();
} }

@ -14,15 +14,19 @@ class ItemDetailsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource['ITEM'] as $v) { foreach ($this->resource['response'] as $v) {
$lists[] = [ $lists[] = [
'type_name' => $v['TYPENAME'], 'type_name' => $v['typeName'],
'item_name' => $v['COSTNAME'], 'item_name' => $v['costName'],
'unit' => $v['UNIT'], 'unit' => $v['unit'],
'spec' => $v['COSTSPEC'], 'spec' => $v['costSpec'],
'price' => $v['PRICE'], 'price' => (float) $v['price'],
'cd_name' => $v['CDNAME'] ?? '', 'cd_name' => $v['manufacturer'] ?? '',
]; ];
} }

@ -14,6 +14,10 @@ class ItemListsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource['response'] as $v) { foreach ($this->resource['response'] as $v) {
$lists[] = [ $lists[] = [

@ -15,6 +15,10 @@ class PendingDetailsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource['response'] as $v) { foreach ($this->resource['response'] as $v) {
@ -26,8 +30,8 @@ class PendingDetailsResource extends JsonResource
'price' => (float) $v['unitPrice'], 'price' => (float) $v['unitPrice'],
'quantity' => $v['quantity'], 'quantity' => $v['quantity'],
'unit' => $v['company'], 'unit' => $v['company'],
'spec' => $v['projectSpecifications'], 'spec' => $v['projectSpecifications'] ?: '',
'total_price' => $v['money'], 'total_price' => (float) $v['money'],
'prescription_id' => $v['prescriptionNumber'], 'prescription_id' => $v['prescriptionNumber'],
'prescription_type' => $v['prescriptionType'], 'prescription_type' => $v['prescriptionType'],
'dept_id' => $v['treatmentDepartment'], 'dept_id' => $v['treatmentDepartment'],

@ -15,27 +15,43 @@ class PendingListsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource['response'] as $v) { foreach ($this->resource['response'] as $v) {
$lists[] = [ // 按就诊编号合并处方
if (!isset($lists[$v['visitNumber']])) {
$lists[$v['visitNumber']] = [
'category' => $v['visitType'], 'category' => $v['visitType'],
'visit_date' => date('Y-m-d', strtotime($v['visitDate'])), 'visit_date' => date('Y-m-d', strtotime($v['visitDate'])),
'diagnosis' => $v['outpatientDiagnosis'], 'diagnosis' => $v['outpatientDiagnosis'],
'dept_id' => $v['treatmentDepartment'], 'dept_id' => $v['treatmentDepartment'],
'dept_name' => $v['departmentName'], 'dept_name' => $v['departmentName'],
'reg_id' => $v['regId'], 'reg_id' => $v['regId'],
'prescription_id' => $v['prescriptionId'], 'prescription_ids' => $v['prescriptionId'],
'total_prescription_amount' => (float) $v['prescriptionAmount'], 'total_prescription_amount' => (float) $v['prescriptionAmount'],
'single_prescription_amount' => (float) $v['singleAmount'],
'doctor_name' => $v['doctorName'], 'doctor_name' => $v['doctorName'],
'remark' => $v['remarks'], 'remark' => $v['remarks'],
'is_self_pay' => $v['isexpense'], 'is_self_pay' => $v['isexpense'],
'prescription_number' => $v['nrescriptionNumber'], 'prescription_numbers' => $v['nrescriptionNumber'],
'exec_address' => $v['takeMedicine'] ?: '', 'exec_address' => $v['takeMedicine'] ?: '',
'visit_no' => $v['visitNumber'], 'visit_no' => $v['visitNumber'],
]; ];
} else {
// 拼接处方号
$lists[$v['visitNumber']]['prescription_ids'] .= ','. $v['prescriptionId'];
$lists[$v['visitNumber']]['prescription_numbers'] .= ','. $v['nrescriptionNumber'];
}
// 子处方列表
$lists[$v['visitNumber']]['prescription_lists'][] = [
'prescription_id' => $v['prescriptionId'],
'single_prescription_amount' => (float) $v['singleAmount'],
];
} }
return $lists; return array_values($lists);
} }
} }

@ -15,6 +15,10 @@ class RecordDetailsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$this->resource = $this->resource['response']; $this->resource = $this->resource['response'];
$info = [ $info = [
@ -31,15 +35,16 @@ class RecordDetailsResource extends JsonResource
'charge_user' => $this->resource['chargeStaff'], 'charge_user' => $this->resource['chargeStaff'],
]; ];
foreach ($this->resource['outpatientDetail']['outpatientItemreList'] as $v) { foreach ($this->resource['outpatientDetail'] as $v) {
$v = reset($v['outpatientItemreList']);
$info['item_lists'][] = [ $info['item_lists'][] = [
'visit_date' => $v['visitdate'], 'visit_date' => $v['visitdate'],
'category_name' => $v['classname'], 'category_name' => $v['classname'],
'item_name' => $v['itemname'], 'item_name' => $v['itemname'],
'spec' => $v['itemspec'], 'spec' => $v['itemspec'] ?: '',
'unit' => $v['units'], 'unit' => $v['units'],
'quantity' => (int) $v['amount'], 'quantity' => (int) $v['amount'],
'price' => (float) $v['arice'], 'price' => (float) $v['price'],
'total_price' => (float) $v['costs'], 'total_price' => (float) $v['costs'],
// 冗余字段 // 冗余字段

@ -15,6 +15,10 @@ class RecordListsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource['response'] as $v) { foreach ($this->resource['response'] as $v) {
$lists[] = [ $lists[] = [

@ -14,6 +14,10 @@ class PatientListsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource as $v) { foreach ($this->resource as $v) {
$lists[] = [ $lists[] = [

@ -14,12 +14,17 @@ class RecordListsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$lists = []; $lists = [];
foreach ($this->resource['response'] as $v) { foreach ($this->resource['response'] as $v) {
$lists[] = [ $lists[] = [
'reg_serial_no' => $v['visitNo'], 'reg_serial_no' => $v['visitNo'],
'reg_type' => $v['registrationType'], 'reg_type' => $v['registrationType'],
'reg_date' => $v['registrationDate'], //'reg_date' => $v['registrationDate'],
'reg_date' => $v['regDate'],
'patient_id' => $v['patientId'], 'patient_id' => $v['patientId'],
'patient_name' => $v['patientName'], 'patient_name' => $v['patientName'],
'dept_id' => $v['depId'], 'dept_id' => $v['depId'],

@ -21,23 +21,25 @@ class DeptListsResource extends JsonResource
$categories = $this->getDepartmentCategoryLists(); $categories = $this->getDepartmentCategoryLists();
// 科室及排序 // 科室及排序
$departments = $this->getDepartmentLists(); $departments = $this->getDepartmentLists();
$sorts = collect($departments)->pluck('sort', 'dept_id')->toArray();
// 根据科室的 sort 字段对 科室列表 进行排序 foreach ($departments as $v) {
usort($this->resource['response'], function ($a, $b) use ($sorts) { // 检查 departments 中是否存在当前 typeId
$sort_a = $sorts[$a['typeId']] ?? 0; if (!isset($departments[$v['dept_id']])) {
$sort_b = $sorts[$b['typeId']] ?? 0; continue;
return $sort_b <=> $sort_a; // 倒序排序 }
});
$department = $departments[$v['dept_id']];
foreach ($this->resource['response'] as $v) { // 检查 category_id 是否设置且在 categories 中存在
if (!isset($categories[$departments[$v['typeId']]['category_id']])) { if (!isset($department['category_id']) || !isset($categories[$department['category_id']])) {
continue; continue;
} }
$categories[$departments[$v['typeId']]['category_id']]['item_lists'][] = [ $categories[$departments[$v['dept_id']]['category_id']]['item_lists'][] = [
'dept_id' => $v['typeId'], 'dept_id' => $v['dept_id'],
'dept_name' => $v['typeName'], 'dept_name' => $v['dept_name'],
'is_emergency' => $v['is_emergency'],
'show_title_tags' => $departments[$v['dept_id']]['show_title_tags'] ?? ''
// 'dept_intro' => $v['introduce'] ?? '' // 'dept_intro' => $v['introduce'] ?? ''
]; ];
} }
@ -68,7 +70,7 @@ class DeptListsResource extends JsonResource
} }
/** /**
* 获取医生列表 * 获取科室列表
* @return array * @return array
*/ */
public function getDepartmentLists(): array public function getDepartmentLists(): array

@ -16,17 +16,29 @@ class DoctorListsResource extends JsonResource
*/ */
public function toArray(Request $request = null): array public function toArray(Request $request = null): array
{ {
if (empty($this->resource)) {
return [];
}
$doctors = $this->getDoctorLists(); $doctors = $this->getDoctorLists();
$sort = collect($doctors)->pluck('sort', 'doctor_id'); $sort = collect($doctors)->pluck('sort', 'doctor_id');
$lists = []; $lists = [];
foreach ($this->resource['response'] as $k=>$v) { foreach ($this->resource['response'] as $k => $v) {
// 医生头像
if (!empty($doctors[$v['doctId']]['avatar'])) {
$doctor_avatar = getAdminUploadImageUrl($doctors[$v['doctId']]['avatar'], 'doctor_avatar');
} else {
$doctor_avatar = '';
}
$lists[$k] = [ $lists[$k] = [
'doctor_id' => $v['doctId'], 'doctor_id' => $v['doctId'],
'doctor_name' => $v['doctName'], 'doctor_name' => $v['doctName'],
'doctor_title' => $v['docTitle'], 'doctor_title' => $v['docTitle'],
'doctor_intro' => $doctors[$v['doctId']]['doctor_specialty'] ?? ($v['depLocation'] ?: '暂无介绍'), 'doctor_specialty' => $doctors[$v['doctId']]['doctor_specialty'] ?? '暂无介绍',
'doctor_avatar' => $doctors[$v['doctId']]['avatar'] ?: '', 'doctor_intro' => $doctors[$v['doctId']]['introduction'] ?? ($v['depLocation'] ?: '暂无介绍'),
'doctor_avatar' => $doctor_avatar,
'is_doctor' => (int) $v['isksDoc'], 'is_doctor' => (int) $v['isksDoc'],
]; ];

@ -34,8 +34,10 @@ class Department extends Model
'category_id', 'category_id',
'building_id', 'building_id',
'dept_location', 'dept_location',
'show_title_tags',
'icon', 'icon',
'introduction', 'introduction',
'is_emergency',
'sort', 'sort',
'is_enable' 'is_enable'
]; ];
@ -49,6 +51,7 @@ class Department extends Model
'id' => 'integer', 'id' => 'integer',
'category_id' => 'integer', 'category_id' => 'integer',
'sort' => 'integer', 'sort' => 'integer',
'is_emergency' => 'integer',
'is_enable' => 'integer', 'is_enable' => 'integer',
]; ];

@ -102,11 +102,11 @@ class Order extends Model
/** /**
* Relationships OutpatientPaymentRecord Model. * Relationships OutpatientPaymentRecord Model.
* @return hasMany * @return hasOne
*/ */
public function outpatientPaymentRecord(): hasMany public function outpatientPaymentRecord(): hasOne
{ {
return $this->hasMany(OutpatientPaymentRecord::class, 'relate_order_id'); return $this->hasOne(OutpatientPaymentRecord::class, 'relate_order_id');
} }
/** /**
@ -161,6 +161,16 @@ class Order extends Model
return $this->where('order_id', $order_id)->with('patient')->first(); return $this->where('order_id', $order_id)->with('patient')->first();
} }
/**
* 获取订单详情by his_order_id
* @param string $his_order_id
* @return mixed
*/
public function getOrderInfoByHisOrderId(string $his_order_id): mixed
{
return $this->where('his_order_id', $his_order_id)->first();
}
/** /**
* 创建订单 * 创建订单
* @param int $relate_patient_id * @param int $relate_patient_id
@ -215,7 +225,7 @@ class Order extends Model
$result->registrationRecord()->create($record_info); $result->registrationRecord()->create($record_info);
break; break;
case Type::OUTPATIENT_PAYMENT->value: case Type::OUTPATIENT_PAYMENT->value:
$result->outpatientPaymentRecord()->createMany($record_info); $result->outpatientPaymentRecord()->create($record_info);
break; break;
default: default:
break; break;
@ -294,12 +304,10 @@ class Order extends Model
break; break;
case Type::OUTPATIENT_PAYMENT->value: case Type::OUTPATIENT_PAYMENT->value:
$record = $order->outpatientPaymentRecord; $record = $order->outpatientPaymentRecord;
$extra_info = json_decode($record->extra_info, true);
foreach ($record as $v) {
$extra_info = json_decode($v->extra_info, true);
$extra_info['confirm_response'] = $response; $extra_info['confirm_response'] = $response;
$v->update(['extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]);
} $record->update(['extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]);
break; break;
default: default:
break; break;
@ -343,7 +351,7 @@ class Order extends Model
//原订单 //原订单
if ($is_success) { if ($is_success) {
$order = $this->where('id', $r_order->relate_id)->first(); $order = $this->where('id', $r_order->relate_id)->first();
$order->refund_fee += $refund_fee * 100; $order->refund_fee += $refund_fee;
$order->status = Status::REVERSE->value; $order->status = Status::REVERSE->value;
$order->save(); $order->save();
} }

@ -36,6 +36,7 @@ class Patient extends Model
'birthday', 'birthday',
'mobile_phone', 'mobile_phone',
'address', 'address',
'def_status',
'qr_code_text', 'qr_code_text',
'health_card_id', 'health_card_id',
'health_card_status', 'health_card_status',
@ -50,6 +51,7 @@ class Patient extends Model
'id' => 'integer', 'id' => 'integer',
'card_type' => 'integer', 'card_type' => 'integer',
'sex' => 'integer', 'sex' => 'integer',
'def_status' => 'integer',
'health_card_status' => 'integer', 'health_card_status' => 'integer',
]; ];
@ -150,6 +152,15 @@ class Patient extends Model
return $this->where('patient_id', $patient_id)->first(); return $this->where('patient_id', $patient_id)->first();
} }
/**
* 获取绑定患者信息By Patient Number
* @param string $patient_number
* @return mixed
*/
public function getPatientInfoByPatientNumber(string $patient_number): mixed
{
return $this->where('patient_number', $patient_number)->first();
}
/** /**
* 建档 * 建档
@ -178,8 +189,7 @@ class Patient extends Model
'def_status' => 0 'def_status' => 0
]; ];
$count = $this->where('open_id', $open_id)->where('def_status', 1)->count(); if ($this->where('open_id', $open_id)->where('def_status', 1)->doesntExist()) {
if (!$count) {
$data['def_status'] = 1; $data['def_status'] = 1;
} }

@ -33,8 +33,8 @@ class AppServiceProvider extends ServiceProvider
Schema::defaultStringLength(191); Schema::defaultStringLength(191);
// Route参数表正则绑定 // Route参数表正则绑定
Route::pattern('patient_id', '[a-zA-Z0-9]+'); Route::pattern('patient_id', '[0-9]+');
Route::pattern('serial_no', '[a-zA-Z0-9]+'); Route::pattern('serial_no', '[0-9]+');
// 配置https // 配置https
if(env('REDIRECT_HTTPS')) { if(env('REDIRECT_HTTPS')) {

@ -0,0 +1,64 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Laravel\Telescope\IncomingEntry;
use Laravel\Telescope\Telescope;
use Laravel\Telescope\TelescopeApplicationServiceProvider;
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// Telescope::night();
$this->hideSensitiveRequestDetails();
$isLocal = $this->app->environment('local');
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
return $isLocal ||
$entry->isReportableException() ||
$entry->isFailedRequest() ||
$entry->isFailedJob() ||
$entry->isScheduledTask() ||
$entry->hasMonitoredTag();
});
}
/**
* Prevent sensitive request details from being logged by Telescope.
*/
protected function hideSensitiveRequestDetails(): void
{
if ($this->app->environment('local')) {
return;
}
Telescope::hideRequestParameters(['_token']);
Telescope::hideRequestHeaders([
'cookie',
'x-csrf-token',
'x-xsrf-token',
]);
}
/**
* Register the Telescope gate.
*
* This gate determines who can access Telescope in non-local environments.
*/
protected function gate(): void
{
Gate::define('viewTelescope', function ($user) {
return in_array($user->email, [
//
]);
});
}
}

@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
namespace App\Services\HealthRecordAuth;
use App\Utils\SM4;
use App\Utils\Traits\HttpRequest;
use Exception;
class Client
{
use HttpRequest;
//api接口地址
private string $api_url = 'https://yyzc.gdgov.cn/ebus/jiankangdangan/gdehr/dhccApi/codeAuthRec/save';
// 医院编号
private string $org_code;
// 医院名称
private string $org_name;
// App ID
private string $app_id;
private string $paas_id;
private string $paas_token;
// sm4 加密密钥
private string $sm4_encrypt;
/**
* Client constructor.
*/
public function __construct()
{
$this->org_code = env('HEALTH_RECORD_HOSPITAL_COST_CODE', '');
$this->org_name = env('HEALTH_RECORD_HOSPITAL_COST_NAME', '');
$this->app_id = env('HEALTH_RECORD_HOSPITAL_APP_ID', '');
$this->paas_id = env('HEALTH_RECORD_HOSPITAL_PAAS_ID', '');
$this->paas_token = env('HEALTH_RECORD_HOSPITAL_PAAS_TOKEN', '');
$this->sm4_encrypt = env('HEALTH_RECORD_HOSPITAL_SM4_ENCRYPT', '');
}
/**
* 获取请求header
* @return string[]
*/
private function getRequestHeaders(): array
{
$timestamp = time();
$nonceStr = $this->getNonceStr(11);
$sign = $this->getSign((string) $timestamp, $nonceStr);
return [
'x-tif-timestamp:'. $timestamp,
'x-tif-paasid:'. $this->paas_id,
'x-tif-nonce:'. $nonceStr,
'x-tif-signature:'. $sign
];
}
/**
* 获取随机字符串
* @param int $length
* @return string
*/
private function getNonceStr(int $length = 10): string
{
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
/**
* 生成签名
* @param string $timestamp
* @param string $nonceStr
* @return string
*/
private function getSign(string $timestamp, string $nonceStr): string
{
$signature = $timestamp. $this->paas_token. $nonceStr. $timestamp;
// 使用SHA256算法对字符串进行哈希,返回就是十六进制字符串,无需再转
$signature = hash('sha256', $signature);
// 转全大写
return strtoupper($signature);
}
/**
* 记录日志
* @param array $requestData
* @param mixed|NULL $responseData
* @return void
*/
private function recordLog(array $requestData, mixed $responseData = NULL): void
{
date_default_timezone_set("Asia/Shanghai");
$content = '[REQUEST TIME]'. date('Y-m-d H:i:s'). "\r\n".
'[REQUEST DATA]'. json_encode($requestData, JSON_UNESCAPED_UNICODE). "\r\n";
if (!empty($responseData)) {
$content .= '[RESPONSE DATA]'. json_encode($responseData, JSON_UNESCAPED_UNICODE). "\r\n";
}
$filePath = "log". DIRECTORY_SEPARATOR. 'HealthRecordAuthLog'. DIRECTORY_SEPARATOR. date('Ym'). DIRECTORY_SEPARATOR;
$fileName = date('d'). '.log';
!is_dir($filePath) && mkdir($filePath, 0755, true);
file_put_contents($filePath. $fileName, $content. "\r\n", FILE_APPEND);
}
/**
* api 请求方式 RESETFul
* @param array $data
* @param string $type
* @return bool|mixed|string
*/
private function apiRequest(array $data, string $type = 'POST'): mixed
{
$headers = $this->getRequestHeaders();
try {
$response = $this->request($type, $this->api_url, [
'headers' => $headers,
'json' => $data
]);
$response = json_decode($response, true);
$this->recordLog($data, $response);
return $response;
} catch (Exception $e) {
return false;
}
}
/**
* 申请授权
* @param string $patientName
* @param string $patientCardNo
* @param int $status
* @return bool|mixed|string
* @throws Exception
*/
public function applyAuth(string $patientName, string $patientCardNo, int $status = 0): mixed
{
$sm4 = new SM4($this->sm4_encrypt);
$patientCardNo = $sm4->encrypt($patientCardNo);
$data = [
'codeAuthRec' => [
'authDays' => 30, // 固定30天
'patientIdcard' => $patientCardNo,
'patientName' => $patientName,
'org_code' => $this->org_code,
'org_name' => $this->org_name,
'status' => $status,
'app_id' => $this->app_id
]
];
return $this->apiRequest($data);
}
}

@ -95,9 +95,9 @@ class Client
return $this->requestHandle('POST', 'CreateCardPatInfo', [ return $this->requestHandle('POST', 'CreateCardPatInfo', [
'json' => [ 'json' => [
'cardNo' => $card_no, 'cardNo' => $card_no,
'cardType' => $card_type->value, 'cardType' => (string) $card_type->value,
'patientName' => $patient_name, 'patientName' => $patient_name,
'sex' => $sex->value, 'sex' => (string) $sex->value,
'birthday' => $birthday, 'birthday' => $birthday,
'idCardNo' => $id_card_no, 'idCardNo' => $id_card_no,
'mobile' => $mobile, 'mobile' => $mobile,
@ -109,22 +109,24 @@ class Client
/** /**
* 获取患者信息 * 获取患者信息
* @param string $register_area 挂号区域(默认为 01)
* @param string $card_no 卡号 * @param string $card_no 卡号
* @param CardType $card_type 卡类型 * @param CardType $card_type 卡类型
* @param string $name 姓名 * @param string $name 姓名
* @param string $mzhm 门诊号码
* @param string $register_area 挂号区域(默认为 01)
* @return mixed * @return mixed
* @throws GeneralException * @throws GeneralException
*/ */
public function getPatientInfo(string $card_no, CardType $card_type, string $name, string $register_area = '01'): mixed public function getPatientInfo(string $card_no, CardType $card_type, string $name, string $mzhm = '', string $register_area = '01'): mixed
{ {
// 调用请求处理方法 // 调用请求处理方法
return $this->requestHandle('POST', 'GetCardInfo', [ return $this->requestHandle('POST', 'GetCardInfo', [
'json' => [ 'json' => [
'registerArea' => $register_area, 'registerArea' => $register_area,
'cardNo' => $card_no, 'cardNo' => $card_no,
'cardType' => $card_type->value, 'cardType' => (string) $card_type->value,
'name' => $name, 'name' => $name,
'mzhm' => $mzhm,
... $this->commonRequestData() ... $this->commonRequestData()
] ]
]); ]);
@ -279,7 +281,7 @@ class Client
* @param string $doctor_id 医生ID * @param string $doctor_id 医生ID
* @param string $reg_id 号源ID * @param string $reg_id 号源ID
* @param string $rank_id 午别ID * @param string $rank_id 午别ID
* @param string $date 挂号日期 * @param string $date 挂号日期 yyyy-mm-dd
* @param string $tran_type 支付方式 12 银联 3 医保 88 微信 89 支付宝 * @param string $tran_type 支付方式 12 银联 3 医保 88 微信 89 支付宝
* @param string $order_id 交易流水号 * @param string $order_id 交易流水号
* @param string $bankTranNo 银行交易流水号 * @param string $bankTranNo 银行交易流水号
@ -397,7 +399,7 @@ class Client
string $bank_tran_amt string $bank_tran_amt
): mixed ): mixed
{ {
return $this->requestHandle('POST', 'GHCancelConfirm', [ return $this->requestHandle('POST', 'GHCancel', [
'json' => [ 'json' => [
'visitNo' => $visit_no, 'visitNo' => $visit_no,
'orderID' => $order_id, 'orderID' => $order_id,
@ -422,8 +424,10 @@ class Client
public function getPendingLists(string $patient_id): mixed public function getPendingLists(string $patient_id): mixed
{ {
return $this->requestHandle('POST', 'ListVisitRec', [ return $this->requestHandle('POST', 'ListVisitRec', [
'json' => [
'patientID' => $patient_id, 'patientID' => $patient_id,
'registerArea' => '', 'registerArea' => '',
],
... $this->commonRequestData() ... $this->commonRequestData()
]); ]);
} }
@ -457,7 +461,7 @@ class Client
* 确认缴费 * 确认缴费
* @param string $patient_id 患者ID * @param string $patient_id 患者ID
* @param string $settle_type 结算类型 0 自费,1 门诊统筹 * @param string $settle_type 结算类型 0 自费,1 门诊统筹
* @param string $settle_date 结算日期 yyyy-mm-dd * @param string $settle_date 结算日期 yyyy-mm-dd hh24:ii:ss
* @param string $prescription_ids 处方号,多张处方用,隔开 * @param string $prescription_ids 处方号,多张处方用,隔开
* @param string $reg_id 就诊序号 * @param string $reg_id 就诊序号
* @param string $reg_type 就诊类别 * @param string $reg_type 就诊类别
@ -617,7 +621,9 @@ class Client
public function getDictionaryLists(): mixed public function getDictionaryLists(): mixed
{ {
return $this->requestHandle('POST', 'GetDictionary', [ return $this->requestHandle('POST', 'GetDictionary', [
'json' => [
... $this->commonRequestData() ... $this->commonRequestData()
],
]); ]);
} }

@ -796,15 +796,16 @@ if (!function_exists('replaceSpecialChar')) {
if (!function_exists('getAdminUploadImageUrl')) { if (!function_exists('getAdminUploadImageUrl')) {
/** /**
* 获取admin后台image地址 * 获取admin后台image地址
* @param string $image * @param string $image 图片名称
* @param string $module 模块
* @return string * @return string
*/ */
function getAdminUploadImageUrl(string $image): string function getAdminUploadImageUrl(string $image, string $module = ''): string
{ {
if (empty($image)) { if (empty($image)) {
return ''; return '';
} }
return asset('images/uploads/' . $image, true); return asset('am/'. ($module ?: 'uploads'). '/' . $image, true);
} }
} }

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace App\Utils\Traits;
trait BuildCacheKeyName
{
/**
* 获取 门诊待缴费列表 缓存键名
* @param string $open_id
* @param string $patient_id
* @return string
*/
public function getOutpatientPendingListsKey(string $open_id, string $patient_id): string
{
return 'outpatient.pending.'. $open_id. '.'. $patient_id;
}
/**
* 获取 门诊待缴费详情 缓存键名
* @param string $open_id
* @param string $patient_id
* @param string $serial_no
* @return string
*/
public function getOutpatientPendingDetailsKey(string $open_id, string $patient_id, string $serial_no): string
{
return 'outpatient.pending.'. $open_id.'.'. $patient_id. '.'. $serial_no;
}
}

@ -218,7 +218,10 @@ trait SendSubscribeMessage
// 重新强关联,避免缓存 // 重新强关联,避免缓存
$order->load('outpatientPaymentRecord'); $order->load('outpatientPaymentRecord');
$record = &$order->outpatientPaymentRecord; $record = &$order->outpatientPaymentRecord;
// 获取取药或执行地址
$extra_info = json_decode($record->extra_info, true); $extra_info = json_decode($record->extra_info, true);
$pay_address = $extra_info['confirm_response']['phyAddress'] ?? '';
$subscribe_id = SubscribeId::OUTPATIENT_PAYMENT_SUCCESS; $subscribe_id = SubscribeId::OUTPATIENT_PAYMENT_SUCCESS;
$data = [ $data = [
'touser' => $order->open_id, 'touser' => $order->open_id,
@ -227,7 +230,7 @@ trait SendSubscribeMessage
'data' => [ 'data' => [
'amount6' => ['value' => ($order->fee / 100). '元'], 'amount6' => ['value' => ($order->fee / 100). '元'],
'character_string7' => ['value' => $order->order_id], 'character_string7' => ['value' => $order->order_id],
'thing12' => ['value' => $extra_info['confirm_response']['phyAddress']], 'thing12' => ['value' => $pay_address],
'thing17' => ['value' => $order->patient->patient_number], 'thing17' => ['value' => $order->patient->patient_number],
'thing9' => ['value' => '门诊缴费'], 'thing9' => ['value' => '门诊缴费'],
], ],
@ -254,7 +257,6 @@ trait SendSubscribeMessage
'template_id' => $subscribe_id->value, 'template_id' => $subscribe_id->value,
'page' => '', 'page' => '',
'data' => [ 'data' => [
'character_string1' => ['value' => $order->order_id], 'character_string1' => ['value' => $order->order_id],
'thing2' => ['value' => '门诊缴费'], 'thing2' => ['value' => '门诊缴费'],
'name3' => ['value' => $order->patient_name], 'name3' => ['value' => $order->patient_name],

@ -6,6 +6,7 @@ namespace App\Utils\Transfer\HisHttpClient;
use App\Utils\Transfer\HttpTransferAbstract; use App\Utils\Transfer\HttpTransferAbstract;
use Exception; use Exception;
use JsonException; use JsonException;
use Psr\Http\Message\ResponseInterface;
class ClientHttpTransfer extends HttpTransferAbstract class ClientHttpTransfer extends HttpTransferAbstract
{ {
@ -38,13 +39,17 @@ class ClientHttpTransfer extends HttpTransferAbstract
/** /**
* 响应格式化 * 响应格式化
* @param mixed $data
* @return mixed * @return mixed
*/ */
public function responseFormat(mixed $data): mixed public function responseFormat(): mixed
{ {
$response = $this->transfer_response;
if ($this->transfer_response instanceof ResponseInterface) {
$response = $this->transfer_response->getBody()->getContents();
}
try { try {
return json_decode($data, true, JSON_THROW_ON_ERROR); return json_decode($response, true, JSON_THROW_ON_ERROR);
} catch (JsonException|Exception $e) { } catch (JsonException|Exception $e) {
return [ return [
'status' => 200, 'status' => 200,

@ -68,15 +68,14 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
/** /**
* 响应格式化 * 响应格式化
* @param mixed $data
* @return mixed * @return mixed
* @throws Exception * @throws Exception
*/ */
public function responseFormat(mixed $data): mixed public function responseFormat(): mixed
{ {
try { try {
// 此处为json格式 // 此处为json格式
return json_decode((string)$data, true); return json_decode((string)$this->transfer_response, true);
} catch (Exception $e) { } catch (Exception $e) {
throw new Exception($e->getMessage()); throw new Exception($e->getMessage());
} }
@ -115,11 +114,12 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
*/ */
private function mockGetPatientInfo(array $params): self private function mockGetPatientInfo(array $params): self
{ {
$patient_id = random_int(1000000, 9999999); // $patient_id = random_int(1000000, 9999999);
$patient_number = random_int(100000, 999999). random_int(100000, 999999); // $patient_number = random_int(100000, 999999). random_int(100000, 999999);
$card_no = &$params['json']['cardNo']; // $card_no = &$params['json']['cardNo'];
$name = &$params['json']['name']; // $name = &$params['json']['name'];
$this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":{"patientId":"'. $patient_id.' ","cardNo":"'. $card_no. '","name":"'. ($name ?: '谭玉山').'","sex":"1","birthday":"1999-03-24","cardStatus":"0","naturePatients":"123","patientNumber":"'. $patient_number. '"}}'; // $this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":{"patientId":"'. $patient_id.' ","cardNo":"'. $card_no. '","name":"'. ($name ?: '谭玉山').'","sex":"1","birthday":"1999-03-24","cardStatus":"0","naturePatients":"123","patientNumber":"'. $patient_number. '"}}';
$this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":{"patientId":"2247368","cardNo":"440402197605115715","name":"黄华峰","sex":"0","birthday":"1976-05-11","cardStatus":"0","naturePatients":"123","patientNumber":"288712347368"}}';
return $this; return $this;
} }
@ -202,7 +202,7 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
{ {
$date_1 = date('Ymd'); $date_1 = date('Ymd');
$date_2 = date('Y-m-d'); $date_2 = date('Y-m-d');
$this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":[{"idCardNo":"230403199903245493","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"'.$date_2.'","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"132","departmentName":"急诊内科","regId":"0","prescriptionId":"1-17488657","prescriptionAmount":"1","singleAmount":"1","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"1-17488657","takeMedicine":null,"visitNumber":"3896308"}]}'; $this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":[{"idCardNo":"360825199901303214","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"2025年313日","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"127","departmentName":"五官科","regId":"0","prescriptionId":"4-10259173","prescriptionAmount":"22.38","singleAmount":"12.96","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"4-10259173","takeMedicine":null,"visitNumber":"3936931"},{"idCardNo":"360825199901303214","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"2025年3月13日","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"127","departmentName":"五官科","regId":"0","prescriptionId":"1-17643828","prescriptionAmount":"22.38","singleAmount":".75","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"1-17643828","takeMedicine":null,"visitNumber":"3936931"},{"idCardNo":"360825199901303214","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"2025年3月13日","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"127","departmentName":"五官科","regId":"0","prescriptionId":"5-10259166","prescriptionAmount":"22.38","singleAmount":"8.1","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"5-10259166","takeMedicine":null,"visitNumber":"3936931"},{"idCardNo":"360825199901303214","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"2025年3月13日","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"127","departmentName":"五官科","regId":"0","prescriptionId":"2-10259174","prescriptionAmount":"22.38","singleAmount":".57","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"2-10259174","takeMedicine":null,"visitNumber":"3936931"},{"idCardNo":"360825199901303214","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"2025年3月13日","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"127","departmentName":"五官科","regId":"0","prescriptionId":"2-10259175","prescriptionAmount":"21.54","singleAmount":".54","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"2-10259175","takeMedicine":null,"visitNumber":"3936932"},{"idCardNo":"360825199901303214","visitType":"门诊","visitDate":"'.$date_1.'","strVisitDate":"2025年3月13日","outpatientDiagnosis":"健康查体,健康查体,健康查体,健康查体,健康查体,健康查体,健康查体","treatmentDepartment":"127","departmentName":"五官科","regId":"0","prescriptionId":"2-10259176","prescriptionAmount":"21.54","singleAmount":"21","doctorId":"10365","doctorName":"管理员","remarks":"","isexpense":"1","strExpense":"自费","nrescriptionNumber":"2-10259176","takeMedicine":null,"visitNumber":"3936932"}]}';
return $this; return $this;
} }
@ -215,7 +215,7 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
private function mockGetPendingDetails(array $params) private function mockGetPendingDetails(array $params)
{ {
$date = date('Y-m-d'); $date = date('Y-m-d');
$this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":[{"feeDate":"'.$date.'","itemNo":"11283271","projectNumber":"1547","entryName":"0.9%氯化钠注射液G","unitPrice":"1","quantity":"1","money":"1","remarks":null,"projectSpecifications":"100ML:0.9G/瓶","prescriptionNumber":"1-17488657","company":"瓶","prescriptionType":"西药","treatmentDepartment":"132","departmentName":"急诊内科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"XB05XAL211B002030902763"}]}'; $this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":[{"feeDate":"'.$date.'","itemNo":"11382601","projectNumber":"1388","entryName":"阿苯达唑片G","unitPrice":".75","quantity":"1","money":".75","remarks":null,"projectSpecifications":"0.2GX10片/盒","prescriptionNumber":"1-17643828","company":"片","prescriptionType":"西药","treatmentDepartment":"127","departmentName":"五官科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"XP02CAA010A001020101884"},{"feeDate":"'.$date.'","itemNo":"25078374","projectNumber":"1674","entryName":"*RH血型鉴定","unitPrice":"4.86","quantity":"1","money":"4.86","remarks":null,"projectSpecifications":null,"prescriptionNumber":"4-10259173","company":"次","prescriptionType":"检验单","treatmentDepartment":"127","departmentName":"五官科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"002600000040000-260000004"},{"feeDate":"'.$date.'","itemNo":"25078375","projectNumber":"1687","entryName":"*ABO血型鉴定","unitPrice":"8.1","quantity":"1","money":"8.1","remarks":null,"projectSpecifications":null,"prescriptionNumber":"4-10259173","company":"次","prescriptionType":"检验单","treatmentDepartment":"127","departmentName":"五官科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"002600000020000-260000002"},{"feeDate":"'.$date.'","itemNo":"25078357","projectNumber":"6629","entryName":"普通透视(使用影像增强器或电视屏)","unitPrice":"8.1","quantity":"1","money":"8.1","remarks":null,"projectSpecifications":null,"prescriptionNumber":"5-10259166","company":"每部位","prescriptionType":"处置单","treatmentDepartment":"127","departmentName":"五官科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"002101010010000-210101001-1"},{"feeDate":"'.$date.'","itemNo":"25078377","projectNumber":"7938","entryName":"EDTAK2(紫色)2ML,13*75MM一次性使用人体静脉血样采集容器","unitPrice":".28","quantity":"1","money":".28","remarks":null,"projectSpecifications":null,"prescriptionNumber":"2-10259174","company":"支","prescriptionType":"治疗单","treatmentDepartment":"127","departmentName":"五官科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"C1423022030001008207"},{"feeDate":"'.$date.'","itemNo":"25078376","projectNumber":"7924","entryName":"一次性使用采血针XYII蝶翼型0.7","unitPrice":".29","quantity":"1","money":".29","remarks":null,"projectSpecifications":null,"prescriptionNumber":"2-10259174","company":"包","prescriptionType":"治疗单","treatmentDepartment":"127","departmentName":"五官科","doctorNumber":"10365","doctorName":"管理员","ysybdm":"D440402003702","gjmlbm":"C1603062150000200629"}]}';
return $this; return $this;
} }
@ -251,7 +251,7 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
*/ */
private function mockGetPaidDetails(array $params): self private function mockGetPaidDetails(array $params): self
{ {
$this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":{"settlementDate":"2025-02-07","treaId":"6497702","hostranno":"ZZ00000049","costs":"1","expensePay":"1","medicalPayment":"","phyAddress":"门诊西药房","depName":"急诊内科","doctName":"管理员","outpatientDiagnosis":"1.健康查体","chargeStaff":"20","outpatientDetail":{"outpatientItemreList":[{"visitdate":"2025-02-07","classname":"西药费","itemname":"0.9%氯化钠注射液G","itemspec":"100ML:0.9G/瓶","units":"瓶","amount":"1","arice":"1","costs":"1","ztmc":"","ycjl":"100","jldw":"ML","yyts":"1","mrcs":"1","pcmc":"QD","ypbm":"XB05XAL211B002030902763","yjbm":"86902763001266","ybfl":"甲类","ygxm":"管理员"}]}}}'; $this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":{"settlementDate":"2025-03-13","treaId":"6558450","hostranno":"ZZJ00000052","costs":"22.38","expensePay":"22.38","medicalPayment":"","phyAddress":"门诊西药房","depName":"五官科","doctName":"管理员","outpatientDiagnosis":"1.健康查体","chargeStaff":"20","outpatientDetail":[{"outpatientItemreList":[{"visitdate":"2025-03-13","classname":"西药费","itemname":"阿苯达唑片G","itemspec":"0.2GX10片/盒","units":"片","amount":"1","price":".75","costs":".75","ztmc":"","ycjl":".2","jldw":"G","yyts":"1","mrcs":"1","pcmc":"QD","ypbm":"XP02CAA010A001020101884","yjbm":"86901884000028","ybfl":"甲类","ygxm":"管理员"}]},{"outpatientItemreList":[{"visitdate":"2025-03-13","classname":"X光费","itemname":"普通透视(使用影像增强器或电视屏)","itemspec":null,"units":"每部位","amount":"1","price":"8.1","costs":"8.1","ztmc":"腹部透视","ycjl":null,"jldw":null,"yyts":null,"mrcs":null,"pcmc":null,"ypbm":"002101010010000-210101001-1","yjbm":null,"ybfl":"甲类","ygxm":"管理员"}]},{"outpatientItemreList":[{"visitdate":"2025-03-13","classname":"检验费","itemname":"*ABO血型鉴定","itemspec":null,"units":"次","amount":"1","price":"8.1","costs":"8.1","ztmc":"ABO+RH血型","ycjl":null,"jldw":null,"yyts":null,"mrcs":null,"pcmc":null,"ypbm":"002600000020000-260000002","yjbm":null,"ybfl":"甲类","ygxm":"管理员"}]},{"outpatientItemreList":[{"visitdate":"2025-03-13","classname":"检验费","itemname":"*RH血型鉴定","itemspec":null,"units":"次","amount":"1","price":"4.86","costs":"4.86","ztmc":"ABO+RH血型","ycjl":null,"jldw":null,"yyts":null,"mrcs":null,"pcmc":null,"ypbm":"002600000040000-260000004","yjbm":null,"ybfl":"甲类","ygxm":"管理员"}]},{"outpatientItemreList":[{"visitdate":"2025-03-13","classname":"医材费","itemname":"一次性使用采血针XYII蝶翼型0.7","itemspec":null,"units":"包","amount":"1","price":".29","costs":".29","ztmc":"","ycjl":null,"jldw":null,"yyts":null,"mrcs":null,"pcmc":null,"ypbm":"C1603062150000200629","yjbm":null,"ybfl":"甲类","ygxm":"管理员"}]},{"outpatientItemreList":[{"visitdate":"2025-03-13","classname":"医材费","itemname":"EDTAK2(紫色)2ML,13*75MM一次性使用人体静脉血样采集容器","itemspec":null,"units":"支","amount":"1","price":".28","costs":".28","ztmc":"","ycjl":null,"jldw":null,"yyts":null,"mrcs":null,"pcmc":null,"ypbm":"C1423022030001008207","yjbm":null,"ybfl":"甲类","ygxm":"管理员"}]}]}}';
return $this; return $this;
} }
@ -293,7 +293,7 @@ class ClientMockHttpTransfer extends HttpTransferAbstract
*/ */
private function mockGetChargeList(array $params): self private function mockGetChargeList(array $params): self
{ {
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG></ERRORMSG><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>苯巴比妥片</COSTNAME><UNIT></UNIT><COSTSPEC>30MG</COSTSPEC><CDNAME>上海信谊药厂</CDNAME><PRICE>0.097</PRICE><REMARK></REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>阿莫西林胶囊</COSTNAME><UNIT></UNIT><COSTSPEC>500MG</COSTSPEC><CDNAME>华北制药厂</CDNAME><PRICE>0.12</PRICE><REMARK>用于治疗细菌感染</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>复方氯噻吨片</COSTNAME><UNIT></UNIT><COSTSPEC>0.25G</COSTSPEC><CDNAME>长春药业</CDNAME><PRICE>0.15</PRICE><REMARK>缓解高血压症状</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>洛伐他汀片</COSTNAME><UNIT></UNIT><COSTSPEC>20MG</COSTSPEC><CDNAME>中科院制药</CDNAME><PRICE>0.25</PRICE><REMARK>降低血脂</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>维生素C片</COSTNAME><UNIT></UNIT><COSTSPEC>500MG</COSTSPEC><CDNAME>美国善格</CDNAME><PRICE>0.05</PRICE><REMARK>增强免疫力</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>布洛芬片</COSTNAME><UNIT></UNIT><COSTSPEC>200MG</COSTSPEC><CDNAME>华药集团</CDNAME><PRICE>0.1</PRICE><REMARK>缓解轻度疼痛</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>氯氮平片</COSTNAME><UNIT></UNIT><COSTSPEC>25MG</COSTSPEC><CDNAME>南京医药</CDNAME><PRICE>0.3</PRICE><REMARK>用于治疗精神分裂症</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>头孢克肟胶囊</COSTNAME><UNIT></UNIT><COSTSPEC>500MG</COSTSPEC><CDNAME>石药集团</CDNAME><PRICE>0.18</PRICE><REMARK>抗菌药物</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>硝苯地平片</COSTNAME><UNIT></UNIT><COSTSPEC>10MG</COSTSPEC><CDNAME>国药集团</CDNAME><PRICE>0.2</PRICE><REMARK>用于治疗高血压</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>美托洛尔片</COSTNAME><UNIT></UNIT><COSTSPEC>25MG</COSTSPEC><CDNAME>拜耳制药</CDNAME><PRICE>0.22</PRICE><REMARK>用于治疗心脏病</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>甲硝唑片</COSTNAME><UNIT></UNIT><COSTSPEC>250MG</COSTSPEC><CDNAME>南京同仁堂</CDNAME><PRICE>0.12</PRICE><REMARK>用于治疗感染</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>阿托伐他汀片</COSTNAME><UNIT></UNIT><COSTSPEC>10MG</COSTSPEC><CDNAME>默沙东</CDNAME><PRICE>0.3</PRICE><REMARK>调节血脂</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>硫酸氢氯噻吨片</COSTNAME><UNIT></UNIT><COSTSPEC>12.5MG</COSTSPEC><CDNAME>齐鲁制药</CDNAME><PRICE>0.15</PRICE><REMARK>用于治疗水肿</REMARK></ITEM><ITEM><TYPENAME>西药费</TYPENAME><COSTNAME>兰索拉唑胶囊</COSTNAME><UNIT></UNIT><COSTSPEC>30MG</COSTSPEC><CDNAME>百时美施贵宝</CDNAME><PRICE>0.18</PRICE><REMARK>治疗胃酸过多</REMARK></ITEM></RESPONSE>'; $this->transfer_response = '{"status":200,"success":true,"msg":"成功","msgDev":null,"response":[{"typeName":"草药费","costName":"莲子","unit":"G","costSpec":"10GX100小包/袋","manufacturer":"岭南中药饮片有","price":".08875","remark":""},{"typeName":"草药费","costName":"茯苓","unit":"G","costSpec":"10GX100小包/袋","manufacturer":"广州至信中药饮","price":".0925","remark":""}]}';
return $this; return $this;
} }

@ -51,15 +51,14 @@ class ClientSoapTransfer extends SoapTransferAbstract
/** /**
* 响应格式化 * 响应格式化
* @param mixed $data
* @return mixed * @return mixed
* @throws Exception * @throws Exception
*/ */
public function responseFormat(mixed $data): mixed public function responseFormat(): mixed
{ {
try { try {
// 此处为xml格式 // 此处为xml格式
$obj = simplexml_load_string((string)$data, 'SimpleXMLElement', LIBXML_NOCDATA); $obj = simplexml_load_string((string)$this->transfer_response, 'SimpleXMLElement', LIBXML_NOCDATA);
return json_decode((string)json_encode($obj), true); return json_decode((string)json_encode($obj), true);
} catch (Exception $e) { } catch (Exception $e) {

@ -27,7 +27,7 @@ abstract class HttpTransferAbstract
public mixed $transfer_parameter; public mixed $transfer_parameter;
// 调用返回结果 string格式用于mock数据 // 调用返回结果 string格式用于mock数据
public ResponseInterface|string $transfer_response; public ResponseInterface|string $transfer_response = '';
// 运行时间 // 运行时间
public array $request_time; public array $request_time;
@ -120,7 +120,7 @@ abstract class HttpTransferAbstract
public function getResult(bool $is_format = true): mixed public function getResult(bool $is_format = true): mixed
{ {
if ($is_format) { if ($is_format) {
return $this->responseFormat($this->transfer_response); return $this->responseFormat();
} }
return $this->transfer_response; return $this->transfer_response;
@ -128,10 +128,9 @@ abstract class HttpTransferAbstract
/** /**
* 响应格式化 * 响应格式化
* @param mixed $data
* @return mixed * @return mixed
*/ */
abstract public function responseFormat(mixed $data): mixed; abstract public function responseFormat(): mixed;
/** /**
* 魔术方法实现动态调用方法 * 魔术方法实现动态调用方法
@ -163,10 +162,16 @@ abstract class HttpTransferAbstract
empty($this->his_config['not_log_arr']) || empty($this->his_config['not_log_arr']) ||
!in_array($this->transfer_name, $this->his_config['not_log_arr']) !in_array($this->transfer_name, $this->his_config['not_log_arr'])
) { ) {
$response = $this->transfer_response;
if ($this->transfer_response instanceof ResponseInterface) {
$response = $this->transfer_response->getBody()->getContents();
// 流指针重置
$this->transfer_response->getBody()->rewind();
}
// 记录入参和结果 // 记录入参和结果
$content = '[METHOD NAME] '. $this->transfer_method. '|'. $this->transfer_name. PHP_EOL. $content = '[METHOD NAME] '. $this->transfer_method. '|'. $this->transfer_name. PHP_EOL.
'[REQUEST PARAM] '. json_encode($this->transfer_parameter, JSON_UNESCAPED_UNICODE). PHP_EOL. '[REQUEST PARAM] '. json_encode($this->transfer_parameter, JSON_UNESCAPED_UNICODE). PHP_EOL.
'[RESPONSE PARAM] '. json_encode($this->transfer_response, JSON_UNESCAPED_UNICODE). PHP_EOL. '[RESPONSE PARAM] '. (is_string($response) ? $response : json_encode($response, JSON_UNESCAPED_UNICODE)). PHP_EOL.
'[RUN TIME] '. $run_time . "/s"; '[RUN TIME] '. $run_time . "/s";
$this->recordRequestLog($this->his_config['his_name'], $content); $this->recordRequestLog($this->his_config['his_name'], $content);
} }
@ -183,7 +188,7 @@ abstract class HttpTransferAbstract
date_default_timezone_set("Asia/Shanghai"); date_default_timezone_set("Asia/Shanghai");
$dirname = $this->his_config['his_name']; $dirname = $this->his_config['his_name'];
$path = app()->storagePath(). DIRECTORY_SEPARATOR. $dirname. DIRECTORY_SEPARATOR; $path = app()->storagePath('logs'). DIRECTORY_SEPARATOR. $dirname. DIRECTORY_SEPARATOR;
$file_path = $path. $his_name. 'Log'. DIRECTORY_SEPARATOR. date('Ym'). DIRECTORY_SEPARATOR; $file_path = $path. $his_name. 'Log'. DIRECTORY_SEPARATOR. date('Ym'). DIRECTORY_SEPARATOR;
$file_name = date('d'). ".log"; $file_name = date('d'). ".log";

@ -183,7 +183,7 @@ abstract class SoapTransferAbstract
$this->transfer_response = $this->transfer_response->$result_attr_str(); $this->transfer_response = $this->transfer_response->$result_attr_str();
if ($is_format) { if ($is_format) {
return $this->responseFormat($this->transfer_response); return $this->responseFormat();
} }
return $this->transfer_response; return $this->transfer_response;
@ -191,9 +191,8 @@ abstract class SoapTransferAbstract
/** /**
* 响应格式化 * 响应格式化
* @param $data
*/ */
abstract public function responseFormat($data); abstract public function responseFormat();
/** /**
* 保存日志记录 * 保存日志记录

@ -3,6 +3,7 @@
use App\Console\Commands\SendAppointmentReminders; use App\Console\Commands\SendAppointmentReminders;
use App\Exceptions\GeneralException; use App\Exceptions\GeneralException;
use App\Http\Middleware\IntranetAccess; use App\Http\Middleware\IntranetAccess;
use App\Http\Middleware\PerformanceDebug;
use App\Http\Middleware\RecordApiLog; use App\Http\Middleware\RecordApiLog;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Application; use Illuminate\Foundation\Application;
@ -26,7 +27,8 @@ return Application::configure(basePath: dirname(__DIR__))
$middleware->alias([ $middleware->alias([
'apiLog' => RecordApiLog::class, 'apiLog' => RecordApiLog::class,
'intranetAccess' => IntranetAccess::class 'intranetAccess' => IntranetAccess::class,
'performanceDebug' => PerformanceDebug::class
]); ]);
}) })
->withExceptions(function (Exceptions $exceptions) { ->withExceptions(function (Exceptions $exceptions) {
@ -87,10 +89,10 @@ return Application::configure(basePath: dirname(__DIR__))
$err_msg = $e->getMessage(); $err_msg = $e->getMessage();
$record_msg = $err_msg. ' in '. $e->getFile(). ':'. $e->getLine(); $record_msg = $err_msg. ' in '. $e->getFile(). ':'. $e->getLine();
// 500 错误拦截
recordLog('AppError', $record_msg); recordLog('AppError', $record_msg);
return jsonResponse(Response::HTTP_INTERNAL_SERVER_ERROR, $record_msg); return jsonResponse(Response::HTTP_INTERNAL_SERVER_ERROR, $record_msg);
}); });
})->withCommands([ })->withCommands([
SendAppointmentReminders::class, SendAppointmentReminders::class,
]) ])

@ -2,5 +2,6 @@
return [ return [
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
UnifyPayment\UnifyServiceProvider::class App\Providers\TelescopeServiceProvider::class,
UnifyPayment\UnifyServiceProvider::class,
]; ];

@ -16,11 +16,13 @@
"ext-bcmath": "*", "ext-bcmath": "*",
"laravel/framework": "^11.31", "laravel/framework": "^11.31",
"laravel/sanctum": "^4.0", "laravel/sanctum": "^4.0",
"laravel/telescope": "*",
"laravel/tinker": "^2.9", "laravel/tinker": "^2.9",
"overtrue/laravel-wechat": "^7.2", "overtrue/laravel-wechat": "^7.2",
"wsdltophp/packagegenerator": "^4.1" "wsdltophp/packagegenerator": "^4.1"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-debugbar": "^3.15",
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
"laravel/pail": "^1.1", "laravel/pail": "^1.1",
"laravel/pint": "^1.13", "laravel/pint": "^1.13",

237
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "b055ceb543cb3e07eb9a24a3d16eb972", "content-hash": "c6f07051e3f4fbfce32f6882b1abd40a",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@ -2156,6 +2156,75 @@
}, },
"time": "2024-12-16T15:26:28+00:00" "time": "2024-12-16T15:26:28+00:00"
}, },
{
"name": "laravel/telescope",
"version": "v5.5.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/telescope.git",
"reference": "2594b20b946155ba767002d8af971e33e1095637"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/telescope/zipball/2594b20b946155ba767002d8af971e33e1095637",
"reference": "2594b20b946155ba767002d8af971e33e1095637",
"shasum": ""
},
"require": {
"ext-json": "*",
"laravel/framework": "^8.37|^9.0|^10.0|^11.0|^12.0",
"php": "^8.0",
"symfony/console": "^5.3|^6.0|^7.0",
"symfony/var-dumper": "^5.0|^6.0|^7.0"
},
"require-dev": {
"ext-gd": "*",
"guzzlehttp/guzzle": "^6.0|^7.0",
"laravel/octane": "^1.4|^2.0|dev-develop",
"orchestra/testbench": "^6.40|^7.37|^8.17|^9.0|^10.0",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^9.0|^10.5|^11.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Laravel\\Telescope\\TelescopeServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Laravel\\Telescope\\": "src/",
"Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
},
{
"name": "Mohamed Said",
"email": "mohamed@laravel.com"
}
],
"description": "An elegant debug assistant for the Laravel framework.",
"keywords": [
"debugging",
"laravel",
"monitoring"
],
"support": {
"issues": "https://github.com/laravel/telescope/issues",
"source": "https://github.com/laravel/telescope/tree/v5.5.0"
},
"time": "2025-02-11T15:01:27+00:00"
},
{ {
"name": "laravel/tinker", "name": "laravel/tinker",
"version": "v2.10.0", "version": "v2.10.0",
@ -8561,6 +8630,94 @@
} }
], ],
"packages-dev": [ "packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.15.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "0bc1e1361e7fffc2be156f46ad1fba6927c01729"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/0bc1e1361e7fffc2be156f46ad1fba6927c01729",
"reference": "0bc1e1361e7fffc2be156f46ad1fba6927c01729",
"shasum": ""
},
"require": {
"illuminate/routing": "^9|^10|^11|^12",
"illuminate/session": "^9|^10|^11|^12",
"illuminate/support": "^9|^10|^11|^12",
"php": "^8.1",
"php-debugbar/php-debugbar": "~2.1.1",
"symfony/finder": "^6|^7"
},
"conflict": {
"maximebf/debugbar": "*"
},
"require-dev": {
"mockery/mockery": "^1.3.3",
"orchestra/testbench-dusk": "^7|^8|^9|^10",
"phpunit/phpunit": "^9.5.10|^10|^11",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facades\\Debugbar"
},
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.15-dev"
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"Barryvdh\\Debugbar\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "PHP Debugbar integration for Laravel",
"keywords": [
"debug",
"debugbar",
"dev",
"laravel",
"profiler",
"webprofiler"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-debugbar/issues",
"source": "https://github.com/barryvdh/laravel-debugbar/tree/v3.15.2"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2025-02-25T15:25:22+00:00"
},
{ {
"name": "fakerphp/faker", "name": "fakerphp/faker",
"version": "v1.24.1", "version": "v1.24.1",
@ -9311,6 +9468,76 @@
}, },
"time": "2022-02-21T01:04:05+00:00" "time": "2022-02-21T01:04:05+00:00"
}, },
{
"name": "php-debugbar/php-debugbar",
"version": "v2.1.6",
"source": {
"type": "git",
"url": "https://github.com/php-debugbar/php-debugbar.git",
"reference": "16fa68da5617220594aa5e33fa9de415f94784a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/16fa68da5617220594aa5e33fa9de415f94784a0",
"reference": "16fa68da5617220594aa5e33fa9de415f94784a0",
"shasum": ""
},
"require": {
"php": "^8",
"psr/log": "^1|^2|^3",
"symfony/var-dumper": "^4|^5|^6|^7"
},
"require-dev": {
"dbrekelmans/bdi": "^1",
"phpunit/phpunit": "^8|^9",
"symfony/panther": "^1|^2.1",
"twig/twig": "^1.38|^2.7|^3.0"
},
"suggest": {
"kriswallsmith/assetic": "The best way to manage assets",
"monolog/monolog": "Log using Monolog",
"predis/predis": "Redis storage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"DebugBar\\": "src/DebugBar/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Debug bar in the browser for php application",
"homepage": "https://github.com/php-debugbar/php-debugbar",
"keywords": [
"debug",
"debug bar",
"debugbar",
"dev"
],
"support": {
"issues": "https://github.com/php-debugbar/php-debugbar/issues",
"source": "https://github.com/php-debugbar/php-debugbar/tree/v2.1.6"
},
"time": "2025-02-21T17:47:03+00:00"
},
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "11.0.8", "version": "11.0.8",
@ -10767,13 +10994,7 @@
"prefer-stable": true, "prefer-stable": true,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {
"php": "^8.2", "php": "^8.2"
"ext-libxml": "*",
"ext-openssl": "*",
"ext-pdo": "*",
"ext-redis": "*",
"ext-simplexml": "*",
"ext-soap": "*"
}, },
"platform-dev": {}, "platform-dev": {},
"plugin-api-version": "2.6.0" "plugin-api-version": "2.6.0"

@ -8,5 +8,7 @@ return [
// 绑定就诊卡数上限 // 绑定就诊卡数上限
'max_bind_patient_count' => 5, 'max_bind_patient_count' => 5,
// 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
'mini_program_message_state' => 'developer' 'mini_program_message_state' => 'developer',
// 支付通知地址
'payment_notify_url' => env('APP_URL'). '/Api/notify'
]; ];

@ -0,0 +1,206 @@
<?php
use Laravel\Telescope\Http\Middleware\Authorize;
use Laravel\Telescope\Watchers;
return [
/*
|--------------------------------------------------------------------------
| Telescope Master Switch
|--------------------------------------------------------------------------
|
| This option may be used to disable all Telescope watchers regardless
| of their individual configuration, which simply provides a single
| and convenient way to enable or disable Telescope data storage.
|
*/
'enabled' => env('TELESCOPE_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Telescope Domain
|--------------------------------------------------------------------------
|
| This is the subdomain where Telescope will be accessible from. If the
| setting is null, Telescope will reside under the same domain as the
| application. Otherwise, this value will be used as the subdomain.
|
*/
'domain' => env('TELESCOPE_DOMAIN'),
/*
|--------------------------------------------------------------------------
| Telescope Path
|--------------------------------------------------------------------------
|
| This is the URI path where Telescope will be accessible from. Feel free
| to change this path to anything you like. Note that the URI will not
| affect the paths of its internal API that aren't exposed to users.
|
*/
'path' => env('TELESCOPE_PATH', 'telescope'),
/*
|--------------------------------------------------------------------------
| Telescope Storage Driver
|--------------------------------------------------------------------------
|
| This configuration options determines the storage driver that will
| be used to store Telescope's data. In addition, you may set any
| custom options as needed by the particular driver you choose.
|
*/
'driver' => env('TELESCOPE_DRIVER', 'database'),
'storage' => [
'database' => [
'connection' => env('DB_CONNECTION', 'mysql'),
'chunk' => 1000,
],
],
/*
|--------------------------------------------------------------------------
| Telescope Queue
|--------------------------------------------------------------------------
|
| This configuration options determines the queue connection and queue
| which will be used to process ProcessPendingUpdate jobs. This can
| be changed if you would prefer to use a non-default connection.
|
*/
'queue' => [
'connection' => env('TELESCOPE_QUEUE_CONNECTION', null),
'queue' => env('TELESCOPE_QUEUE', null),
'delay' => env('TELESCOPE_QUEUE_DELAY', 10),
],
/*
|--------------------------------------------------------------------------
| Telescope Route Middleware
|--------------------------------------------------------------------------
|
| These middleware will be assigned to every Telescope route, giving you
| the chance to add your own middleware to this list or change any of
| the existing middleware. Or, you can simply stick with this list.
|
*/
'middleware' => [
'web',
Authorize::class,
],
/*
|--------------------------------------------------------------------------
| Allowed / Ignored Paths & Commands
|--------------------------------------------------------------------------
|
| The following array lists the URI paths and Artisan commands that will
| not be watched by Telescope. In addition to this list, some Laravel
| commands, like migrations and queue commands, are always ignored.
|
*/
'only_paths' => [
// 'api/*'
],
'ignore_paths' => [
'livewire*',
'nova-api*',
'pulse*',
],
'ignore_commands' => [
//
],
/*
|--------------------------------------------------------------------------
| Telescope Watchers
|--------------------------------------------------------------------------
|
| The following array lists the "watchers" that will be registered with
| Telescope. The watchers gather the application's profile data when
| a request or task is executed. Feel free to customize this list.
|
*/
'watchers' => [
Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
Watchers\CacheWatcher::class => [
'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
'hidden' => [],
],
Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
Watchers\CommandWatcher::class => [
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
'ignore' => [],
],
Watchers\DumpWatcher::class => [
'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
],
Watchers\EventWatcher::class => [
'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
'ignore' => [],
],
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
Watchers\GateWatcher::class => [
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
'ignore_abilities' => [],
'ignore_packages' => true,
'ignore_paths' => [],
],
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
Watchers\LogWatcher::class => [
'enabled' => env('TELESCOPE_LOG_WATCHER', true),
'level' => 'error',
],
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
Watchers\ModelWatcher::class => [
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
'events' => ['eloquent.*'],
'hydrations' => true,
],
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
Watchers\QueryWatcher::class => [
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
'ignore_packages' => true,
'ignore_paths' => [],
'slow' => 100,
],
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
Watchers\RequestWatcher::class => [
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
'ignore_http_methods' => [],
'ignore_status_codes' => [],
],
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
],
];

@ -0,0 +1,70 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Get the migration connection name.
*/
public function getConnection(): ?string
{
return config('telescope.storage.database.connection');
}
/**
* Run the migrations.
*/
public function up(): void
{
$schema = Schema::connection($this->getConnection());
$schema->create('telescope_entries', function (Blueprint $table) {
$table->bigIncrements('sequence');
$table->uuid('uuid');
$table->uuid('batch_id');
$table->string('family_hash')->nullable();
$table->boolean('should_display_on_index')->default(true);
$table->string('type', 20);
$table->longText('content');
$table->dateTime('created_at')->nullable();
$table->unique('uuid');
$table->index('batch_id');
$table->index('family_hash');
$table->index('created_at');
$table->index(['type', 'should_display_on_index']);
});
$schema->create('telescope_entries_tags', function (Blueprint $table) {
$table->uuid('entry_uuid');
$table->string('tag');
$table->primary(['entry_uuid', 'tag']);
$table->index('tag');
$table->foreign('entry_uuid')
->references('uuid')
->on('telescope_entries')
->onDelete('cascade');
});
$schema->create('telescope_monitoring', function (Blueprint $table) {
$table->string('tag')->primary();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$schema = Schema::connection($this->getConnection());
$schema->dropIfExists('telescope_entries_tags');
$schema->dropIfExists('telescope_entries');
$schema->dropIfExists('telescope_monitoring');
}
};

@ -215,9 +215,11 @@ class BasicClient
throw new InvalidConfigException('Missing Unify Payment Config -- [SecretKey]'); throw new InvalidConfigException('Missing Unify Payment Config -- [SecretKey]');
} }
ksort($data); $content = $this->getSignContent($data);
$sign = md5($content. $key);
Log::debug('Generate Sign Content', [$content, $sign]);
return md5($this->getSignContent($data) . $key); return $sign;
} }
/** /**
@ -236,13 +238,11 @@ class BasicClient
} }
try { try {
$buff = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE); $buff = json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
} catch (JsonException $e) { } catch (JsonException $e) {
throw new RuntimeException('Generate Sign Error:' . $e->getMessage()); throw new RuntimeException('Generate Sign Error:' . $e->getMessage());
} }
Log::debug('Generate Sign Content', [$data, $buff]);
return trim($buff); return trim($buff);
} }

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

@ -0,0 +1,5 @@
{
"/app.js": "/app.js?id=a04a99f77a55ffcecde23cd7304b481b",
"/app-dark.css": "/app-dark.css?id=1ea407db56c5163ae29311f1f38eb7b9",
"/app.css": "/app.css?id=de4c978567bfd90b38d186937dee5ccf"
}

@ -55,7 +55,7 @@ Route::middleware(['apiLog'])->group(function() {
Route::prefix('Outpatient')->group(function () { Route::prefix('Outpatient')->group(function () {
Route::get('/{patient_id}/pending', [PendingController::class, 'lists']); Route::get('/{patient_id}/pending', [PendingController::class, 'lists']);
Route::get('/{patient_id}/pending/{serial_no}/', [PendingController::class, 'details']); Route::get('/{patient_id}/pending/{serial_no}/', [PendingController::class, 'details']);
Route::post('/{patient_id}/pending/payment', [PaymentController::class, 'payment']); Route::post('/{patient_id}/pending/{serial_no}/payment', [PaymentController::class, 'payment']);
Route::get('/{patient_id}/record', [OutpatientRecordController::class, 'lists']); Route::get('/{patient_id}/record', [OutpatientRecordController::class, 'lists']);
Route::get('/{patient_id}/record/{serial_no}/', [OutpatientRecordController::class, 'details']); Route::get('/{patient_id}/record/{serial_no}/', [OutpatientRecordController::class, 'details']);

@ -0,0 +1,2 @@
*
!.gitignore
Loading…
Cancel
Save