Compare commits

..
7 Commits
Author SHA1 Message Date
haomingming fcbc4c66d0 Merge branch 'dev'
Build Docker / build (push) Has been cancelled
2026-01-09 17:21:24 +08:00
haomingming 315adad6d0 Merge branch 'dev'
Build Docker / build (push) Has been cancelled
2026-01-06 17:51:31 +08:00
haomingming e223725c49 Merge branch 'dev'
Build Docker / build (push) Has been cancelled
2025-12-23 10:49:39 +08:00
haomingming ef2ae67a37 Merge branch 'dev'
Build Docker / build (push) Waiting to run
2025-12-23 09:45:29 +08:00
haomingming 7690ec848b Merge branch 'dev'
Build Docker / build (push) Waiting to run
2025-12-22 14:29:20 +08:00
haomingming 569b2a84fd Merge branch 'dev'
Build Docker / build (push) Waiting to run
2025-12-22 13:32:13 +08:00
haomingming bc61f09ad0 合并 dev
Build Docker / build (push) Has been cancelled
2025-10-22 15:06:05 +08:00
20 changed files with 247 additions and 1841 deletions
-1
View File
@@ -4,7 +4,6 @@
*.patch *.patch
.idea/ .idea/
.git/ .git/
docs/
runtime/ runtime/
vendor/ vendor/
.phpintel/ .phpintel/
@@ -261,12 +261,7 @@ class AutoPharmacistCaVerifyDelayDirectConsumer extends ConsumerMessage
} }
// 修改处方文件表,添加prescription_pdf_oss_path字段 // 修改处方文件表,添加prescription_pdf_oss_path字段
$this->modifyOrderPrescriptionFile( $this->modifyOrderPrescriptionFile($data['prescription_file_id'],$prescription_pdf_oss_path,$prescription_open_result['file_id']);
$data['prescription_file_id'],
$prescription_pdf_oss_path,
$prescription_open_result['file_id'],
$prescription_open_result
);
// 修改处方表为通过 // 修改处方表为通过
$this->modifyOrderPrescription($data['order_prescription_id'],1); $this->modifyOrderPrescription($data['order_prescription_id'],1);
@@ -443,7 +438,7 @@ class AutoPharmacistCaVerifyDelayDirectConsumer extends ConsumerMessage
* @param string $hospital_ca_file_id 医院签章文件id * @param string $hospital_ca_file_id 医院签章文件id
* @return void * @return void
*/ */
protected function modifyOrderPrescriptionFile(string $prescription_file_id,string $prescription_pdf_oss_path,string $hospital_ca_file_id,array $pharmacist_ca_data = []): void protected function modifyOrderPrescriptionFile(string $prescription_file_id,string $prescription_pdf_oss_path,string $hospital_ca_file_id): void
{ {
try { try {
$params = array(); $params = array();
@@ -452,11 +447,6 @@ class AutoPharmacistCaVerifyDelayDirectConsumer extends ConsumerMessage
$data = array(); $data = array();
$data['hospital_ca_file_id'] = $hospital_ca_file_id; $data['hospital_ca_file_id'] = $hospital_ca_file_id;
$data['prescription_pdf_oss_path'] = $prescription_pdf_oss_path; $data['prescription_pdf_oss_path'] = $prescription_pdf_oss_path;
$data['pharmacist_ca_supplier'] = $pharmacist_ca_data['ca_supplier'] ?? "";
$data['pharmacist_ca_sign_type'] = $pharmacist_ca_data['ca_sign_type'] ?? "";
$data['pharmacist_ca_sign_originaltext'] = $pharmacist_ca_data['ca_sign_originaltext'] ?? "";
$data['pharmacist_ca_sign_text'] = $pharmacist_ca_data['ca_sign_text'] ?? "";
$data['pharmacist_ca_sign_time'] = $pharmacist_ca_data['ca_sign_time'] ?? "";
OrderPrescriptionFile::edit($params,$data); OrderPrescriptionFile::edit($params,$data);
}catch(\Exception $e){ }catch(\Exception $e){
+13 -312
View File
@@ -9,12 +9,12 @@ use App\Model\HospitalDepartmentCustom;
use App\Model\OrderInquiry; use App\Model\OrderInquiry;
use App\Model\OrderInquiryCase; use App\Model\OrderInquiryCase;
use App\Model\OrderPrescription; use App\Model\OrderPrescription;
use App\Model\OrderPrescriptionFile;
use App\Model\OrderPrescriptionIcd; use App\Model\OrderPrescriptionIcd;
use App\Model\OrderPrescriptionProduct; use App\Model\OrderPrescriptionProduct;
use App\Model\PatientFamily; use App\Model\PatientFamily;
use App\Model\Product; use App\Model\Product;
use App\Model\ReportRegulatory; use App\Model\ReportRegulatory;
use App\Model\UserCaCert;
use App\Model\UserDoctor; use App\Model\UserDoctor;
use App\Model\UserDoctorInfo; use App\Model\UserDoctorInfo;
use App\Model\UserPharmacist; use App\Model\UserPharmacist;
@@ -188,7 +188,7 @@ class ReportRegulatoryCommand extends HyperfCommand
}else{ }else{
$this->line("C-2、检测处方(抄方)数据"); $this->line("C-2、检测处方(抄方)数据");
// 获取上报数据-处方 (抄方类型) // 获取上报数据-处方 (抄方类型)
$report_prescription_data = $this->getReportTransferPrescriptionDataV2($order_inquiry, $order_prescription); $report_prescription_data = $this->getReportTransferPrescriptionData($order_inquiry, $order_prescription);
} }
$this->line("C-3、上报处方"); $this->line("C-3、上报处方");
@@ -198,17 +198,6 @@ class ReportRegulatoryCommand extends HyperfCommand
$this->line("C-4、上报处方成功" . json_encode($result,JSON_UNESCAPED_UNICODE)); $this->line("C-4、上报处方成功" . json_encode($result,JSON_UNESCAPED_UNICODE));
$report_prescription_detail_data = $this->getReportPrescriptionDetailData(
$order_prescription,
$report_prescription_data
);
if (empty($report_prescription_detail_data)) {
throw new BusinessException("处方明细数据错误");
}
$result = $regulatoryPlatform->uploadRecipeDetail($report_prescription_detail_data);
$this->line("C-4-1、上报处方明细成功" . json_encode($result,JSON_UNESCAPED_UNICODE));
// 上报成功 // 上报成功
$res = $this->modifyReportRegulatoryPrescription($report_regulatory, 1); $res = $this->modifyReportRegulatoryPrescription($report_regulatory, 1);
if (!$res) { if (!$res) {
@@ -485,7 +474,7 @@ class ReportRegulatoryCommand extends HyperfCommand
$params['user_id'] = $user_doctor['user_id']; $params['user_id'] = $user_doctor['user_id'];
$params['type'] = 2; $params['type'] = 2;
$params['is_latest'] = 1; $params['is_latest'] = 1;
$doctor_user_ca_cert = $this->buildLegacyCaCertPayload($order_prescription['order_prescription_id'], 'doctor'); $doctor_user_ca_cert = UserCaCert::getOne($params);
if (empty($doctor_user_ca_cert)){ if (empty($doctor_user_ca_cert)){
$this->line("错误:无医生ca数据"); $this->line("错误:无医生ca数据");
return false; return false;
@@ -496,7 +485,7 @@ class ReportRegulatoryCommand extends HyperfCommand
$params['user_id'] = $user_pharmacist['user_id']; $params['user_id'] = $user_pharmacist['user_id'];
$params['type'] = 2; $params['type'] = 2;
$params['is_latest'] = 1; $params['is_latest'] = 1;
$pharmacist_user_ca_cert = $this->buildLegacyCaCertPayload($order_prescription['order_prescription_id'], 'pharmacist'); $pharmacist_user_ca_cert = UserCaCert::getOne($params);
if (empty($pharmacist_user_ca_cert)){ if (empty($pharmacist_user_ca_cert)){
$this->line("错误:无药师ca数据"); $this->line("错误:无药师ca数据");
return false; return false;
@@ -544,13 +533,6 @@ class ReportRegulatoryCommand extends HyperfCommand
$data['recipeNo'] = $order_prescription['order_prescription_id']; // 医院处方编号 $data['recipeNo'] = $order_prescription['order_prescription_id']; // 医院处方编号
$data['cityId'] = "510100"; // 城市ID(参考地区字段) $data['cityId'] = "510100"; // 城市ID(参考地区字段)
$pharmacist_ca_data = $this->getStoredPrescriptionCaData($order_prescription['order_prescription_id'], 'pharmacist');
$data['caSupplier'] = $pharmacist_ca_data['caSupplier'] ?? "";
$data['caSignType'] = $pharmacist_ca_data['caSignType'] ?? "";
$data['caSignTime'] = $pharmacist_ca_data['caSignTime'] ?? "";
$data['caSignOriginaltext'] = $pharmacist_ca_data['caSignOriginaltext'] ?? "";
$data['caSignText'] = $pharmacist_ca_data['caSignText'] ?? "";
return $data; return $data;
} }
@@ -562,7 +544,6 @@ class ReportRegulatoryCommand extends HyperfCommand
*/ */
private function getReportTransferPrescriptionData(array|object $order_inquiry, array|object $order_prescription): bool|array private function getReportTransferPrescriptionData(array|object $order_inquiry, array|object $order_prescription): bool|array
{ {
return $this->getReportTransferPrescriptionDataV2($order_inquiry, $order_prescription);
// 获取医生数据 // 获取医生数据
$params = array(); $params = array();
$params['doctor_id'] = $order_prescription['doctor_id']; $params['doctor_id'] = $order_prescription['doctor_id'];
@@ -657,7 +638,7 @@ class ReportRegulatoryCommand extends HyperfCommand
$params['user_id'] = $user_doctor['user_id']; $params['user_id'] = $user_doctor['user_id'];
$params['type'] = 2; $params['type'] = 2;
$params['is_latest'] = 1; $params['is_latest'] = 1;
$doctor_user_ca_cert = $this->buildLegacyCaCertPayload($order_prescription['order_prescription_id'], 'doctor'); $doctor_user_ca_cert = UserCaCert::getOne($params);
if (empty($doctor_user_ca_cert)){ if (empty($doctor_user_ca_cert)){
$this->line("错误:无医生ca数据"); $this->line("错误:无医生ca数据");
return false; return false;
@@ -668,7 +649,7 @@ class ReportRegulatoryCommand extends HyperfCommand
$params['user_id'] = $user_pharmacist['user_id']; $params['user_id'] = $user_pharmacist['user_id'];
$params['type'] = 2; $params['type'] = 2;
$params['is_latest'] = 1; $params['is_latest'] = 1;
$pharmacist_user_ca_cert = $this->buildLegacyCaCertPayload($order_prescription['order_prescription_id'], 'pharmacist'); $pharmacist_user_ca_cert = UserCaCert::getOne($params);
if (empty($pharmacist_user_ca_cert)){ if (empty($pharmacist_user_ca_cert)){
$this->line("错误:无药师ca数据"); $this->line("错误:无药师ca数据");
return false; return false;
@@ -716,160 +697,6 @@ class ReportRegulatoryCommand extends HyperfCommand
$data['recipeNo'] = $order_prescription['order_prescription_id']; // 医院处方编号 $data['recipeNo'] = $order_prescription['order_prescription_id']; // 医院处方编号
$data['cityId'] = "510100"; // 城市ID(参考地区字段) $data['cityId'] = "510100"; // 城市ID(参考地区字段)
$pharmacist_ca_data = $this->getStoredPrescriptionCaData($order_prescription['order_prescription_id'], 'pharmacist');
$data['caSupplier'] = $pharmacist_ca_data['caSupplier'] ?? "";
$data['caSignType'] = $pharmacist_ca_data['caSignType'] ?? "";
$data['caSignTime'] = $pharmacist_ca_data['caSignTime'] ?? "";
$data['caSignOriginaltext'] = $pharmacist_ca_data['caSignOriginaltext'] ?? "";
$data['caSignText'] = $pharmacist_ca_data['caSignText'] ?? "";
return $data;
}
private function getReportTransferPrescriptionDataV2(array|object $order_inquiry, array|object $order_prescription): bool|array
{
$params = array();
$params['doctor_id'] = $order_prescription['doctor_id'];
$user_doctor = UserDoctor::getOne($params);
if (empty($user_doctor)) {
$this->line("閿欒锛氬尰鐢熸暟鎹敊璇?");
return false;
}
$params = array();
$params['doctor_id'] = $order_prescription['doctor_id'];
$user_doctor_info = UserDoctorInfo::getOne($params);
if (empty($user_doctor_info)) {
$this->line("閿欒锛氬尰鐢熻鎯呮暟鎹敊璇?");
return false;
}
$params = array();
$params['department_custom_id'] = $user_doctor['department_custom_id'];
$hospital_department_custom = HospitalDepartmentCustom::getOne($params);
if (empty($hospital_department_custom)) {
$this->line("閿欒锛氬尰鐢熻嚜瀹氫箟鏁版嵁閿欒");
return false;
}
$params = array();
$params['family_id'] = $order_inquiry['family_id'];
$patient_family = PatientFamily::getOne($params);
if (empty($patient_family)) {
$this->line("閿欒锛氶棶璇婃偅鑰呮暟鎹敊璇?");
return false;
}
$params = array();
$params['order_inquiry_id'] = $order_inquiry['order_inquiry_id'];
$params['status'] = 1;
$order_inquiry_case = OrderInquiryCase::getOne($params);
if (empty($order_inquiry_case)) {
$this->line("閿欒锛氭偅鑰呴棶璇婄梾渚嬮敊璇?");
return false;
}
$params = array();
$params['pharmacist_id'] = $order_prescription['pharmacist_id'];
$user_pharmacist = UserPharmacist::getOne($params);
if (empty($user_pharmacist)) {
$this->line("閿欒锛氳嵂甯堟暟鎹敊璇?");
return false;
}
$params = array();
$params['pharmacist_id'] = $order_prescription['pharmacist_id'];
$user_pharmacist_info = UserPharmacistInfo::getOne($params);
if (empty($user_pharmacist_info)) {
$this->line("閿欒锛氳嵂甯堣鎯呮暟鎹敊璇?");
return false;
}
$params = array();
$params['order_prescription_id'] = $order_prescription['order_prescription_id'];
$order_prescription_icd = OrderPrescriptionIcd::getList($params);
if (empty($order_prescription_icd)) {
$this->line("閿欒锛氭棤澶嶈瘖鐤剧梾璇婃柇鏁版嵁");
return false;
}
$icd_name = "";
$icd_name_data = array_column($order_prescription_icd->toArray(), 'icd_name');
if (!empty($icd_name_data)) {
if (count($icd_name_data) > 1) {
$icd_name = implode('|', $icd_name_data);
} else {
$icd_name = $icd_name_data[0];
}
}
$order_prescription_product = $this->getPreProductData($order_prescription['order_prescription_id']);
if (empty($order_prescription_product)) {
$this->line("閿欒锛氭棤澶勬柟鍟嗗搧鏁版嵁");
return false;
}
$doctor_user_ca_cert = $this->buildLegacyCaCertPayload($order_prescription['order_prescription_id'], 'doctor');
if (empty($doctor_user_ca_cert)) {
$this->line("閿欒锛氭棤鍖荤敓ca鏁版嵁");
return false;
}
$pharmacist_user_ca_cert = $this->buildLegacyCaCertPayload($order_prescription['order_prescription_id'], 'pharmacist');
if (empty($pharmacist_user_ca_cert)) {
$this->line("閿欒锛氭棤鑽笀ca鏁版嵁");
return false;
}
$data = array();
$data['thirdUniqueid'] = $order_inquiry['order_inquiry_id'];
$data['orgName'] = "鎴愰兘閲戠墰娆f鐩哥収浜掕仈缃戝尰闄?";
$data['orgCode'] = "MA6CGUDA251010619D2112";
$data['section'] = $hospital_department_custom['department_name'];
$data['sectionCode'] = $hospital_department_custom['department_code'];
$data['docName'] = $user_doctor['user_name'];
$data['docCertificateNum'] = $user_doctor_info['qualification_cert_num'];
$data['pharmacistName'] = $user_pharmacist_info['card_name'];
$data['pharmacistOrg'] = "鎴愰兘閲戠墰娆f鐩哥収浜掕仈缃戝尰闄?";
$data['pharmacistCertificateNum'] = $user_pharmacist_info['qualification_cert_num'];
$data['furtherConsultNo'] = $order_inquiry['order_inquiry_id'];
$data['furtherConsultDiagnosis'] = $icd_name;
$data['patientName'] = $order_inquiry['patient_name'];
$data['patientSex'] = $order_inquiry['patient_sex'] == 0 ?: 1;
$data['patientAge'] = (int) $order_inquiry['patient_age'];
$data['patientIdcardType'] = 1;
$data['patientIdcardNum'] = $patient_family['id_number'];
$data['feeType'] = 1;
$data['medicalHistory'] = $order_inquiry_case['disease_desc'];
$data['recipeTime'] = $order_prescription['doctor_created_time'];
$data['recipeType'] = 2;
$data['reviewTime'] = $order_prescription['pharmacist_verify_time'];
$data['recipeUnitPrice'] = $order_prescription_product['amount_total'];
$data['drugName'] = $order_prescription_product['drug_name'];
$data['drugCode'] = $order_prescription_product['drug_code'];
$data['drugCommonName'] = $order_prescription_product['drug_common_name'];
$data['specification'] = $order_prescription_product['specification'];
$data['frequency'] = $order_prescription_product['frequency'];
$data['usage'] = $order_prescription_product['usage'];
$data['doseUnit'] = $order_prescription_product['dose_unit'];
$data['doseEachTime'] = $order_prescription_product['dose_each_time'];
$data['medicationDays'] = $order_prescription_product['medication_days'];
$data['quantity'] = $order_prescription_product['quantity'];
$data['drugPackage'] = $order_prescription_product['drug_package'];
$data['recipeAllPrice'] = $order_prescription_product['amount_total'];
$data['uploadTime'] = date("Y-m-d H:i:s", time());
$data['docCaSign'] = $doctor_user_ca_cert['cert_base64'];
$data['pharmacistCaSign'] = $pharmacist_user_ca_cert['cert_base64'];
$data['recipeNo'] = $order_prescription['order_prescription_id'];
$data['cityId'] = "510100";
$pharmacist_ca_data = $this->getStoredPrescriptionCaData($order_prescription['order_prescription_id'], 'pharmacist');
$data['caSupplier'] = $pharmacist_ca_data['caSupplier'] ?? "";
$data['caSignType'] = $pharmacist_ca_data['caSignType'] ?? "";
$data['caSignTime'] = $pharmacist_ca_data['caSignTime'] ?? "";
$data['caSignOriginaltext'] = $pharmacist_ca_data['caSignOriginaltext'] ?? "";
$data['caSignText'] = $pharmacist_ca_data['caSignText'] ?? "";
return $data; return $data;
} }
@@ -909,9 +736,9 @@ class ReportRegulatoryCommand extends HyperfCommand
$specification = $item['product_spec']; // 规格 $specification = $item['product_spec']; // 规格
$frequency = $item['frequency_use']; // 使用频度 $frequency = $item['frequency_use']; // 使用频度
$usage = $item['single_use']; // 用法 $usage = $item['single_use']; // 用法
$dose_unit = $item['single_unit']; // 剂量单位 $dose_unit = $product['single_unit']; // 剂量单位
$dose_each_time = $item['single_unit']; // 每次剂量 $dose_each_time = $product['single_unit']; // 每次剂量
$medication_days = (double)$item['available_days']; // 用药天数 $medication_days = (double)$product['available_days']; // 用药天数
$quantity = (double)$item['prescription_product_num']; // 数量 $quantity = (double)$item['prescription_product_num']; // 数量
$drug_package = $item['packaging_unit']; // 药品包装 $drug_package = $item['packaging_unit']; // 药品包装
} else { } else {
@@ -921,22 +748,14 @@ class ReportRegulatoryCommand extends HyperfCommand
$specification = $specification . "|" . $item['product_spec']; // 规格 $specification = $specification . "|" . $item['product_spec']; // 规格
$frequency = $frequency . "|" . $item['frequency_use']; // 使用频度 $frequency = $frequency . "|" . $item['frequency_use']; // 使用频度
$usage = $usage . "|" . $item['single_use']; // 用法 $usage = $usage . "|" . $item['single_use']; // 用法
$dose_unit = $dose_unit . "|" . $item['single_unit']; // 剂量单位 $dose_unit = $dose_unit . "|" . $product['single_unit']; // 剂量单位
$dose_each_time = $dose_each_time . "|" . $item['single_unit']; // 每次剂量 $dose_each_time = $dose_each_time . "|" . $product['single_unit']; // 每次剂量
$medication_days = $medication_days . "|" . (double)$item['available_days']; // 用药天数 $medication_days = $medication_days . "|" . (double)$product['available_days']; // 用药天数
$quantity = $quantity . "|" . (double)$item['prescription_product_num']; // 数量 $quantity = $quantity . "|" . (double)$item['prescription_product_num']; // 数量
$drug_package = $drug_package . "|" . $item['packaging_unit']; // 药品包装 $drug_package = $drug_package . "|" . $item['packaging_unit']; // 药品包装
} }
$amount_total = bcadd( $amount_total += $item['product_price'] * $item['prescription_product_num'];
(string) $amount_total,
bcmul(
(string) ($item['product_price'] ?? $product['product_price'] ?? 0),
(string) $item['prescription_product_num'],
2
),
2
);
} }
$result = array(); $result = array();
@@ -956,121 +775,11 @@ class ReportRegulatoryCommand extends HyperfCommand
return $result; return $result;
} }
private function getPreProductDetailData(string $order_prescription_id): array
{
$params = array();
$params['order_prescription_id'] = $order_prescription_id;
$order_prescription_product = OrderPrescriptionProduct::getList($params);
if (empty($order_prescription_product)) {
$this->line("错误:无处方药品数据");
return [];
}
$result = [];
foreach ($order_prescription_product as $item) {
$params = array();
$params['product_id'] = $item['product_id'];
$product = Product::getWithAmountOne($params);
if (empty($product)) {
$this->line("错误:无药品数据");
return [];
}
$amount_total = bcmul(
(string) ($item['product_price'] ?? $product['product_price'] ?? 0),
(string) $item['prescription_product_num'],
2
);
$result[] = [
'drug_name' => (string) ($item['product_name'] ?? ''),
'drug_code' => (string) ($product['product_pharmacy_code'] ?? ''),
'drug_common_name' => (string) ($product['common_name'] ?? ''),
'specification' => (string) ($item['product_spec'] ?? ''),
'frequency' => (string) ($item['frequency_use'] ?? ''),
'usage' => (string) ($item['single_use'] ?? ''),
'dose_unit' => (string) ($item['single_unit'] ?? $product['single_unit'] ?? ''),
'dose_each_time' => (string) ($item['single_unit'] ?? $product['single_unit'] ?? ''),
'medication_days' => (string) ($item['available_days'] ?? $product['available_days'] ?? ''),
'quantity' => (string) $item['prescription_product_num'],
'drug_package' => (string) ($item['packaging_unit'] ?? ''),
'product_price' => (string) ($item['product_price'] ?? $product['product_price'] ?? 0),
'amount_total' => $amount_total,
];
}
return $result;
}
private function getReportPrescriptionDetailData(
array|object $order_prescription,
array $report_prescription_data
): array {
$product_details = $this->getPreProductDetailData((string) $order_prescription['order_prescription_id']);
if (empty($product_details)) {
return [];
}
$result = [];
foreach ($product_details as $detail) {
$row = $report_prescription_data;
$row['recipeUnitPrice'] = $detail['product_price'];
$row['drugName'] = $detail['drug_name'];
$row['drugCode'] = $detail['drug_code'];
$row['drugCommonName'] = $detail['drug_common_name'];
$row['specification'] = $detail['specification'];
$row['frequency'] = $detail['frequency'];
$row['usage'] = $detail['usage'];
$row['doseUnit'] = $detail['dose_unit'];
$row['doseEachTime'] = $detail['dose_each_time'];
$row['medicationDays'] = $detail['medication_days'];
$row['quantity'] = $detail['quantity'];
$row['drugPackage'] = $detail['drug_package'];
$row['recipeAllPrice'] = $detail['amount_total'];
$row['uploadTime'] = date("Y-m-d H:i:s", time());
$result[] = $row;
}
return $result;
}
/** /**
* 获取上报数据-网络咨询 * 获取上报数据-网络咨询
* @param array|object $order_inquiry * @param array|object $order_inquiry
* @return array * @return array
*/ */
private function getStoredPrescriptionCaData(string|int $order_prescription_id, string $role): array
{
$params = array();
$params['order_prescription_id'] = $order_prescription_id;
$order_prescription_file = OrderPrescriptionFile::getOne($params);
if (empty($order_prescription_file)) {
return [];
}
$prefix = $role === 'doctor' ? 'doctor' : 'pharmacist';
return [
'caSupplier' => (string) ($order_prescription_file[$prefix . '_ca_supplier'] ?? ''),
'caSignType' => (string) ($order_prescription_file[$prefix . '_ca_sign_type'] ?? ''),
'caSignTime' => (string) ($order_prescription_file[$prefix . '_ca_sign_time'] ?? ''),
'caSignOriginaltext' => (string) ($order_prescription_file[$prefix . '_ca_sign_originaltext'] ?? ''),
'caSignText' => (string) ($order_prescription_file[$prefix . '_ca_sign_text'] ?? ''),
];
}
private function buildLegacyCaCertPayload(string|int $order_prescription_id, string $role): array
{
$ca_data = $this->getStoredPrescriptionCaData($order_prescription_id, $role);
if (empty($ca_data['caSignText'])) {
return [];
}
return [
'cert_base64' => $ca_data['caSignText'],
];
}
private function getConsultData(array|object $order_inquiry): array private function getConsultData(array|object $order_inquiry): array
{ {
// 获取医生数据 // 获取医生数据
@@ -1127,7 +836,6 @@ class ReportRegulatoryCommand extends HyperfCommand
$data['section'] = $hospital_department_custom['department_name'];//科室名称 $data['section'] = $hospital_department_custom['department_name'];//科室名称
$data['sectionCode'] = $hospital_department_custom['department_code'];//科室编码 $data['sectionCode'] = $hospital_department_custom['department_code'];//科室编码
$data['docName'] = $user_doctor['user_name'];// 姓名(医师、护师、技师) $data['docName'] = $user_doctor['user_name'];// 姓名(医师、护师、技师)
$data['doc_idcard'] = $user_doctor_info['card_num']; // 医生身份证号
$data['certificateNum'] = $user_doctor_info['qualification_cert_num']; // 执业资格证号 $data['certificateNum'] = $user_doctor_info['qualification_cert_num']; // 执业资格证号
$data['patientName'] = $order_inquiry['patient_name']; // 患者姓名 $data['patientName'] = $order_inquiry['patient_name']; // 患者姓名
$data['patientAge'] = (int)$order_inquiry['patient_age']; // 患者年龄 $data['patientAge'] = (int)$order_inquiry['patient_age']; // 患者年龄
@@ -1284,13 +992,6 @@ class ReportRegulatoryCommand extends HyperfCommand
$data['cityId'] = "510100"; // 城市ID(参考地区字段) $data['cityId'] = "510100"; // 城市ID(参考地区字段)
$data['isMark'] = 1;//是否留痕 1:代表留痕;0:代表未留痕 $data['isMark'] = 1;//是否留痕 1:代表留痕;0:代表未留痕
$doctor_ca_data = $this->getStoredPrescriptionCaData($order_prescription['order_prescription_id'], 'doctor');
$data['caSupplier'] = $doctor_ca_data['caSupplier'] ?? "";
$data['caSignType'] = $doctor_ca_data['caSignType'] ?? "";
$data['caSignTime'] = $doctor_ca_data['caSignTime'] ?? "";
$data['caSignOriginaltext'] = $doctor_ca_data['caSignOriginaltext'] ?? "";
$data['caSignText'] = $doctor_ca_data['caSignText'] ?? "";
return $data; return $data;
} }
} }
-6
View File
@@ -89,12 +89,6 @@ class TestController extends AbstractController
// 疾病名称 // 疾病名称
protected string $icd_name; protected string $icd_name;
public function testError()
{
// 模拟触发 SQLSTATE[42S22]: Column not found 数据库报错
Db::select("SELECT nonexistent_column_test FROM gdxz_user_ca_cert LIMIT 1");
}
public function test(){ public function test(){
// $this->test_8(); // $this->test_8();
// $this->test_3(); // $this->test_3();
+1 -1
View File
@@ -33,7 +33,7 @@ class OrderPrescriptionFile extends Model
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
*/ */
protected array $fillable = ['prescription_file_id', 'order_prescription_id', 'doctor_ca_file_id', 'doctor_ca_supplier', 'doctor_ca_sign_type', 'doctor_ca_sign_originaltext', 'doctor_ca_sign_text', 'doctor_ca_sign_time', 'pharmacist_ca_supplier', 'pharmacist_ca_sign_type', 'pharmacist_ca_sign_originaltext', 'pharmacist_ca_sign_text', 'pharmacist_ca_sign_time', 'hospital_ca_file_id', 'prescription_img_oss_path', 'prescription_pdf_oss_path', 'is_converted_pdf', 'created_at', 'updated_at']; protected array $fillable = ['prescription_file_id', 'order_prescription_id', 'doctor_ca_file_id', 'hospital_ca_file_id', 'prescription_img_oss_path', 'prescription_pdf_oss_path', 'is_converted_pdf', 'created_at', 'updated_at'];
protected string $primaryKey = "prescription_file_id"; protected string $primaryKey = "prescription_file_id";
+1 -1
View File
@@ -40,7 +40,7 @@ class OrderPrescriptionProduct extends Model
/** /**
* The attributes that are mass assignable. * The attributes that are mass assignable.
*/ */
protected array $fillable = ['prescription_product_id', 'order_prescription_id', 'product_id', 'use_status', 'prescription_product_num', 'product_name', 'product_price', 'product_spec', 'license_number', 'manufacturer', 'single_unit', 'single_use', 'packaging_unit', 'frequency_use', 'available_days', 'created_at', 'updated_at']; protected array $fillable = ['prescription_product_id', 'order_prescription_id', 'product_id', 'use_status', 'prescription_product_num', 'product_name', 'product_spec', 'license_number', 'manufacturer', 'single_unit', 'single_use', 'packaging_unit', 'frequency_use', 'available_days', 'created_at', 'updated_at'];
protected string $primaryKey = "prescription_product_id"; protected string $primaryKey = "prescription_product_id";
+2 -10
View File
@@ -76,17 +76,9 @@ class ReportRegulatory extends Model
* @param array $data * @param array $data
* @return ReportRegulatory|\Hyperf\Database\Model\Model * @return ReportRegulatory|\Hyperf\Database\Model\Model
*/ */
// public static function addReportRegulatory(array $data): ReportRegulatory|\Hyperf\Database\Model\Model public static function addReportRegulatory(array $data): ReportRegulatory|\Hyperf\Database\Model\Model
// {
// return self::create($data);
// }
/**
* 暂时不上报监管
*/
public static function addReportRegulatory(array $data): bool
{ {
// 直接返回成功,不执行创建操作 return self::create($data);
return true;
} }
/** /**
+21 -50
View File
@@ -56,8 +56,6 @@ class CaService extends BaseService
// 处方pdf oss地址 // 处方pdf oss地址
protected string $prescription_pdf_oss_path; protected string $prescription_pdf_oss_path;
protected array $sign_result = [];
/** /**
* 初始化类,此处会获取基础数据 * 初始化类,此处会获取基础数据
* @param array|object $order_prescription 处方表数据 * @param array|object $order_prescription 处方表数据
@@ -256,33 +254,13 @@ class CaService extends BaseService
$data['product'][] = $product; $data['product'][] = $product;
} }
dump($this->entity_id);
$cert_sign_result = $CaOnline->getCertSign($this->entity_id, $this->entity_id, $data); $cert_sign_result = $CaOnline->getCertSign($this->entity_id, $this->entity_id, $data);
// 验证云证书签名 验证无需处理,只要不返回错误即可 // 验证云证书签名 验证无需处理,只要不返回错误即可
$CaOnline->verifyPkcs7($cert_sign_result['signP7'], $data); $CaOnline->verifyPkcs7($cert_sign_result['signP7'], $data);
$this->cert_serial_number = $cert_sign_result['certSerialnumber']; $this->cert_serial_number = $cert_sign_result['certSerialnumber'];
$sign_originaltext = hash_hmac("sha1", json_encode($data, JSON_UNESCAPED_UNICODE), config('ca.online.secret'));
$timestamp_sign = "";
try {
$timestamp_result = $CaOnline->getTimestampSign($sign_originaltext);
if (is_array($timestamp_result)) {
$timestamp_sign = $timestamp_result['signedData'] ?? "";
} elseif (is_string($timestamp_result)) {
$timestamp_sign = $timestamp_result;
}
} catch (\Throwable $throwable) {
$timestamp_sign = "";
}
$this->sign_result = [
'ca_supplier' => (string) config('regulatory_platform.ca_supplier', '2'),
'ca_sign_type' => (string) config('regulatory_platform.ca_sign_type', '1'),
'ca_sign_originaltext' => $sign_originaltext,
'ca_sign_text' => $cert_sign_result['signP7'] ?? "",
'ca_sign_time' => $timestamp_sign,
'cert_serial_number' => $cert_sign_result['certSerialnumber'] ?? "",
];
} }
/** /**
@@ -290,11 +268,6 @@ class CaService extends BaseService
* @param array|object $order_prescription * @param array|object $order_prescription
* @return string * @return string
*/ */
public function getSignResult(): array
{
return $this->sign_result;
}
public function createPrescriptionImgPdf(array|object $order_prescription): string public function createPrescriptionImgPdf(array|object $order_prescription): string
{ {
// 打开基础处方图片 // 打开基础处方图片
@@ -528,31 +501,29 @@ class CaService extends BaseService
$CaOnline = new CaOnline(); $CaOnline = new CaOnline();
// 检测是否已添加签章配置 // 检测是否已添加签章配置
// $params = array(); $params = array();
// $params['cert_serial_number'] = $this->cert_serial_number; $params['cert_serial_number'] = $this->cert_serial_number;
// $user_ca_cert = UserCaCert::getOne($params); $user_ca_cert = UserCaCert::getOne($params);
// if (empty($user_ca_cert)){ if (empty($user_ca_cert)){
// // Mock empty cert to bypass check when CA is skipped throw new BusinessException("未申请证书");
// $user_ca_cert = ['is_sign_config' => 1, 'cert_id' => 0]; }
// }
// if ($user_ca_cert['is_sign_config'] == 0){ if ($user_ca_cert['is_sign_config'] == 0){
// // 添加签章配置 // 添加签章配置
// $data = array(); $data = array();
// $data['sign_param'] = json_encode($sign_param); $data['sign_param'] = json_encode($sign_param);
// $data['seal_img'] = $sign_image; $data['seal_img'] = $sign_image;
// $CaOnline->addUserSignConfig($this->entity_id,$this->card_num,$data); $CaOnline->addUserSignConfig($this->entity_id,$this->card_num,$data);
// $params = array(); $params = array();
// $params['cert_id'] = $user_ca_cert['cert_id']; $params['cert_id'] = $user_ca_cert['cert_id'];
// $data = array();
// $data['sign_config'] = json_encode($sign_param);
// $data['is_sign_config'] = 1;
// UserCaCert::edit($params,$data);
// }
$data = array();
$data['sign_config'] = json_encode($sign_param);
$data['is_sign_config'] = 1;
UserCaCert::edit($params,$data);
}
// 打开处方pdf文件 // 打开处方pdf文件
$pdf_file = fopen($this->prescription_pdf_local_path, 'r'); $pdf_file = fopen($this->prescription_pdf_local_path, 'r');
@@ -571,4 +542,4 @@ class CaService extends BaseService
return $sign_pdf_result[0]['fileId']; return $sign_pdf_result[0]['fileId'];
} }
} }
+2 -7
View File
@@ -152,6 +152,7 @@ class OrderPrescriptionService extends BaseService
throw new BusinessException("医生开方日期错误"); throw new BusinessException("医生开方日期错误");
} }
dump($user_id);
$CaService = new CaService($order_prescription,$type,$user_id); $CaService = new CaService($order_prescription,$type,$user_id);
// 获取云证书签名+验证云证书签名 // 获取云证书签名+验证云证书签名
@@ -166,15 +167,9 @@ class OrderPrescriptionService extends BaseService
// 进行处方pdf签章 // 进行处方pdf签章
$file_id = $CaService->addSignPdf($type); $file_id = $CaService->addSignPdf($type);
$sign_result = $CaService->getSignResult();
$result = array(); $result = array();
$result['prescription_img_oss_path'] = $prescription_img_oss_path ?? ""; $result['prescription_img_oss_path'] = $prescription_img_oss_path ?? "";
$result['file_id'] = $file_id; $result['file_id'] = $file_id;
$result['ca_supplier'] = $sign_result['ca_supplier'] ?? "";
$result['ca_sign_type'] = $sign_result['ca_sign_type'] ?? "";
$result['ca_sign_originaltext'] = $sign_result['ca_sign_originaltext'] ?? "";
$result['ca_sign_text'] = $sign_result['ca_sign_text'] ?? "";
$result['ca_sign_time'] = $sign_result['ca_sign_time'] ?? "";
return $result; return $result;
} catch (\Throwable $e) { } catch (\Throwable $e) {
@@ -575,4 +570,4 @@ class OrderPrescriptionService extends BaseService
return $promotion; return $promotion;
} }
} }
+1 -7
View File
@@ -1730,7 +1730,6 @@ class UserDoctorService extends BaseService
$data['product_id'] = $item['product_id']; $data['product_id'] = $item['product_id'];
$data['prescription_product_num'] = $item['prescription_product_num']; $data['prescription_product_num'] = $item['prescription_product_num'];
$data['product_name'] = $product['product_name']; $data['product_name'] = $product['product_name'];
$data['product_price'] = $product['product_price'];
$data['product_spec'] = $product['product_spec']; $data['product_spec'] = $product['product_spec'];
$data['license_number'] = $product['license_number']; $data['license_number'] = $product['license_number'];
$data['manufacturer'] = $product['manufacturer']; $data['manufacturer'] = $product['manufacturer'];
@@ -1800,11 +1799,6 @@ class UserDoctorService extends BaseService
$data = array(); $data = array();
$data['order_prescription_id'] = $order_prescription->order_prescription_id; $data['order_prescription_id'] = $order_prescription->order_prescription_id;
$data['doctor_ca_file_id'] = $prescription_open_result['file_id']; $data['doctor_ca_file_id'] = $prescription_open_result['file_id'];
$data['doctor_ca_supplier'] = $prescription_open_result['ca_supplier'] ?? "";
$data['doctor_ca_sign_type'] = $prescription_open_result['ca_sign_type'] ?? "";
$data['doctor_ca_sign_originaltext'] = $prescription_open_result['ca_sign_originaltext'] ?? "";
$data['doctor_ca_sign_text'] = $prescription_open_result['ca_sign_text'] ?? "";
$data['doctor_ca_sign_time'] = $prescription_open_result['ca_sign_time'] ?? "";
$data['prescription_img_oss_path'] = $prescription_open_result['prescription_img_oss_path']; $data['prescription_img_oss_path'] = $prescription_open_result['prescription_img_oss_path'];
$order_prescription_file = OrderPrescriptionFile::addOrderPrescriptionFile($data); $order_prescription_file = OrderPrescriptionFile::addOrderPrescriptionFile($data);
if (empty($order_prescription_file)){ if (empty($order_prescription_file)){
@@ -3165,4 +3159,4 @@ class UserDoctorService extends BaseService
return $multi_point_enable; return $multi_point_enable;
} }
} }
-1
View File
@@ -39,7 +39,6 @@ class Auth
"/basic/keyword/search" => "get", // 获取热门搜索关键词 "/basic/keyword/search" => "get", // 获取热门搜索关键词
"/test/uninquiry" => "get", // 获取未接诊的医生 "/test/uninquiry" => "get", // 获取未接诊的医生
"/test/refund" => "post", // 测试退款 "/test/refund" => "post", // 测试退款
"/test/error" => "get", // 测试报错
"/test" => "get", // 测试 "/test" => "get", // 测试
"/callback/detection" => "post", // 检测所结果回调 "/callback/detection" => "post", // 检测所结果回调
"/callback/video/trtc" => "post", // 音视频回调 "/callback/video/trtc" => "post", // 音视频回调
+2 -2
View File
@@ -25,8 +25,8 @@ class Log
self::getInstance()->{$name}(...$arguments); self::getInstance()->{$name}(...$arguments);
} }
public static function getInstance(string $name = 'app', string $group = 'default'): LoggerInterface public static function getInstance(string $name = 'app'): LoggerInterface
{ {
return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name, $group); return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);
} }
} }
-30
View File
@@ -51,34 +51,4 @@ return [
], ],
'formatter' => $formatter, 'formatter' => $formatter,
], ],
'regulatory_platform_http_detail' => [
'handler' => [
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
'filename' => BASE_PATH . '/runtime/logs/regulatory-platform-http-detail.log',
'level' => Monolog\Logger::INFO,
],
],
'formatter' => $formatter,
],
'regulatory_platform_business' => [
'handler' => [
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
'filename' => BASE_PATH . '/runtime/logs/regulatory-platform-business.log',
'level' => Monolog\Logger::INFO,
],
],
'formatter' => $formatter,
],
'regulatory_platform_token' => [
'handler' => [
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
'filename' => BASE_PATH . '/runtime/logs/regulatory-platform-token.log',
'level' => Monolog\Logger::INFO,
],
],
'formatter' => $formatter,
],
]; ];
-6
View File
@@ -121,12 +121,6 @@ return [
"client_id" => env('REG_PLAT_CLIENT_ID', '09b117f8d1eb4dbfbf565447205ea60f'), "client_id" => env('REG_PLAT_CLIENT_ID', '09b117f8d1eb4dbfbf565447205ea60f'),
"client_secret" => env('REG_PLAT_CLIENT_SECRET', 'dcfd9223a3f448b0aae83ce22cdcc015'), "client_secret" => env('REG_PLAT_CLIENT_SECRET', 'dcfd9223a3f448b0aae83ce22cdcc015'),
"api_url" => env('REG_PLAT_APP_URL', 'https://202.61.88.184:19200/'), "api_url" => env('REG_PLAT_APP_URL', 'https://202.61.88.184:19200/'),
"sm4_key" => env('REG_PLAT_SM4_KEY', 'e0e295da97ed46cc9ad71b61ed361721'),
"sm4_iv" => env('REG_PLAT_SM4_IV', '8a1f69a58603416a9d5b93c4bb67f72f'),
"sm2_private_key" => env('REG_PLAT_SM2_PRIVATE_KEY', 'bbc97b0418cc92b8f3b7b7764e554beed6b3adb1aa9bfb9e7839583e5ccf4722'),
"sm2_public_key" => env('REG_PLAT_SM2_PUBLIC_KEY', '04fca188451748a35b8c14890a0270fbe787e74f2286b72f6305939c8d527d1fd9fec2926cc0ff6c4f04cfbee2a3d65230565691a8f8453b44665d2b6fbbc79c91'),
"ca_supplier" => env('REG_PLAT_CA_SUPPLIER', '2'),
"ca_sign_type" => env('REG_PLAT_CA_SIGN_TYPE', '1'),
], ],
'kuaidi100' => [ // 快递100 'kuaidi100' => [ // 快递100
"key" => env('LOGISTICS_KEY', 'Mpjjgebe8764'), "key" => env('LOGISTICS_KEY', 'Mpjjgebe8764'),
-1
View File
@@ -912,7 +912,6 @@ Router::addGroup('/case', function () {
// 测试使用 // 测试使用
Router::addGroup('/test', function () { Router::addGroup('/test', function () {
Router::get('', [TestController::class, 'test']); Router::get('', [TestController::class, 'test']);
Router::get('/error', [TestController::class, 'testError']);
// 获取未接诊的医生 // 获取未接诊的医生
Router::get('/uninquiry', [TestController::class, 'uninquiry']); Router::get('/uninquiry', [TestController::class, 'uninquiry']);
+1 -37
View File
@@ -46,7 +46,6 @@ abstract class Ca
*/ */
public function getCertSign(string $user_id, string $pin, array $data): mixed public function getCertSign(string $user_id, string $pin, array $data): mixed
{ {
return ['signP7' => 'mock_sign_p7', 'certSerialnumber' => 'mock_serial_number'];
$option = [ $option = [
'form_params' => [ 'form_params' => [
'entityId' => $user_id, // 用户唯一标识,由业务系统定义 'entityId' => $user_id, // 用户唯一标识,由业务系统定义
@@ -78,7 +77,6 @@ abstract class Ca
*/ */
public function verifyPkcs7(string $sign_p7, array $data) public function verifyPkcs7(string $sign_p7, array $data)
{ {
return true;
$generator = $this->container->get(IdGeneratorInterface::class); $generator = $this->container->get(IdGeneratorInterface::class);
$option = [ $option = [
@@ -112,40 +110,8 @@ abstract class Ca
* @param array $data * @param array $data
* @return bool * @return bool
*/ */
/**
* Timestamp sign service.
* @param string $to_sign
* @return mixed
*/
public function getTimestampSign(string $to_sign): mixed
{
return ['signedData' => 'mock_timestamp_sign'];
$generator = $this->container->get(IdGeneratorInterface::class);
$option = [
'form_params' => [
'requestId' => $generator->generate(),
'toSign' => $to_sign,
]
];
try {
$response = $this->httpRequest(
$this->api_url . '/signgw-service/api/signgw/timestamap/sign',
$option
);
if (empty($response)) {
throw new BusinessException(HttpEnumCode::getMessage(HttpEnumCode::SERVER_ERROR));
}
return $response;
} catch (GuzzleException $e) {
throw new BusinessException($e->getMessage());
}
}
public function addUserSignConfig(string $user_id, string $card_num, array $data): bool public function addUserSignConfig(string $user_id, string $card_num, array $data): bool
{ {
return true;
$arg = [ $arg = [
'form_params' => [ 'form_params' => [
'userId' => $user_id,//用户标识信息(为云证书entityId) 'userId' => $user_id,//用户标识信息(为云证书entityId)
@@ -263,7 +229,6 @@ abstract class Ca
*/ */
public function addSignPdf(string $user_id, array $data): mixed public function addSignPdf(string $user_id, array $data): mixed
{ {
return [['fileId' => 'mock_file_id']];
$option = [ $option = [
'multipart' => [ 'multipart' => [
[ [
@@ -313,7 +278,6 @@ abstract class Ca
*/ */
public function getSignedFile(string $entity_id, string $file_id): string public function getSignedFile(string $entity_id, string $file_id): string
{ {
return "mock_pdf_content";
$arg = [ $arg = [
'form_params' => [ 'form_params' => [
'userId' => $entity_id,// 用户标识信息(为云证书entityId) 'userId' => $entity_id,// 用户标识信息(为云证书entityId)
@@ -491,4 +455,4 @@ abstract class Ca
return hash_hmac("sha1", $data, $this->secret); return hash_hmac("sha1", $data, $this->secret);
} }
} }
@@ -1,595 +0,0 @@
<?php
declare(strict_types=1);
namespace Extend\RegulatoryPlatform;
use App\Exception\BusinessException;
use function Hyperf\Config\config;
class RegulatoryPlatformProtocol
{
protected const SM2_CURVE_OID = '1.2.156.10197.1.301';
protected const EC_PUBLIC_KEY_OID = '1.2.840.10045.2.1';
protected ?string $clientId;
protected ?string $clientSecret;
protected ?string $sm4KeyHex;
protected ?string $sm4IvHex;
protected ?string $sm2PrivateKey;
protected ?string $sm2PublicKey;
public function __construct(array $config = [])
{
$this->clientId = $this->resolveConfigValue($config, [
'client_id',
'v2.client_id',
'prod.client_id',
'default.client_id',
]);
$this->clientSecret = $this->resolveConfigValue($config, [
'client_secret',
'v2.client_secret',
'prod.client_secret',
'default.client_secret',
]);
$this->sm4KeyHex = $this->resolveConfigValue($config, [
'sm4_key',
'encrypt_key',
'v2.sm4_key',
'crypto.sm4_key',
'sm4.key',
]);
$this->sm4IvHex = $this->resolveConfigValue($config, [
'sm4_iv',
'encrypt_iv',
'v2.sm4_iv',
'crypto.sm4_iv',
'sm4.iv',
]);
$this->sm2PrivateKey = $this->resolveConfigValue($config, [
'sm2_private_key',
'sign_private_key',
'v2.sm2_private_key',
'crypto.sm2_private_key',
'sm2.private_key',
]);
$this->sm2PublicKey = $this->resolveConfigValue($config, [
'sm2_public_key',
'verify_public_key',
'platform_public_key',
'v2.sm2_public_key',
'crypto.sm2_public_key',
'sm2.public_key',
]);
}
public static function fromConfig(?array $config = null): self
{
$config ??= (array) config('regulatory_platform', []);
return new self($config);
}
public function getClientId(): ?string
{
return $this->clientId;
}
public function getClientSecret(): ?string
{
return $this->clientSecret;
}
public function buildRequestEnvelope(
array $payload,
bool $includeClientId = false,
?string $clientId = null,
?string $clientSecret = null
): array {
$plainText = $this->encodeCanonicalJson($payload, true);
return $this->buildRequestEnvelopeFromPlainText($plainText, $includeClientId, $clientId, $clientSecret);
}
public function buildRequestEnvelopeFromPlainText(
string $plainText,
bool $includeClientId = false,
?string $clientId = null,
?string $clientSecret = null
): array {
$resolvedClientId = $clientId ?? $this->requireClientId();
$resolvedClientSecret = $clientSecret ?? $this->requireClientSecret();
$encryptedHex = $this->encrypt($plainText);
$sign = $this->sign($this->buildSignString($resolvedClientId, $encryptedHex, $resolvedClientSecret));
$envelope = [
'sign' => $sign,
'data' => $encryptedHex,
];
if ($includeClientId) {
$envelope['client_id'] = $resolvedClientId;
}
return $envelope;
}
public function decodeResponseEnvelope(
array $response,
bool $verifySignature = false,
?string $clientId = null,
?string $clientSecret = null
): array {
$envelope = $this->extractResponseEnvelope($response);
$resolvedClientId = $clientId ?? $this->requireClientId();
$resolvedClientSecret = $clientSecret ?? $this->requireClientSecret();
if ($verifySignature) {
$verified = $this->verify(
$this->buildSignString($resolvedClientId, $envelope['data'], $resolvedClientSecret),
$envelope['sign']
);
if (! $verified) {
throw new BusinessException('监管平台响应验签失败');
}
}
$plainText = $this->decrypt($envelope['data']);
$decoded = json_decode($plainText, true);
if (! is_array($decoded)) {
throw new BusinessException('监管平台响应解密成功,但 JSON 解析失败');
}
return [
'envelope' => $envelope,
'plain_text' => $plainText,
'decoded' => $decoded,
];
}
public function buildSignString(string $clientId, string $encryptedHex, ?string $clientSecret = null): string
{
$resolvedClientSecret = $clientSecret ?? $this->requireClientSecret();
return sprintf('client_id=%s&data=%s&key=%s', $clientId, $encryptedHex, $resolvedClientSecret);
}
public function encodeCanonicalJson(array $payload, bool $removeEmptyValues = true): string
{
$normalized = $this->canonicalizePayload($payload, $removeEmptyValues);
$json = json_encode(
$normalized,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION
);
if ($json === false) {
throw new BusinessException('监管平台请求 JSON 编码失败');
}
return $json;
}
public function canonicalizePayload(array $payload, bool $removeEmptyValues = true): array
{
$normalized = $this->normalizeValue($payload, $removeEmptyValues);
if (! is_array($normalized)) {
throw new BusinessException('监管平台请求体格式错误');
}
return $normalized;
}
public function encrypt(string $plainText): string
{
$key = $this->decodeHex($this->requireSm4Key(), 'SM4 key');
$iv = $this->decodeHex($this->requireSm4Iv(), 'SM4 iv');
$cipherText = openssl_encrypt($plainText, 'sm4-cbc', $key, OPENSSL_RAW_DATA, $iv);
if ($cipherText === false) {
throw new BusinessException('监管平台 SM4 加密失败: ' . $this->getLastOpenSslError());
}
return strtolower(bin2hex($cipherText));
}
public function decrypt(string $cipherHex): string
{
$cipherRaw = $this->decodeHex($cipherHex, 'SM4 cipher');
$key = $this->decodeHex($this->requireSm4Key(), 'SM4 key');
$iv = $this->decodeHex($this->requireSm4Iv(), 'SM4 iv');
$plainText = openssl_decrypt($cipherRaw, 'sm4-cbc', $key, OPENSSL_RAW_DATA, $iv);
if ($plainText === false) {
throw new BusinessException('监管平台 SM4 解密失败: ' . $this->getLastOpenSslError());
}
return $plainText;
}
public function sign(string $plainText): string
{
$privateKey = openssl_pkey_get_private($this->resolveKeyMaterial($this->sm2PrivateKey, 'SM2 private key'));
if ($privateKey === false) {
throw new BusinessException('监管平台 SM2 私钥加载失败: ' . $this->getLastOpenSslError());
}
$signature = '';
$result = openssl_sign($plainText, $signature, $privateKey, 'sm3');
if ($result !== true) {
throw new BusinessException('监管平台 SM2 签名失败: ' . $this->getLastOpenSslError());
}
return strtolower(bin2hex($signature));
}
public function verify(string $plainText, string $signatureHex): bool
{
$publicKey = openssl_pkey_get_public($this->resolveKeyMaterial($this->sm2PublicKey, 'SM2 public key'));
if ($publicKey === false) {
throw new BusinessException('监管平台 SM2 公钥加载失败: ' . $this->getLastOpenSslError());
}
$signatureRaw = $this->decodeHex($signatureHex, 'SM2 signature');
$result = openssl_verify($plainText, $signatureRaw, $publicKey, 'sm3');
if ($result === -1) {
throw new BusinessException('监管平台 SM2 验签失败: ' . $this->getLastOpenSslError());
}
return $result === 1;
}
protected function extractResponseEnvelope(array $response): array
{
if (isset($response['data']) && is_array($response['data']) && isset($response['data']['data'])) {
$response = $response['data'];
}
$sign = $response['sign'] ?? null;
$data = $response['data'] ?? null;
if (! is_string($sign) || ! is_string($data) || $sign === '' || $data === '') {
throw new BusinessException('监管平台响应报文缺少 sign/data');
}
return [
'sign' => $sign,
'data' => $data,
];
}
protected function normalizeValue(mixed $value, bool $removeEmptyValues): mixed
{
if (is_array($value)) {
if ($this->isAssoc($value)) {
$normalized = [];
ksort($value);
foreach ($value as $key => $item) {
$item = $this->normalizeValue($item, $removeEmptyValues);
if ($removeEmptyValues && $this->isEmptyValue($item)) {
continue;
}
$normalized[$key] = $item;
}
return $normalized;
}
$normalized = [];
foreach ($value as $item) {
$item = $this->normalizeValue($item, $removeEmptyValues);
if ($removeEmptyValues && $this->isEmptyValue($item)) {
continue;
}
$normalized[] = $item;
}
return $normalized;
}
return $value;
}
protected function isAssoc(array $value): bool
{
return array_keys($value) !== range(0, count($value) - 1);
}
protected function isEmptyValue(mixed $value): bool
{
if ($value === null) {
return true;
}
if (is_string($value)) {
return trim($value) === '';
}
if (is_array($value)) {
return $value === [];
}
return false;
}
protected function decodeHex(string $value, string $label): string
{
$value = trim($value);
if ($value === '' || strlen($value) % 2 !== 0 || ! ctype_xdigit($value)) {
throw new BusinessException(sprintf('监管平台 %s 不是合法十六进制字符串', $label));
}
$decoded = hex2bin($value);
if ($decoded === false) {
throw new BusinessException(sprintf('监管平台 %s 十六进制解码失败', $label));
}
return $decoded;
}
protected function resolveKeyMaterial(?string $key, string $label): string
{
$key = trim((string) $key);
if ($key === '') {
throw new BusinessException(sprintf('监管平台 %s 未配置', $label));
}
if (str_starts_with($key, 'file://')) {
$key = substr($key, 7);
}
if (is_file($key)) {
$contents = file_get_contents($key);
if ($contents === false || trim($contents) === '') {
throw new BusinessException(sprintf('监管平台 %s 文件读取失败', $label));
}
return $contents;
}
if ($label === 'SM2 private key' && $this->isRawHexPrivateKey($key)) {
return $this->buildSm2PrivateKeyPem($key, $this->sm2PublicKey);
}
if ($label === 'SM2 public key' && $this->isRawHexPublicKey($key)) {
return $this->buildSm2PublicKeyPem($key);
}
return $key;
}
protected function resolveConfigValue(array $config, array $paths): ?string
{
foreach ($paths as $path) {
$value = $this->getByPath($config, $path);
if ($value !== null && $value !== '') {
return (string) $value;
}
}
return null;
}
protected function getByPath(array $config, string $path): mixed
{
$current = $config;
foreach (explode('.', $path) as $segment) {
if (! is_array($current) || ! array_key_exists($segment, $current)) {
return null;
}
$current = $current[$segment];
}
return $current;
}
protected function requireClientId(): string
{
if (empty($this->clientId)) {
throw new BusinessException('监管平台 client_id 未配置');
}
return $this->clientId;
}
protected function requireClientSecret(): string
{
if (empty($this->clientSecret)) {
throw new BusinessException('监管平台 client_secret 未配置');
}
return $this->clientSecret;
}
protected function requireSm4Key(): string
{
if (empty($this->sm4KeyHex)) {
throw new BusinessException('监管平台 SM4 key 未配置');
}
return $this->sm4KeyHex;
}
protected function requireSm4Iv(): string
{
if (empty($this->sm4IvHex)) {
throw new BusinessException('监管平台 SM4 iv 未配置');
}
return $this->sm4IvHex;
}
protected function getLastOpenSslError(): string
{
$errors = [];
while (($error = openssl_error_string()) !== false) {
$errors[] = $error;
}
return $errors === [] ? 'unknown openssl error' : implode(' | ', $errors);
}
protected function isRawHexPrivateKey(string $key): bool
{
return strlen($key) === 64 && ctype_xdigit($key);
}
protected function isRawHexPublicKey(string $key): bool
{
if (! ctype_xdigit($key)) {
return false;
}
return in_array(strlen($key), [128, 130], true);
}
protected function buildSm2PrivateKeyPem(string $privateKeyHex, ?string $publicKeyHex = null): string
{
$privateKeyRaw = $this->decodeHex($privateKeyHex, 'SM2 private key');
$sequence = $this->derSequence(
$this->derInteger(1),
$this->derOctetString($privateKeyRaw),
$this->derContextSpecific(0, $this->derObjectIdentifier(self::SM2_CURVE_OID))
);
if (is_string($publicKeyHex) && $this->isRawHexPublicKey(trim($publicKeyHex))) {
$publicKeyRaw = $this->normalizeRawPublicKey(trim($publicKeyHex));
$sequence .= $this->derContextSpecific(1, $this->derBitString($publicKeyRaw));
$sequence = $this->derSequence($this->derInteger(1), $this->derOctetString($privateKeyRaw), $this->derContextSpecific(0, $this->derObjectIdentifier(self::SM2_CURVE_OID)), $this->derContextSpecific(1, $this->derBitString($publicKeyRaw)));
}
return $this->pemEncode('EC PRIVATE KEY', $sequence);
}
protected function buildSm2PublicKeyPem(string $publicKeyHex): string
{
$publicKeyRaw = $this->normalizeRawPublicKey($publicKeyHex);
$algorithm = $this->derSequence(
$this->derObjectIdentifier(self::EC_PUBLIC_KEY_OID),
$this->derObjectIdentifier(self::SM2_CURVE_OID)
);
$subjectPublicKeyInfo = $this->derSequence(
$algorithm,
$this->derBitString($publicKeyRaw)
);
return $this->pemEncode('PUBLIC KEY', $subjectPublicKeyInfo);
}
protected function normalizeRawPublicKey(string $publicKeyHex): string
{
$publicKeyHex = strtolower($publicKeyHex);
if (strlen($publicKeyHex) === 128) {
$publicKeyHex = '04' . $publicKeyHex;
}
return $this->decodeHex($publicKeyHex, 'SM2 public key');
}
protected function pemEncode(string $label, string $der): string
{
return "-----BEGIN {$label}-----\n"
. chunk_split(base64_encode($der), 64, "\n")
. "-----END {$label}-----\n";
}
protected function derSequence(string ...$parts): string
{
return $this->derWrap(0x30, implode('', $parts));
}
protected function derInteger(int $value): string
{
$encoded = '';
$current = $value;
do {
$encoded = chr($current & 0xff) . $encoded;
$current >>= 8;
} while ($current > 0);
if ((ord($encoded[0]) & 0x80) !== 0) {
$encoded = "\x00" . $encoded;
}
return $this->derWrap(0x02, $encoded);
}
protected function derOctetString(string $value): string
{
return $this->derWrap(0x04, $value);
}
protected function derBitString(string $value): string
{
return $this->derWrap(0x03, "\x00" . $value);
}
protected function derObjectIdentifier(string $oid): string
{
$parts = array_map('intval', explode('.', $oid));
if (count($parts) < 2) {
throw new BusinessException('监管平台 OID 格式错误');
}
$encoded = chr(($parts[0] * 40) + $parts[1]);
for ($i = 2; $i < count($parts); $i++) {
$encoded .= $this->encodeOidPart($parts[$i]);
}
return $this->derWrap(0x06, $encoded);
}
protected function derContextSpecific(int $index, string $value): string
{
return $this->derWrap(0xa0 + $index, $value);
}
protected function derWrap(int $tag, string $value): string
{
return chr($tag) . $this->derLength(strlen($value)) . $value;
}
protected function derLength(int $length): string
{
if ($length < 0x80) {
return chr($length);
}
$encoded = '';
$current = $length;
while ($current > 0) {
$encoded = chr($current & 0xff) . $encoded;
$current >>= 8;
}
return chr(0x80 | strlen($encoded)) . $encoded;
}
protected function encodeOidPart(int $value): string
{
if ($value === 0) {
return "\x00";
}
$encoded = '';
$current = $value;
while ($current > 0) {
$encoded = chr($current & 0x7f) . $encoded;
$current >>= 7;
}
$length = strlen($encoded);
for ($i = 0; $i < $length - 1; $i++) {
$encoded[$i] = chr(ord($encoded[$i]) | 0x80);
}
return $encoded;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,11 +0,0 @@
ALTER TABLE `order_prescription_file`
ADD COLUMN `doctor_ca_supplier` varchar(16) NOT NULL DEFAULT '' COMMENT '医生CA供应商' AFTER `doctor_ca_file_id`,
ADD COLUMN `doctor_ca_sign_type` varchar(16) NOT NULL DEFAULT '' COMMENT '医生CA签名类型' AFTER `doctor_ca_supplier`,
ADD COLUMN `doctor_ca_sign_originaltext` text COMMENT '医生CA签名原文' AFTER `doctor_ca_sign_type`,
ADD COLUMN `doctor_ca_sign_text` longtext COMMENT '医生CA签名值' AFTER `doctor_ca_sign_originaltext`,
ADD COLUMN `doctor_ca_sign_time` longtext COMMENT '医生CA时间戳签名值' AFTER `doctor_ca_sign_text`,
ADD COLUMN `pharmacist_ca_supplier` varchar(16) NOT NULL DEFAULT '' COMMENT '药师CA供应商' AFTER `doctor_ca_sign_time`,
ADD COLUMN `pharmacist_ca_sign_type` varchar(16) NOT NULL DEFAULT '' COMMENT '药师CA签名类型' AFTER `pharmacist_ca_supplier`,
ADD COLUMN `pharmacist_ca_sign_originaltext` text COMMENT '药师CA签名原文' AFTER `pharmacist_ca_sign_type`,
ADD COLUMN `pharmacist_ca_sign_text` longtext COMMENT '药师CA签名值' AFTER `pharmacist_ca_sign_originaltext`,
ADD COLUMN `pharmacist_ca_sign_time` longtext COMMENT '药师CA时间戳签名值' AFTER `pharmacist_ca_sign_text`;
@@ -1,2 +0,0 @@
ALTER TABLE `order_prescription_product`
ADD COLUMN `product_price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '开方时商品单价' AFTER `product_name`;