commit
ecb35a99f1
@ -0,0 +1,18 @@ |
||||
root = true |
||||
|
||||
[*] |
||||
charset = utf-8 |
||||
end_of_line = lf |
||||
indent_size = 4 |
||||
indent_style = space |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
|
||||
[*.md] |
||||
trim_trailing_whitespace = false |
||||
|
||||
[*.{yml,yaml}] |
||||
indent_size = 2 |
||||
|
||||
[docker-compose.yml] |
||||
indent_size = 4 |
@ -0,0 +1,11 @@ |
||||
* text=auto eol=lf |
||||
|
||||
*.blade.php diff=html |
||||
*.css diff=css |
||||
*.html diff=html |
||||
*.md diff=markdown |
||||
*.php diff=php |
||||
|
||||
/.github export-ignore |
||||
CHANGELOG.md export-ignore |
||||
.styleci.yml export-ignore |
@ -0,0 +1,23 @@ |
||||
/.phpunit.cache |
||||
/node_modules |
||||
/public/build |
||||
/public/hot |
||||
/public/storage |
||||
/storage/*.key |
||||
/storage/pail |
||||
/vendor |
||||
.env |
||||
.env.backup |
||||
.env.production |
||||
.phpactor.json |
||||
.phpunit.result.cache |
||||
Homestead.json |
||||
Homestead.yaml |
||||
auth.json |
||||
npm-debug.log |
||||
yarn-error.log |
||||
/.fleet |
||||
/.idea |
||||
/.nova |
||||
/.vscode |
||||
/.zed |
@ -0,0 +1,66 @@ |
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p> |
||||
|
||||
<p align="center"> |
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a> |
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a> |
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a> |
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a> |
||||
</p> |
||||
|
||||
## About Laravel |
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: |
||||
|
||||
- [Simple, fast routing engine](https://laravel.com/docs/routing). |
||||
- [Powerful dependency injection container](https://laravel.com/docs/container). |
||||
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. |
||||
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). |
||||
- Database agnostic [schema migrations](https://laravel.com/docs/migrations). |
||||
- [Robust background job processing](https://laravel.com/docs/queues). |
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). |
||||
|
||||
Laravel is accessible, powerful, and provides tools required for large, robust applications. |
||||
|
||||
## Learning Laravel |
||||
|
||||
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. |
||||
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch. |
||||
|
||||
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. |
||||
|
||||
## Laravel Sponsors |
||||
|
||||
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). |
||||
|
||||
### Premium Partners |
||||
|
||||
- **[Vehikl](https://vehikl.com/)** |
||||
- **[Tighten Co.](https://tighten.co)** |
||||
- **[WebReinvent](https://webreinvent.com/)** |
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** |
||||
- **[64 Robots](https://64robots.com)** |
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)** |
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)** |
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)** |
||||
- **[Jump24](https://jump24.co.uk)** |
||||
- **[Redberry](https://redberry.international/laravel/)** |
||||
- **[Active Logic](https://activelogic.com)** |
||||
- **[byte5](https://byte5.de)** |
||||
- **[OP.GG](https://op.gg)** |
||||
|
||||
## Contributing |
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). |
||||
|
||||
## Code of Conduct |
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). |
||||
|
||||
## Security Vulnerabilities |
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. |
||||
|
||||
## License |
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). |
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Custom; |
||||
|
||||
enum Code: int |
||||
{ |
||||
case SUCCESS = 0; |
||||
|
||||
case ERROR = 1; |
||||
|
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::SUCCESS => '成功', |
||||
self::ERROR => '失败', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\EHealthCard; |
||||
|
||||
/** |
||||
* 电子健康卡 - 用卡渠道 |
||||
* |
||||
* @see https://open.tengmed.com/openAccess/docs/develop#75 |
||||
*/ |
||||
enum CardChannel: string |
||||
{ |
||||
case WECHAT = '0400'; |
||||
|
||||
case OFFICIAL_ACCOUNT = '0401'; |
||||
|
||||
case MINI_PROGRAM = '0402'; |
||||
|
||||
case OTHER = '0599'; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::WECHAT => '微信', |
||||
self::OFFICIAL_ACCOUNT => '服务号', |
||||
self::MINI_PROGRAM => '小程序', |
||||
self::OTHER => '其他', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\EHealthCard; |
||||
|
||||
/** |
||||
* 电子健康卡 - 用卡费别 |
||||
* |
||||
* @see https://open.tengmed.com/openAccess/docs/develop#76 |
||||
*/ |
||||
enum CardCostTypes: string |
||||
{ |
||||
case SELF_PAYMENT = '0100'; |
||||
|
||||
case MEDICAL_INSURANCE = '0200'; |
||||
|
||||
case PUBLIC_EXPENSE = '0300'; |
||||
|
||||
case OTHER = '0000'; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::SELF_PAYMENT => '自费', |
||||
self::MEDICAL_INSURANCE => '医保', |
||||
self::PUBLIC_EXPENSE => '公费', |
||||
self::OTHER => '其他', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,80 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\EHealthCard; |
||||
|
||||
use App\Dictionary\Patient\IdentityType as PatientCardType; |
||||
|
||||
/** |
||||
* 电子健康卡 - 证件类型 |
||||
* |
||||
* @see https://open.tengmed.com/openAccess/docs/develop#73 |
||||
*/ |
||||
enum CardType: int |
||||
{ |
||||
|
||||
case RESIDENT_ID_CARD = 1; |
||||
|
||||
case RESIDENT_HOUSEHOLD_REGISTER = 2; |
||||
|
||||
case PASSPORT = 3; |
||||
|
||||
case OFFICER_ID_CARD = 4; |
||||
|
||||
case DRIVER_LICENSE = 5; |
||||
|
||||
case HK_MACAO_RESIDENT_PASS = 6; |
||||
|
||||
case TAIWAN_RESIDENT_PASS = 7; |
||||
|
||||
case BIRTH_CERTIFICATE = 8; |
||||
|
||||
case MEDICAL_INSURANCE_CARD = 9; |
||||
|
||||
case MEDICAL_CARD = 10; |
||||
|
||||
case ELECTRON_HEALTH_CARD = 11; |
||||
|
||||
case NEWBORN_CERTIFICATE = 12; |
||||
|
||||
case PERMANENT_RESIDENCE_PERMIT = 15; |
||||
|
||||
case OTHER = 99; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::RESIDENT_ID_CARD => '居民身份证', |
||||
self::RESIDENT_HOUSEHOLD_REGISTER => '居民户口簿', |
||||
self::PASSPORT => '护照', |
||||
self::OFFICER_ID_CARD => '军官证', |
||||
self::DRIVER_LICENSE => '驾驶证', |
||||
self::HK_MACAO_RESIDENT_PASS => '港澳居民来往内地通行证', |
||||
self::TAIWAN_RESIDENT_PASS => '台湾居民来往内地通行证', |
||||
self::BIRTH_CERTIFICATE => '出生医学证明', |
||||
self::MEDICAL_INSURANCE_CARD => '医保卡', |
||||
self::MEDICAL_CARD => '就诊卡', |
||||
self::ELECTRON_HEALTH_CARD => '电子健康卡', |
||||
self::NEWBORN_CERTIFICATE => '新生儿证件', |
||||
self::PERMANENT_RESIDENCE_PERMIT => '外国人永久居住证', |
||||
self::OTHER => '其他法定有效证件', |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Patient Card Type To Electron Hath Card Type |
||||
*/ |
||||
public function patientCardTypeToEHathCardType(PatientCardType $card_type): CardType |
||||
{ |
||||
return match ($card_type) { |
||||
PatientCardType::ID_CARD_NO => self::RESIDENT_ID_CARD, |
||||
PatientCardType::HMT_CARD_NO => self::HK_MACAO_RESIDENT_PASS, |
||||
PatientCardType::PASSPORT => self::PASSPORT, |
||||
PatientCardType::OFFICER_ID_CARD => self::OFFICER_ID_CARD |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\EHealthCard; |
||||
|
||||
/** |
||||
* 电子健康卡 - 二维码类型 |
||||
*/ |
||||
enum CodeType: int |
||||
{ |
||||
case DYNAMIC_CODE = 0; |
||||
|
||||
case STATICS_CODE = 1; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::DYNAMIC_CODE => '动态码', |
||||
self::STATICS_CODE => '静态码', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,85 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\EHealthCard; |
||||
|
||||
/** |
||||
* 电子健康卡 - 用卡环节 |
||||
* |
||||
* @see https://open.tengmed.com/openAccess/docs/develop#74 |
||||
*/ |
||||
enum Scene: string |
||||
{ |
||||
case APPOINTMENT_REGISTRATION = '0101011'; |
||||
|
||||
case TODAY_REGISTRATION = '0101012'; |
||||
|
||||
case REGISTRATION_RECORD = '0101013'; |
||||
|
||||
case SMART_GUIDANCE = '0101014'; |
||||
|
||||
case OUTPATIENT_PAYMENT = '0101051'; |
||||
|
||||
case OUTPATIENT_PAYMENT_RECORD = '0101052'; |
||||
|
||||
case INPATIENT_RECHARGE = '0101056'; |
||||
|
||||
case CHECK_REPORT_QUERY = '0101081'; |
||||
|
||||
case TEST_REPORT_QUERY = '0101082'; |
||||
|
||||
case INPATIENT_RECORD = '0101085'; |
||||
|
||||
case BASIC_INFORMATION = '0101087'; |
||||
|
||||
case ONLINE_CONSULTATION = '0201016'; |
||||
|
||||
case QUEUE_NUMBER = '0201028'; |
||||
|
||||
case APPOINTMENT_REGISTRATION_HEALTH_INSURANCE_PAYMENT = '0201074'; |
||||
|
||||
case TODAY_REGISTRATION_HEALTH_INSURANCE_PAYMENT = '0201075'; |
||||
|
||||
case OUTPATIENT_HEALTH_INSURANCE_PAYMENT = '0201076'; |
||||
|
||||
case ONLINE_TEXT_CONSULTATION = '0301011'; |
||||
|
||||
case ONLINE_VIDEO_CONSULTATION = '0301012'; |
||||
|
||||
case TELEPHONE_CONSULTATION = '0301013'; |
||||
|
||||
case BIND_HEALTH_CARD = '050100'; |
||||
|
||||
case OTHER = '09000'; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::APPOINTMENT_REGISTRATION => '预约挂号', |
||||
self::TODAY_REGISTRATION => '当日挂号', |
||||
self::REGISTRATION_RECORD => '挂号记录', |
||||
self::SMART_GUIDANCE => '智能导诊', |
||||
self::OUTPATIENT_PAYMENT => '门诊缴费', |
||||
self::OUTPATIENT_PAYMENT_RECORD => '门诊缴费记录', |
||||
self::INPATIENT_RECHARGE => '住院充值', |
||||
self::CHECK_REPORT_QUERY => '查(取)检查报告', |
||||
self::TEST_REPORT_QUERY => '查(取)检验报告', |
||||
self::INPATIENT_RECORD => '住院记录', |
||||
self::BASIC_INFORMATION => '基本信息', |
||||
self::ONLINE_CONSULTATION => '在线问诊', |
||||
self::QUEUE_NUMBER => '排队取号', |
||||
self::APPOINTMENT_REGISTRATION_HEALTH_INSURANCE_PAYMENT => '预约挂号医保支付', |
||||
self::TODAY_REGISTRATION_HEALTH_INSURANCE_PAYMENT => '当日挂号医保支付', |
||||
self::OUTPATIENT_HEALTH_INSURANCE_PAYMENT => '门诊费(药费)医保支付', |
||||
self::ONLINE_TEXT_CONSULTATION => '图文咨询', |
||||
self::ONLINE_VIDEO_CONSULTATION => '视频咨询', |
||||
self::TELEPHONE_CONSULTATION => '电话咨询', |
||||
self::BIND_HEALTH_CARD => '绑定健康卡', |
||||
self::OTHER => '其他', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Order; |
||||
|
||||
/** |
||||
* 回调消息状态 |
||||
*/ |
||||
enum NotifyStatus: int |
||||
{ |
||||
case NO_ACCEPTED = 0; |
||||
|
||||
case ACCEPTED = 1; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::NO_ACCEPTED => '未接收', |
||||
self::ACCEPTED => '已接收' |
||||
|
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Order; |
||||
|
||||
/** |
||||
* 支付模式 |
||||
*/ |
||||
enum PayMode: int |
||||
{ |
||||
case PAYMENT = 1; |
||||
|
||||
case REFUND = 2; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::PAYMENT => '支付', |
||||
self::REFUND => '退费', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,50 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Order; |
||||
|
||||
/** |
||||
* 支付类型 |
||||
*/ |
||||
enum PayType: int |
||||
{ |
||||
case AGGREGATION_PAY = 1; |
||||
|
||||
case UNION_PAY = 2; |
||||
|
||||
case WECHAT_PAY = 3; |
||||
|
||||
case ALI_PAY = 4; |
||||
|
||||
case MEDICAL_INSURANCE_PAY = 5; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::AGGREGATION_PAY => '聚合支付', |
||||
self::UNION_PAY => '银联支付', |
||||
self::WECHAT_PAY => '微信支付', |
||||
self::ALI_PAY => '支付宝支付', |
||||
self::MEDICAL_INSURANCE_PAY => '医保支付', |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Order id name |
||||
* @return string |
||||
*/ |
||||
public function order(): string |
||||
{ |
||||
return match ($this) { |
||||
self::AGGREGATION_PAY => 'JH', |
||||
self::UNION_PAY => 'YL', |
||||
self::WECHAT_PAY => 'WX', |
||||
self::ALI_PAY => 'AL', |
||||
self::MEDICAL_INSURANCE_PAY => 'YB', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Order; |
||||
|
||||
/** |
||||
* 订单来源 |
||||
*/ |
||||
enum SourceId: int |
||||
{ |
||||
case OFFICIAL_ACCOUNT = 0; |
||||
|
||||
case MINI_PROGRAM = 1; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::OFFICIAL_ACCOUNT => '微信公众号', |
||||
self::MINI_PROGRAM => '微信小程序', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Order; |
||||
|
||||
/** |
||||
* 订单状态 |
||||
*/ |
||||
enum Status: int |
||||
{ |
||||
case NORMAL = 0; |
||||
|
||||
case ABNORMAL = 1; |
||||
|
||||
case SUCCESS = 2; |
||||
|
||||
case REVERSE = 3; |
||||
|
||||
case FAILURE = 4; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::NORMAL => '初始', |
||||
self::ABNORMAL => '异常', |
||||
self::SUCCESS => '成功', |
||||
self::REVERSE => '冲正', |
||||
self::FAILURE => '失败' |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Order; |
||||
|
||||
/** |
||||
* 订单类型 |
||||
*/ |
||||
enum Type: int |
||||
{ |
||||
case TODAY_REGISTRATION = 1; |
||||
|
||||
case APPOINTMENT_REGISTRATION = 2; |
||||
|
||||
case OUTPATIENT_PAYMENT = 3; |
||||
|
||||
case INPATIENT_RECHARGE = 4; |
||||
|
||||
case OUTPATIENT_PREPAID_CARD_RECHARGE = 5; |
||||
|
||||
case INPATIENT_PREPAID_CARD_RECHARGE = 6; |
||||
|
||||
case OUTPATIENT_PREPAID_CARD_REFUND = 7; |
||||
|
||||
case INPATIENT_PREPAID_CARD_REFUND = 8; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::TODAY_REGISTRATION => '当天挂号', |
||||
self::APPOINTMENT_REGISTRATION => '预约挂号', |
||||
self::OUTPATIENT_PAYMENT => '门诊缴费', |
||||
self::INPATIENT_RECHARGE => '住院按金', |
||||
self::OUTPATIENT_PREPAID_CARD_RECHARGE => '门诊预交金充值', |
||||
self::INPATIENT_PREPAID_CARD_RECHARGE => '住院预交金充值', |
||||
self::OUTPATIENT_PREPAID_CARD_REFUND => '门诊预交金退费', |
||||
self::INPATIENT_PREPAID_CARD_REFUND => '住院预交金退费' |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,35 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Patient; |
||||
|
||||
/** |
||||
* 证件类型 |
||||
*/ |
||||
enum CardType: int |
||||
{ |
||||
case MEDICAL_CARD = 1; |
||||
|
||||
case MEDICAL_INSURANCE_CARD = 2; |
||||
|
||||
case RESIDENT_ID_CARD = 3; |
||||
|
||||
case OUTPATIENT_NO = 4; |
||||
|
||||
case INPATIENT_NO = 5; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::MEDICAL_CARD => '就诊卡', |
||||
self::MEDICAL_INSURANCE_CARD => '医保卡', |
||||
self::RESIDENT_ID_CARD => '居民身份证', |
||||
self::OUTPATIENT_NO => '门诊号码(门诊用)', |
||||
self::INPATIENT_NO => '住院号码(住院用)', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Patient; |
||||
|
||||
/** |
||||
* 健康卡状态 |
||||
*/ |
||||
enum HealthCardStatus: int |
||||
{ |
||||
case UNREGISTERED = 0; |
||||
|
||||
case REGISTERED = 1; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::UNREGISTERED => '已注册', |
||||
self::REGISTERED => '未注册', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,97 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Patient; |
||||
|
||||
/** |
||||
* 证件类型,来自国家医保字典 |
||||
*/ |
||||
enum IdentifyCardType: string |
||||
{ |
||||
case RESIDENT_ID_CARD = '01'; |
||||
case CHINESE_PEOPLES_LIBERATION_ARMY_OFFICER_CARD = '02'; |
||||
case ARMED_POLICE_OFFICER_CARD = '03'; |
||||
case HK_SAR_PASSPORT_OR_MAINLAND_TRAVEL_PERMIT = '04'; |
||||
case MACAU_SAR_PASSPORT_OR_MAINLAND_TRAVEL_PERMIT = '05'; |
||||
case TAIWAN_TRAVEL_PERMIT = '06'; |
||||
case FOREIGNER_PERMANENT_RESIDENCE_PERMIT = '07'; |
||||
case FOREIGNER_PASSPORT = '08'; |
||||
case DISABLED_PERSON_CARD = '09'; |
||||
case MARTYR_OR_FAMILY_MEMBER_PROOF = '10'; |
||||
case FOREIGNER_EMPLOYMENT_PERMIT = '11'; |
||||
case FOREIGN_EXPERT_CERTIFICATE = '12'; |
||||
case FOREIGN_PERMANENT_REPORTER_CERTIFICATE = '13'; |
||||
case EMPLOYMENT_PERMIT_FOR_TAIWAN_HK_MACAU_RESIDENTS = '14'; |
||||
case RETURNED_EXPERT_CERTIFICATE = '15'; |
||||
case SOCIAL_SECURITY_CARD = '90'; |
||||
case OTHER_IDENTITY_DOCUMENT = '99'; |
||||
|
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::RESIDENT_ID_CARD => '居民身份证(户口簿)', |
||||
self::CHINESE_PEOPLES_LIBERATION_ARMY_OFFICER_CARD => '中国人民解放军军官证', |
||||
self::ARMED_POLICE_OFFICER_CARD => '中国人民武装警察警官证', |
||||
self::HK_SAR_PASSPORT_OR_MAINLAND_TRAVEL_PERMIT => '香港特区护照/港澳居民来往内地通行证', |
||||
self::MACAU_SAR_PASSPORT_OR_MAINLAND_TRAVEL_PERMIT => '澳门特区护照/港澳居民来往内地通行证', |
||||
self::TAIWAN_TRAVEL_PERMIT => '台湾居民来往大陆通行证', |
||||
self::FOREIGNER_PERMANENT_RESIDENCE_PERMIT => '外国人永久居留证', |
||||
self::FOREIGNER_PASSPORT => '外国人护照', |
||||
self::DISABLED_PERSON_CARD => '残疾人证', |
||||
self::MARTYR_OR_FAMILY_MEMBER_PROOF => '军烈属证明', |
||||
self::FOREIGNER_EMPLOYMENT_PERMIT => '外国人就业证', |
||||
self::FOREIGN_EXPERT_CERTIFICATE => '外国专家证', |
||||
self::FOREIGN_PERMANENT_REPORTER_CERTIFICATE => '外国人常驻记者证', |
||||
self::EMPLOYMENT_PERMIT_FOR_TAIWAN_HK_MACAU_RESIDENTS => '台港澳人员就业证', |
||||
self::RETURNED_EXPERT_CERTIFICATE => '回国(来华)定居专家证', |
||||
self::SOCIAL_SECURITY_CARD => '社会保障卡', |
||||
self::OTHER_IDENTITY_DOCUMENT => '其他身份证件', |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* 具体的校验规则 |
||||
* @param string $number |
||||
* @return bool |
||||
*/ |
||||
public function validateNumber(string $number): bool |
||||
{ |
||||
return match ($this) { |
||||
self::RESIDENT_ID_CARD => validateIDCard($number), |
||||
// 军官证 |
||||
// 规则: 军/兵/士/文/职/广/(其余中文) + "字第" + 4到8位字母或数字 + "号" |
||||
// 样本: 军字第2001988号, 士字第P011816X号 |
||||
self::CHINESE_PEOPLES_LIBERATION_ARMY_OFFICER_CARD => (bool) preg_match("/^[\x{4E00}-\x{9FA5}](字第)([0-9a-zA-Z]{4,8})(号?)$/u", $number), |
||||
// 港澳居民来往内地通行证 |
||||
// 规则: H/M + 10位数字 |
||||
// 样本: H1234567890 |
||||
self::HK_SAR_PASSPORT_OR_MAINLAND_TRAVEL_PERMIT, |
||||
self::MACAU_SAR_PASSPORT_OR_MAINLAND_TRAVEL_PERMIT => (bool) preg_match("/^([HM]\d{10}(\(\w{1}\))?)$/", $number), |
||||
// 台湾居民来往大陆通行证 |
||||
// 规则: 10位数字 |
||||
// 样本: 1234567890 |
||||
self::TAIWAN_TRAVEL_PERMIT => (bool) preg_match("/^\d{10}$/", $number), |
||||
// 2017 / 2024 外国人永居证 |
||||
self::FOREIGNER_PERMANENT_RESIDENCE_PERMIT => validateIDCard($number) || validate2017ForeignersIDCard($number), |
||||
// 护照 |
||||
// 规则: 14/15开头 + 7位数字, G + 8位数字, P + 7位数字, S/D + 7或8位数字,等 |
||||
// 样本: 12345678 或 1234567890B |
||||
// 样本: 141234567, G12345678, P1234567 |
||||
self::FOREIGNER_PASSPORT => (bool) preg_match("/^([A-z]|[\d]){5,17}$/", $number), |
||||
// 社会保障卡号码 |
||||
// 规则:公民身份证号码 / 香港特别行政区代码(HKG)+预留位(0)+港澳居民来往内地通行证号码第2-9位的终身号;澳门特别行政区代码(MAC)+预留位(0)+港澳居民来往内地通行证号码第2-9位的终身号;台湾地区代码(TWN)+预留位(0)+台湾居民来往大陆通行证号码第1-8位的终身号 |
||||
self::SOCIAL_SECURITY_CARD => validateIDCard($number) || preg_match("/^(HKG|MAC|TWN)0\d{8}$/", $number), |
||||
// 以下类型不处理,默认为false |
||||
self::DISABLED_PERSON_CARD, |
||||
self::ARMED_POLICE_OFFICER_CARD, |
||||
self::EMPLOYMENT_PERMIT_FOR_TAIWAN_HK_MACAU_RESIDENTS, |
||||
self::RETURNED_EXPERT_CERTIFICATE, |
||||
self::FOREIGN_PERMANENT_REPORTER_CERTIFICATE, |
||||
self::FOREIGN_EXPERT_CERTIFICATE, |
||||
self::MARTYR_OR_FAMILY_MEMBER_PROOF, |
||||
self::FOREIGNER_EMPLOYMENT_PERMIT, |
||||
self::OTHER_IDENTITY_DOCUMENT => false, |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,135 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Patient; |
||||
|
||||
/** |
||||
* 民族 |
||||
*/ |
||||
enum Nation: int |
||||
{ |
||||
case HAN = 1; |
||||
case MONGOL = 2; |
||||
case HUI = 3; |
||||
case TIBETAN = 4; |
||||
case UYGHUR = 5; |
||||
case MIAO = 6; |
||||
case YI = 7; |
||||
case ZHUANG = 8; |
||||
case BUYI = 9; |
||||
case KOREAN = 10; |
||||
case MANCHU = 11; |
||||
case DONG = 12; |
||||
case YAO = 13; |
||||
case BAI = 14; |
||||
case TUJIA = 15; |
||||
case HANI = 16; |
||||
case KAZAKH = 17; |
||||
case DAI = 18; |
||||
case LI = 19; |
||||
case LISU = 20; |
||||
case VA = 21; |
||||
case SHE = 22; |
||||
case GAOSHAN = 23; |
||||
case LAKA = 24; |
||||
case SUI = 25; |
||||
case DONGXIANG = 26; |
||||
case NAXI = 27; |
||||
case JINGPO = 28; |
||||
case KIRGIZ = 29; |
||||
case TU = 30; |
||||
case DAUR = 31; |
||||
case Mulao = 32; |
||||
case QIANG = 33; |
||||
case BLANG = 34; |
||||
case SALAR = 35; |
||||
case MAONAN = 36; |
||||
case GELAO = 37; |
||||
case XIBE = 38; |
||||
case Achang = 39; |
||||
case PUMI = 40; |
||||
case TAJIK = 41; |
||||
case NU = 42; |
||||
case UZBEK = 43; |
||||
case RUSSIAN = 44; |
||||
case EWENKI = 45; |
||||
case DEANG = 46; |
||||
case BAOAN = 47; |
||||
case YUGUR = 48; |
||||
case JING = 49; |
||||
case TAT = 50; |
||||
case DUOLUO = 51; |
||||
case OROGEN = 52; |
||||
case HEZHEN = 53; |
||||
case MENBA = 54; |
||||
case LHOBA = 55; |
||||
case JINO = 56; |
||||
case OTHER = 99; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::HAN => '汉族', |
||||
self::MONGOL => '蒙古族', |
||||
self::HUI => '回族', |
||||
self::TIBETAN => '藏族', |
||||
self::UYGHUR => '维吾尔族', |
||||
self::MIAO => '苗族', |
||||
self::YI => '彝族', |
||||
self::ZHUANG => '壮族', |
||||
self::BUYI => '布依族', |
||||
self::KOREAN => '朝鲜族', |
||||
self::MANCHU => '满族', |
||||
self::DONG => '侗族', |
||||
self::YAO => '瑶族', |
||||
self::BAI => '白族', |
||||
self::TUJIA => '土家族', |
||||
self::HANI => '哈尼族', |
||||
self::KAZAKH => '哈萨克族', |
||||
self::DAI => '傣族', |
||||
self::LI => '黎族', |
||||
self::LISU => '傈僳族', |
||||
self::VA => '佤族', |
||||
self::SHE => '畲族', |
||||
self::GAOSHAN => '高山族', |
||||
self::LAKA => '拉祜族', |
||||
self::SUI => '水族', |
||||
self::DONGXIANG => '东乡族', |
||||
self::NAXI => '纳西族', |
||||
self::JINGPO => '景颇族', |
||||
self::KIRGIZ => '柯尔克孜族', |
||||
self::TU => '土族', |
||||
self::DAUR => '达斡尔族', |
||||
self::Mulao => '仫佬族', |
||||
self::QIANG => '羌族', |
||||
self::BLANG => '布朗族', |
||||
self::SALAR => '撒拉族', |
||||
self::MAONAN => '毛南族', |
||||
self::GELAO => '仡佬族', |
||||
self::XIBE => '锡伯族', |
||||
self::Achang => '阿昌族', |
||||
self::PUMI => '普米族', |
||||
self::TAJIK => '塔吉克族', |
||||
self::NU => '怒族', |
||||
self::UZBEK => '乌孜别克族', |
||||
self::RUSSIAN => '俄罗斯族', |
||||
self::EWENKI => '鄂温克族', |
||||
self::DEANG => '德昂族', |
||||
self::BAOAN => '保安族', |
||||
self::YUGUR => '裕固族', |
||||
self::JING => '京族', |
||||
self::TAT => '塔塔尔族', |
||||
self::DUOLUO => '独龙族', |
||||
self::OROGEN => '鄂伦春族', |
||||
self::HEZHEN => '赫哲族', |
||||
self::MENBA => '门巴族', |
||||
self::LHOBA => '珞巴族', |
||||
self::JINO => '基诺族', |
||||
self::OTHER => '其他', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,29 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\Patient; |
||||
|
||||
/** |
||||
* 性别 |
||||
*/ |
||||
enum Sex: int |
||||
{ |
||||
case MALE = 1; |
||||
|
||||
case WOMEN = 2; |
||||
|
||||
case UNKNOWN = 9; |
||||
|
||||
/** |
||||
* Label string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::MALE => '男', |
||||
self::WOMEN => '女', |
||||
self::UNKNOWN => '不详', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\PushMessage; |
||||
|
||||
use App\Dictionary\WeChat\Official\OpenApi; |
||||
|
||||
/** |
||||
* 推送微信消息状态 |
||||
*/ |
||||
enum Status: int |
||||
{ |
||||
case NORMAL = 0; |
||||
|
||||
case SUCCESS = 1; |
||||
|
||||
case FAILURE = 2; |
||||
|
||||
/** |
||||
* Label string. |
||||
* |
||||
* @return string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::NORMAL => '未推送', |
||||
self::SUCCESS => '推送成功', |
||||
self::FAILURE => '推送失败', |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,51 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\PushMessage; |
||||
|
||||
use App\Dictionary\WeChat\Official\OpenApi; |
||||
|
||||
/** |
||||
* 推送微信消息类型 |
||||
*/ |
||||
enum Type: int |
||||
{ |
||||
case OFFICIAL_TEMPLATE = 1; |
||||
|
||||
case OFFICIAL_SINGLE_SUBSCRIBE = 2; |
||||
|
||||
case OFFICIAL_SUBSCRIBE = 3; |
||||
|
||||
case OFFICIAL_CUSTOM = 4; |
||||
|
||||
/** |
||||
* Label string. |
||||
* |
||||
* @return string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::OFFICIAL_TEMPLATE => '公众号模板消息', |
||||
self::OFFICIAL_SINGLE_SUBSCRIBE => '公众号一次性订阅消息', |
||||
self::OFFICIAL_SUBSCRIBE => '公众号订阅消息', |
||||
self::OFFICIAL_CUSTOM => '公众号客服消息', |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Get Open Api. |
||||
* |
||||
* @return OpenApi |
||||
*/ |
||||
public function api(): OpenApi |
||||
{ |
||||
return match ($this) { |
||||
self::OFFICIAL_TEMPLATE => OpenApi::SEND_TEMPLATE_MESSAGE, |
||||
self::OFFICIAL_SINGLE_SUBSCRIBE => OpenApi::SEND_SINGLE_SUBSCRIBE_MESSAGE, |
||||
self::OFFICIAL_SUBSCRIBE => OpenApi::SEND_SUBSCRIBE_MESSAGE, |
||||
self::OFFICIAL_CUSTOM => OpenApi::SEND_CUSTOM_MESSAGE, |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\WeChat\MiniProgram; |
||||
|
||||
/** |
||||
* 微信小程序Api列表 |
||||
* |
||||
* @see https://developers.weixin.qq.com/miniprogram/dev/framework/ |
||||
*/ |
||||
enum OpenApi: string |
||||
{ |
||||
// 开始开发 |
||||
case GET_ACCESS_TOKEN = '/cgi-bin/token'; |
||||
case GET_STABLE_ACCESS_TOKEN = '/cgi-bin/stable_token'; |
||||
|
||||
// 小程序登录 |
||||
case GET_CODE_TO_SESSION = '/sns/jscode2session'; |
||||
|
||||
case CHECK_SESSION_KEY = '/wxa/checksession'; |
||||
|
||||
case RESET_USER_SESSION_KEY = '/wxa/resetusersessionkey'; |
||||
|
||||
// 用户信息 |
||||
case GET_PLUGIN_OPEN_PID = '/wxa/getpluginopenpid'; |
||||
|
||||
case CHECK_ENCRYPTED_DATA = '/wxa/business/checkencryptedmsg'; |
||||
|
||||
case GET_PAID_UNION_ID = '/wxa/getpaidunionid'; |
||||
|
||||
case GET_PHONE_NUMBER = '/wxa/business/getuserphonenumber'; |
||||
} |
@ -0,0 +1,80 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\WeChat\Official; |
||||
|
||||
/** |
||||
* 微信公众号Api列表 |
||||
* |
||||
* @see https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html |
||||
*/ |
||||
enum OpenApi: string |
||||
{ |
||||
// 开始开发 |
||||
case GET_ACCESS_TOKEN = '/cgi-bin/token'; |
||||
case GET_STABLE_ACCESS_TOKEN = '/cgi-bin/stable_token'; |
||||
|
||||
// openApi管理 |
||||
case CLEAR_QUOTA = '/cgi-bin/clear_quota'; |
||||
case QUERY_QUOTA = '/cgi-bin/quota/get'; |
||||
case QUERY_RID = '/cgi-bin/openapi/rid/get'; |
||||
case CLEAR_QUOTA_V2 = '/cgi-bin/clear_quota/v2'; |
||||
|
||||
// 自定义菜单 |
||||
case CREATE_MENU = '/cgi-bin/menu/create'; |
||||
case GET_MENU = '/cgi-bin/menu/get'; |
||||
case DELETE_MENU = '/cgi-bin/menu/delete'; |
||||
case ADD_CONDITIONAL_MENU = '/cgi-bin/menu/addconditional'; |
||||
case DELETE_CONDITIONAL_MENU = '/cgi-bin/menu/delconditional'; |
||||
case TRY_MATCH_MENU = '/cgi-bin/menu/trymatch'; |
||||
case GET_CURRENT_SELF_MENU = '/cgi-bin/get_current_selfmenu_info'; |
||||
|
||||
// 基础消息能力 |
||||
case SET_INDUSTRY = '/cgi-bin/template/api_set_industry'; |
||||
case GET_INDUSTRY = '/cgi-bin/template/get_industry'; |
||||
case ADD_TEMPLATE = '/cgi-bin/template/api_add_template'; |
||||
case GET_ALL_TEMPLATE = '/cgi-bin/template/get_all_private_template'; |
||||
case DELETE_TEMPLATE = '/cgi-bin/template/del_private_template'; |
||||
case SEND_TEMPLATE_MESSAGE = '/cgi-bin/message/template/send'; |
||||
case SEND_SINGLE_SUBSCRIBE_MESSAGE = '/cgi-bin/message/template/subscribe'; |
||||
|
||||
// 订阅通知 |
||||
case ADD_SUBSCRIBE_TEMPLATE = '/wxaapi/newtmpl/addtemplate'; |
||||
case DELETE_SUBSCRIBE_TEMPLATE = '/wxaapi/newtmpl/deltemplate'; |
||||
case GET_SUBSCRIBE_CATEGORY = '/wxaapi/newtmpl/getcategory'; |
||||
case GET_SUBSCRIBE_PUB_TEMPLATE_TITLE_LIST = '/wxaapi/newtmpl/getpubtemplatetitles'; |
||||
case GET_SUBSCRIBE_PUB_TEMPLATE_KEY_WORD = '/wxaapi/newtmpl/getpubtemplatekeywords'; |
||||
case GET_SUBSCRIBE_TEMPLATE_TITLE_LIST = '/wxaapi/newtmpl/gettemplate'; |
||||
case SEND_SUBSCRIBE_MESSAGE = '/cgi-bin/message/subscribe/bizsend'; |
||||
|
||||
// 客服消息 |
||||
case SEND_CUSTOM_MESSAGE = '/cgi-bin/message/custom/send'; |
||||
|
||||
// 用户标签管理 |
||||
case TAG_CREATE = '/cgi-bin/tags/create'; |
||||
case TAG_GET = '/cgi-bin/tags/get'; |
||||
case TAG_UPDATE = '/cgi-bin/tags/update'; |
||||
case TAG_DELETE = '/cgi-bin/tags/delete'; |
||||
case TAG_GET_USER = '/cgi-bin/user/tag/get'; |
||||
case TAG_BATCH_TAGGING = '/cgi-bin/tags/members/batchtagging'; |
||||
case TAG_BATCH_UNTAGGING = '/cgi-bin/tags/members/batchuntagging'; |
||||
case TAG_GET_ID_LIST = '/cgi-bin/tags/getidlist'; |
||||
|
||||
// 用户管理 |
||||
case USER_INFO = '/cgi-bin/user/info'; |
||||
case USER_INFO_BATCH_GET = '/cgi-bin/user/info/batchget'; |
||||
case USER_GET = '/cgi-bin/user/get'; |
||||
case USER_BLACKLIST_GET = '/cgi-bin/tags/members/getblacklist'; |
||||
case USER_BLACKLIST_BATCH_ADD = '/cgi-bin/tags/members/batchblacklist'; |
||||
case USER_BLACKLIST_BATCH_REMOVE = '/cgi-bin/tags/members/batchunblacklist'; |
||||
|
||||
// 发布能力 |
||||
case GET_ARTICLE = '/cgi-bin/freepublish/getarticle'; |
||||
case BATCH_GET_ARTICLE = '/cgi-bin/freepublish/batchget'; |
||||
|
||||
// 账号管理 |
||||
case CREATE_QRCODE_TICKET = '/cgi-bin/qrcode/create'; |
||||
case EXCHANGE_QRCODE_BY_TICKET = 'https://mp.weixin.qq.com/cgi-bin/showqrcode'; |
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\WeChat\Official; |
||||
|
||||
/** |
||||
* 推送模板消息ID |
||||
*/ |
||||
enum SubscribeId: string |
||||
{ |
||||
case REGISTRATION_SUCCESS = 'ASUyXyVFONT6RNwbAs49_rHKQUkc_7iXs31kt1AyACU'; |
||||
|
||||
case REGISTRATION_FAILURE = '36fosQYJU-dN8AsNZERrXY9bfEhP1N9zoqVkORnVr_o'; |
||||
|
||||
case REGISTRATION_CANCEL = '8sWThvcSxg0uS6AFy0LWOeGjbRTUI_n2QHDDMYffjGo'; |
||||
|
||||
case OUTPATIENT_PENDING = 'qieeDt7t2XnT0xB8Fc5ec_peuQDN4TQFPl3ivsILKF0'; |
||||
|
||||
case OUTPATIENT_PAYMENT = 'Aeww94Ahcr0q8bGaAQTSW3s6CB2RXdN9qxZV65bYhhc'; |
||||
|
||||
case INPATIENT_RECHARGE_SUCCESS = 'V30A9ZZ6dqJe_DrYhB5YTUmDbj_F99oJ5k3XP4LK7qk'; |
||||
|
||||
case INPATIENT_RECHARGE_FAILURE = '02HnYY5HFP9LKrWDX_UsQNq2vw3ttfGBvZ4H7SfPZyM'; |
||||
|
||||
case REFUND = '3C9Zw6gBgESwciGF3y2ZeoelYXg1fiZeHAnOUXRf2nM'; |
||||
|
||||
case VISIT = 'IrpIcVU20c5GzBPNUqkp_lvuO-t8gxjiiGx7S88GvIA'; |
||||
|
||||
case SUSPEND_VISIT = 'fTUc-MhhqpBA9WzqQQtfceAmgRr8EFuJNDSdvRDG5K8'; |
||||
|
||||
case TAKE_MEDICINE = '-NX91rCEWPejiKVgbkkGf1QF4zNyH7tadHnkTDqyK_c'; |
||||
|
||||
case TODO_LIST = 'pLdQ5HfXP12C8bHM8EiUP2dqOVFqv-2m0YGCpqC-54Y'; |
||||
|
||||
/** |
||||
* Label string |
||||
* |
||||
* @return string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::REGISTRATION_SUCCESS => '挂号成功通知', |
||||
self::REGISTRATION_FAILURE => '挂号失败通知', |
||||
self::REGISTRATION_CANCEL => '挂号取消通知', |
||||
self::OUTPATIENT_PENDING => '门诊待缴费通知', |
||||
self::OUTPATIENT_PAYMENT => '门诊缴费通知', |
||||
self::INPATIENT_RECHARGE_SUCCESS => '住院预交金支付成功通知', |
||||
self::INPATIENT_RECHARGE_FAILURE => '住院预交失败提醒', |
||||
self::REFUND => '退费通知', |
||||
self::VISIT => '就诊提醒', |
||||
self::SUSPEND_VISIT => '医生停诊通知', |
||||
self::TAKE_MEDICINE => '取药通知', |
||||
self::TODO_LIST => '待办事项通知' |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\WeChat\Official; |
||||
|
||||
/** |
||||
* 推送模板消息ID |
||||
*/ |
||||
enum TemplateId: string |
||||
{ |
||||
case REGISTRATION_SUCCESS = 'ASUyXyVFONT6RNwbAs49_rHKQUkc_7iXs31kt1AyACU'; |
||||
|
||||
case REGISTRATION_FAILURE = '36fosQYJU-dN8AsNZERrXY9bfEhP1N9zoqVkORnVr_o'; |
||||
|
||||
case REGISTRATION_CANCEL = '8sWThvcSxg0uS6AFy0LWOeGjbRTUI_n2QHDDMYffjGo'; |
||||
|
||||
case OUTPATIENT_PENDING = 'qieeDt7t2XnT0xB8Fc5ec_peuQDN4TQFPl3ivsILKF0'; |
||||
|
||||
case OUTPATIENT_PAYMENT = 'Aeww94Ahcr0q8bGaAQTSW3s6CB2RXdN9qxZV65bYhhc'; |
||||
|
||||
case INPATIENT_RECHARGE_SUCCESS = 'V30A9ZZ6dqJe_DrYhB5YTUmDbj_F99oJ5k3XP4LK7qk'; |
||||
|
||||
case INPATIENT_RECHARGE_FAILURE = '02HnYY5HFP9LKrWDX_UsQNq2vw3ttfGBvZ4H7SfPZyM'; |
||||
|
||||
case REFUND = '3C9Zw6gBgESwciGF3y2ZeoelYXg1fiZeHAnOUXRf2nM'; |
||||
|
||||
case VISIT = 'IrpIcVU20c5GzBPNUqkp_lvuO-t8gxjiiGx7S88GvIA'; |
||||
|
||||
case SUSPEND_VISIT = 'fTUc-MhhqpBA9WzqQQtfceAmgRr8EFuJNDSdvRDG5K8'; |
||||
|
||||
case TAKE_MEDICINE = '-NX91rCEWPejiKVgbkkGf1QF4zNyH7tadHnkTDqyK_c'; |
||||
|
||||
case TODO_LIST = 'pLdQ5HfXP12C8bHM8EiUP2dqOVFqv-2m0YGCpqC-54Y'; |
||||
|
||||
/** |
||||
* Label string |
||||
* |
||||
* @return string |
||||
*/ |
||||
public function label(): string |
||||
{ |
||||
return match ($this) { |
||||
self::REGISTRATION_SUCCESS => '挂号成功通知', |
||||
self::REGISTRATION_FAILURE => '挂号失败通知', |
||||
self::REGISTRATION_CANCEL => '挂号取消通知', |
||||
self::OUTPATIENT_PENDING => '门诊待缴费通知', |
||||
self::OUTPATIENT_PAYMENT => '门诊缴费通知', |
||||
self::INPATIENT_RECHARGE_SUCCESS => '住院预交金支付成功通知', |
||||
self::INPATIENT_RECHARGE_FAILURE => '住院预交失败提醒', |
||||
self::REFUND => '退费通知', |
||||
self::VISIT => '就诊提醒', |
||||
self::SUSPEND_VISIT => '医生停诊通知', |
||||
self::TAKE_MEDICINE => '取药通知', |
||||
self::TODO_LIST => '待办事项通知' |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Dictionary\WeChat\Payment; |
||||
|
||||
/** |
||||
* JSAPI支付 V2 API列表 |
||||
* |
||||
* @see https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1 |
||||
*/ |
||||
enum V2Api: string |
||||
{ |
||||
// 查询订单 |
||||
case QUERY_ORDER = '/pay/orderquery'; |
||||
|
||||
// 查询退款单 |
||||
case QUERY_REFUND_ORDER = '/pay/refundquery'; |
||||
|
||||
// 统一下单 |
||||
case PAYMENT = '/pay/unifiedorder'; |
||||
|
||||
// 退款 |
||||
case REFUND = '/secapi/pay/refund'; |
||||
} |
@ -0,0 +1,23 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Exceptions; |
||||
|
||||
use Exception; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class GeneralException extends Exception |
||||
{ |
||||
protected int $status_code; |
||||
|
||||
public function __construct(string $message = 'An error occurred.', int $status_code = Response::HTTP_BAD_REQUEST) |
||||
{ |
||||
parent::__construct($message); |
||||
$this->status_code = $status_code; |
||||
} |
||||
|
||||
public function getStatusCode(): int |
||||
{ |
||||
return $this->status_code; |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Controllers\Auth; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Http\Controllers\Controller; |
||||
use App\Http\Logics\Auth\AuthLogic; |
||||
use App\Http\Requests\Auth\LoginRequest; |
||||
use Illuminate\Auth\AuthenticationException; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; |
||||
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; |
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; |
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; |
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; |
||||
|
||||
class AuthController extends Controller |
||||
{ |
||||
protected AuthLogic $auth_logic; |
||||
|
||||
/** |
||||
* AuthController constructor. |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->auth_logic = new AuthLogic(); |
||||
} |
||||
|
||||
/** |
||||
* 登录接口 |
||||
* @param LoginRequest $request |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function login(LoginRequest $request): JsonResponse |
||||
{ |
||||
$response = $this->auth_logic->login($request->code); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success.', $response); |
||||
} |
||||
|
||||
/** |
||||
* 未登录跳转 |
||||
* @throws AuthenticationException |
||||
*/ |
||||
public function unauthorized() |
||||
{ |
||||
throw new AuthenticationException('Unauthorized.'); |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Controllers; |
||||
|
||||
abstract class Controller |
||||
{ |
||||
// |
||||
} |
@ -0,0 +1,51 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Controllers\Dictionary; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Http\Logics\Dictionary\ItemLogic; |
||||
use App\Http\Resources\Dictionary\ItemDetailsResource; |
||||
use App\Http\Resources\Dictionary\ItemListsResource; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Http\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class ItemController |
||||
{ |
||||
protected ItemLogic $item_logic; |
||||
|
||||
/** |
||||
* Patient Construct. |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->item_logic = new ItemLogic(); |
||||
} |
||||
|
||||
/** |
||||
* 获取列表 |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function lists(): JsonResponse |
||||
{ |
||||
$response = $this->item_logic->getLists(); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', ItemListsResource::make($response)->toArray()); |
||||
} |
||||
|
||||
/** |
||||
* 获取详情 |
||||
* @param Request $request |
||||
* @param int $type_id |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function details(Request $request, int $type_id): JsonResponse |
||||
{ |
||||
$response = $this->item_logic->getDetails($type_id); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', ItemDetailsResource::make($response)->toArray()); |
||||
} |
||||
} |
@ -0,0 +1,106 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Controllers\Patient; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Http\Logics\Patient\PatientLogic; |
||||
use App\Http\Requests\Patient\BindPatientRequest; |
||||
use App\Http\Requests\Patient\CreatePatientRequest; |
||||
use App\Http\Resources\Patient\PatientDetailsResource; |
||||
use App\Http\Resources\Patient\PatientListsResource; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Http\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class PatientController |
||||
{ |
||||
protected PatientLogic $patient_logic; |
||||
|
||||
/** |
||||
* Patient Construct. |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->patient_logic = new PatientLogic(); |
||||
} |
||||
|
||||
/** |
||||
* 获取列表 |
||||
* @return JsonResponse |
||||
*/ |
||||
public function lists(): JsonResponse |
||||
{ |
||||
$response = $this->patient_logic->getAllPatientLists(); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', PatientListsResource::make($response)->toArray()); |
||||
} |
||||
|
||||
/** |
||||
* 获取详情 |
||||
* @param Request $request |
||||
* @param string $patient_id |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function details(Request $request, string $patient_id): JsonResponse |
||||
{ |
||||
$response = $this->patient_logic->getPatientDetails($patient_id); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', PatientDetailsResource::make($response)->toArray()); |
||||
} |
||||
|
||||
/** |
||||
* 创建档案 |
||||
* @param CreatePatientRequest $request |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function create(CreatePatientRequest $request): JsonResponse |
||||
{ |
||||
$patient_id = $this->patient_logic->createPatient($request->safe()->all()); |
||||
|
||||
return jsonResponse(Response::HTTP_CREATED, 'success', ['patient_id' => $patient_id]); |
||||
} |
||||
|
||||
/** |
||||
* 绑定档案 |
||||
* @param BindPatientRequest $request |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function bind(BindPatientRequest $request): JsonResponse |
||||
{ |
||||
$patient_id = $this->patient_logic->bindPatient($request->safe()->all()); |
||||
|
||||
return jsonResponse(Response::HTTP_CREATED, 'success', ['patient_id' => $patient_id]); |
||||
} |
||||
|
||||
/** |
||||
* 设置默认状态 |
||||
* @param Request $request |
||||
* @param string $patient_id |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function setDefault(Request $request, string $patient_id): JsonResponse |
||||
{ |
||||
$this->patient_logic->setDefaultPatient($patient_id); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'update success.'); |
||||
} |
||||
|
||||
/** |
||||
* 删除 |
||||
* @param Request $request |
||||
* @param string $patient_id |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function delete(Request $request, string $patient_id): JsonResponse |
||||
{ |
||||
$this->patient_logic->cancelBindPatient($patient_id); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'delete success.'); |
||||
} |
||||
} |
@ -0,0 +1,65 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Controllers\Registration; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Http\Logics\Registration\RecordLogic; |
||||
use App\Http\Logics\Registration\ScheduleLogic; |
||||
use App\Http\Resources\Registration\Record\RecordListsResource; |
||||
use App\Http\Resources\Registration\Schedule\DeptListsResource; |
||||
use App\Http\Resources\Registration\Schedule\DoctorListsResource; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Http\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class RecordController |
||||
{ |
||||
protected RecordLogic $record_logic; |
||||
|
||||
/** |
||||
* Patient Construct. |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->record_logic = new RecordLogic(); |
||||
} |
||||
|
||||
/** |
||||
* 获取挂号记录列表 |
||||
* @param Request $request |
||||
* @param string $patient_id |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function lists(Request $request, string $patient_id): JsonResponse |
||||
{ |
||||
$validated = $request->validate([ |
||||
'start_date' => 'date_format:Y-m-d', |
||||
'end_date' => 'date_format:Y-m-d|after:start_date', |
||||
],['messages' => [ |
||||
'start_date.date_format' => '日期格式错误', |
||||
'end_date.date_format' => '日期格式错误', |
||||
'end_date.after' => '查询日期错误', |
||||
]]); |
||||
|
||||
$response = $this->record_logic->getRecordLists($patient_id, $validated['start_date'], $validated['end_date']); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', RecordListsResource::make($response)->toArray()); |
||||
} |
||||
|
||||
/** |
||||
* 退号 |
||||
* @param Request $request |
||||
* @param string $patient_id |
||||
* @param string $serial_no |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function refund(Request $request, string $patient_id, string $serial_no): JsonResponse |
||||
{ |
||||
$this->record_logic->refundRegisterRecord($patient_id, $serial_no); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'refund success.'); |
||||
} |
||||
} |
@ -0,0 +1,68 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Controllers\Registration; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Http\Logics\Registration\ScheduleLogic; |
||||
use App\Http\Resources\Registration\Schedule\DeptListsResource; |
||||
use App\Http\Resources\Registration\Schedule\DoctorListsResource; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Http\Request; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class ScheduleController |
||||
{ |
||||
protected ScheduleLogic $schedule_logic; |
||||
|
||||
/** |
||||
* Patient Construct. |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->schedule_logic = new ScheduleLogic(); |
||||
} |
||||
|
||||
/** |
||||
* 获取科室列表 |
||||
* @param Request $request |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function dept(Request $request): JsonResponse |
||||
{ |
||||
$validated = $request->validate([ |
||||
'date' => 'required|date_format:Y-m-d', |
||||
],['messages' => [ |
||||
'date.required' => '请传入日期', |
||||
'date.date_format' => '日期格式错误', |
||||
]]); |
||||
|
||||
$response = $this->schedule_logic->getDeptLists($validated['date']); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', DeptListsResource::make($response)->toArray()); |
||||
} |
||||
|
||||
/** |
||||
* 获取医生排班列表 |
||||
* @param Request $request |
||||
* @return JsonResponse |
||||
* @throws GeneralException |
||||
*/ |
||||
public function doctor(Request $request): JsonResponse |
||||
{ |
||||
$validated = $request->validate([ |
||||
'date' => 'required|date_format:Y-m-d', |
||||
'dept_id' => 'required|numeric' |
||||
], ['messages' => [ |
||||
'date.required' => '请传入日期', |
||||
'date.date_format' => '日期格式错误', |
||||
'dept_id.required' => '请传入科室ID', |
||||
'dept_id.numeric' => '科室ID格式错误', |
||||
]]); |
||||
|
||||
$response = $this->schedule_logic->getDoctorLists($validated['date'], $validated['dept_id']); |
||||
|
||||
return jsonResponse(Response::HTTP_OK, 'success', DoctorListsResource::make($response)->toArray()); |
||||
} |
||||
} |
@ -0,0 +1,98 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Http\Logics\Auth; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Models\User; |
||||
use App\Utils\Traits\Logger; |
||||
use Carbon\Carbon; |
||||
use Exception; |
||||
use Illuminate\Support\Facades\Hash; |
||||
use Illuminate\Support\Facades\Redis; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; |
||||
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface; |
||||
|
||||
class AuthLogic |
||||
{ |
||||
use Logger; |
||||
|
||||
/** |
||||
* AuthLogic Construct |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->setChannel('genera'); |
||||
} |
||||
|
||||
/** |
||||
* 小程序登录 |
||||
* @throws GeneralException |
||||
*/ |
||||
public function login(string $code): array |
||||
{ |
||||
$session_info = $this->miniProgramLogin($code); |
||||
$token_info = $this->userLogin($session_info['open_id'], $session_info['session_key']); |
||||
|
||||
Redis::setex($token_info['access_token'], 86400 * 7, json_encode($session_info, JSON_UNESCAPED_UNICODE)); |
||||
|
||||
return $token_info; |
||||
} |
||||
|
||||
/** |
||||
* 用户登录 |
||||
* @param string $open_id |
||||
* @param string $session_key |
||||
* @return array |
||||
*/ |
||||
protected function userLogin(string $open_id, string $session_key): array |
||||
{ |
||||
$user = User::firstOrCreate([ |
||||
'email' => $open_id |
||||
], [ |
||||
'name' => $open_id, |
||||
'password' => bcrypt($open_id) |
||||
]); |
||||
|
||||
// 撤销之前正在使用的所有token |
||||
$user->tokens()->delete(); |
||||
|
||||
// 获取新token |
||||
$expire_time = Carbon::now()->addDays(7); |
||||
$token_str = $user->createToken(bcrypt($session_key), ['*'], $expire_time)->plainTextToken; |
||||
[$id, $token] = explode('|', $token_str, 2); |
||||
|
||||
return [ |
||||
'access_token' => $token ?: '', |
||||
'token_type' => 'Bearer', |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 小程序登录 |
||||
* @param string $code |
||||
* @return array |
||||
* @throws GeneralException |
||||
*/ |
||||
protected function miniProgramLogin(string $code): array |
||||
{ |
||||
try { |
||||
$mini = getWeChatMiniProgramApp(); |
||||
$response = $mini->getUtils()->codeToSession($code); |
||||
|
||||
return [ |
||||
'open_id' => $response['openid'], |
||||
'session_key' => $response['session_key'], |
||||
'union_id' => $response['unionid'] ?? '' |
||||
]; |
||||
|
||||
} catch (HttpExceptionInterface|ExceptionInterface|Exception $e) { |
||||
//service error |
||||
$message = $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine(); |
||||
$this->error('授权登录接口报错', [$message]); |
||||
throw new GeneralException('授权登录失败,请稍后再试!', Response::HTTP_BAD_REQUEST); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,61 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Logics\Dictionary; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Services\HisSoap\Client; |
||||
use App\Utils\Traits\Logger; |
||||
use App\Utils\Traits\MiniProgramAuth; |
||||
use App\Utils\Traits\UniversalEncryption; |
||||
use Illuminate\Auth\AuthenticationException; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class ItemLogic |
||||
{ |
||||
use Logger; |
||||
use MiniProgramAuth; |
||||
use UniversalEncryption; |
||||
|
||||
private Client $his_soap; |
||||
|
||||
/** |
||||
* ItemLogic Construct |
||||
* @throws AuthenticationException |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->authInitialize(); |
||||
$this->his_soap = app('HisSoapService'); |
||||
} |
||||
|
||||
/** |
||||
* 列表 |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getLists() |
||||
{ |
||||
$response = $this->his_soap->getDictionaryLists(); |
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '找不到缴费项目分类列表!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* 详情 |
||||
* @param int $type_id |
||||
* @return array |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDetails(int $type_id): array |
||||
{ |
||||
$response = $this->his_soap->getDictionaryDetails($type_id); |
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '找不到缴费项目分类详情!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
return $response; |
||||
} |
||||
} |
@ -0,0 +1,264 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Logics\Patient; |
||||
|
||||
use App\Dictionary\Patient\CardType; |
||||
use App\Dictionary\Patient\Sex; |
||||
use App\Exceptions\GeneralException; |
||||
use App\Models\Patient; |
||||
use App\Services\HisSoap\Client; |
||||
use App\Utils\Traits\Logger; |
||||
use App\Utils\Traits\MiniProgramAuth; |
||||
use App\Utils\Traits\UniversalEncryption; |
||||
use Exception; |
||||
use Illuminate\Auth\AuthenticationException; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class PatientLogic |
||||
{ |
||||
use Logger; |
||||
use MiniProgramAuth; |
||||
use UniversalEncryption; |
||||
|
||||
private Client $his_soap; |
||||
|
||||
private Patient $patient_model; |
||||
|
||||
/** |
||||
* PatientLogic Construct |
||||
* @throws AuthenticationException |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->authInitialize(); |
||||
$this->patient_model = new Patient(); |
||||
$this->his_soap = app('HisSoapService'); |
||||
} |
||||
|
||||
/** |
||||
* 获取绑定患者列表 |
||||
*/ |
||||
public function getAllPatientLists() |
||||
{ |
||||
return $this->patient_model->getBindPatientLists($this->open_id); |
||||
} |
||||
|
||||
/** |
||||
* 卡详情 |
||||
* @param string $patient_id |
||||
* @return Patient |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getPatientDetails(string $patient_id): Patient |
||||
{ |
||||
$info = $this->patient_model->getBindPatientInfoByPatientId($this->open_id, $patient_id); |
||||
if(empty($info)) { |
||||
throw new GeneralException('找不到该就诊卡!'); |
||||
} |
||||
|
||||
// 获取患者信息 |
||||
$response = $this->his_soap->getPatientInfo('01', $info['patient_id'], CardType::MEDICAL_CARD, $info['name']); |
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '找不到该就诊卡!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
$info->patient_card_id = $response['MZHM'] ?? ''; |
||||
$info->card_no = substr($response['CARDNO'], 0, 3). '**********'. substr($response['CARDNO'], -3); |
||||
|
||||
return $info; |
||||
} |
||||
|
||||
/** |
||||
* 建档 |
||||
* @param array $data |
||||
* @return string |
||||
* @throws GeneralException |
||||
*/ |
||||
public function createPatient(array $data): string |
||||
{ |
||||
// 简单判断一下证件类型 |
||||
$card_type = getIDCardType($data['card_no']); |
||||
switch ($card_type) { |
||||
// 身份证 |
||||
case 1: |
||||
$sex = getGenderByIdCard($data['card_no']) === 1 ? Sex::MALE : Sex::WOMEN; |
||||
$birthday = getBirthdayByIdCard($data['card_no']); |
||||
break; |
||||
// 2017 / 2023 外国人永居证 |
||||
case 3: |
||||
case 4: |
||||
if ($card_type == 3) { |
||||
$sex = Sex::from((int)$data['sex']); |
||||
$birthday = getBirthdayBy2017ForeignersIDCard($data['card_no']); |
||||
} else { |
||||
$sex = getGenderByIdCard($data['card_no']) === 1 ? Sex::MALE : Sex::WOMEN; |
||||
$birthday = getBirthdayByIdCard($data['card_no']); |
||||
} |
||||
break; |
||||
default: |
||||
$sex = Sex::from((int)$data['sex']); |
||||
$birthday = &$data['birthday']; |
||||
break; |
||||
} |
||||
|
||||
//过滤名字特殊字符 |
||||
$data['name'] = replaceSpecialChar($data['name']); |
||||
$card_type = CardType::from((int)$data['card_type']); |
||||
|
||||
// 查询绑定超过X个 |
||||
$bind_count = $this->patient_model->getBindPatientCount($this->open_id); |
||||
if ($bind_count >= config('custom.max_bind_patient_count')) { |
||||
throw new GeneralException('该微信达到绑定卡上限!'); |
||||
} |
||||
|
||||
// 查询患者信息 |
||||
$response = $this->his_soap->getPatientInfo('01', $data['card_no'], $card_type, $data['name']); |
||||
$this->info('查询患者信息:', $response); |
||||
|
||||
if (isset($response['RESULTCODE']) && $response['RESULTCODE'] === '0') { |
||||
$patient_id = &$response['PATIENTID']; |
||||
|
||||
// 查询是否已绑定 |
||||
$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_soap->registerCard( |
||||
$data['card_no'], |
||||
$card_type, |
||||
$data['name'], |
||||
$sex, |
||||
$birthday, |
||||
$data['card_no'], |
||||
$data['mobile_phone'], |
||||
$data['address'] |
||||
); |
||||
$this->info('建档患者:'. $data['name']. '建档结果', $response); |
||||
|
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException('建档失败,失败原因:'. $response['ERRORMSG'] ?? '未知错误', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
$patient_id = &$response['PATIENTID']; |
||||
} |
||||
|
||||
// 写入数据库 |
||||
$result = $this->patient_model->createPatient($this->union_id, $this->open_id, $patient_id, $data['name'], $sex); |
||||
|
||||
if (!$result) { |
||||
throw new GeneralException('数据保存失败,请重试!', Response::HTTP_INTERNAL_SERVER_ERROR); |
||||
} |
||||
|
||||
return $patient_id; |
||||
} |
||||
|
||||
/** |
||||
* 绑定患者 |
||||
* @param array $data |
||||
* @return string |
||||
* @throws GeneralException |
||||
*/ |
||||
public function bindPatient(array $data): string |
||||
{ |
||||
//过滤名字特殊字符 |
||||
$data['name'] = replaceSpecialChar($data['name']); |
||||
$card_type = CardType::from((int)$data['card_type']); |
||||
|
||||
// 查询超过X个 |
||||
$bind_count = $this->patient_model->getBindPatientCount($this->open_id); |
||||
if ($bind_count >= config('custom.max_bind_patient_count')) { |
||||
throw new GeneralException('该微信达到绑定卡上限!'); |
||||
} |
||||
|
||||
// 查询患者信息 |
||||
$response = $this->his_soap->getPatientInfo('01', $data['card_no'], $card_type, $data['name']); |
||||
$this->info('查询患者信息:', $response); |
||||
|
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] != '0') { |
||||
throw new GeneralException($response['ResultContent'] ?? '未知错误'); |
||||
} |
||||
|
||||
$patient_info = &$response; |
||||
$sex = Sex::from((int) $patient_info['SEX']); |
||||
|
||||
if ($patient_info['PATIENTID'] != $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_info['PATIENTID'], $data['name'], $sex); |
||||
|
||||
if (!$result) { |
||||
throw new GeneralException('数据保存失败,请重试!', Response::HTTP_INTERNAL_SERVER_ERROR); |
||||
} |
||||
|
||||
return $patient_info['PATIENTID']; |
||||
} |
||||
|
||||
/** |
||||
* 设置默认就诊卡 |
||||
* @param string $patient_id |
||||
* @return bool |
||||
* @throws GeneralException |
||||
*/ |
||||
public function setDefaultPatient(string $patient_id): bool |
||||
{ |
||||
$info = $this->patient_model->getBindPatientInfoByPatientId($this->open_id, $patient_id); |
||||
if (empty($info)) { |
||||
throw new GeneralException('该就诊卡不存在!'); |
||||
} |
||||
|
||||
$result = $this->patient_model->setDefaultPatient($this->open_id, $patient_id); |
||||
if (!$result) { |
||||
throw new GeneralException('设置失败,请稍后再试!', Response::HTTP_INTERNAL_SERVER_ERROR); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 解绑 |
||||
* @param string $patient_id |
||||
* @return bool |
||||
* @throws GeneralException |
||||
*/ |
||||
public function cancelBindPatient(string $patient_id): bool |
||||
{ |
||||
$info = $this->patient_model->getBindPatientInfoByPatientId($this->open_id, $patient_id); |
||||
if (empty($info)) { |
||||
throw new GeneralException('该就诊卡不存在!'); |
||||
} |
||||
|
||||
$result = $this->patient_model->deletePatient($this->open_id, $patient_id); |
||||
if (!$result) { |
||||
throw new GeneralException('解绑失败,请稍后再试!', Response::HTTP_INTERNAL_SERVER_ERROR); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,167 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Logics\Registration; |
||||
|
||||
use App\Dictionary\Order\PayType; |
||||
use App\Dictionary\Order\SourceId; |
||||
use App\Dictionary\Order\Type; |
||||
use App\Exceptions\GeneralException; |
||||
use App\Models\Order; |
||||
use App\Models\RegistrationRecord; |
||||
use App\Services\HisSoap\Client; |
||||
use App\Utils\Traits\Logger; |
||||
use App\Utils\Traits\MiniProgramAuth; |
||||
use Illuminate\Auth\AuthenticationException; |
||||
use Illuminate\Support\Facades\Cache; |
||||
use ReflectionException; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use UnifyPayment\Cores\Struct\RefundOrder; |
||||
use UnifyPayment\Unify; |
||||
|
||||
class RecordLogic |
||||
{ |
||||
use Logger; |
||||
use MiniProgramAuth; |
||||
|
||||
private Client $his_soap; |
||||
|
||||
private RegistrationRecord $reg_record_model; |
||||
|
||||
private Order $order_model; |
||||
|
||||
/** |
||||
* RecordLogic Construct |
||||
* @throws AuthenticationException |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->authInitialize(); |
||||
$this->setChannel('refund'); |
||||
$this->his_soap = app('HisSoapService'); |
||||
$this->reg_record_model = new RegistrationRecord(); |
||||
$this->order_model = new Order(); |
||||
} |
||||
|
||||
/** |
||||
* 获取挂号记录列表 |
||||
* @param string $patient_id |
||||
* @param string $start_date |
||||
* @param string $end_time |
||||
* @return array |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getRecordLists(string $patient_id, string $start_date, string $end_time): array |
||||
{ |
||||
$response = $this->his_soap->getRegisterRecordLists($patient_id, $start_date,$end_time); |
||||
|
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '暂无相关挂号记录!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
// 缓存2小时 |
||||
Cache::set('Registration.Record.'. $this->open_id.'.'. $patient_id, json_encode($response, JSON_UNESCAPED_UNICODE), 2 * 60 *60); |
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* 退号 |
||||
* @param string $patient_id |
||||
* @param string $reg_serial_no |
||||
* @return true |
||||
* @throws GeneralException |
||||
*/ |
||||
public function refundRegisterRecord(string $patient_id, string $reg_serial_no): true |
||||
{ |
||||
$cache_key = 'Registration.Record.'. $this->open_id.'.'. $patient_id; |
||||
|
||||
$record_info = Cache::get($cache_key); |
||||
if (empty($record_info)) { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '查询不到需要退号的挂号记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
$record_info = json_decode($record_info, true); |
||||
|
||||
// 获取具体的预约详情 |
||||
$record_info = xmlArrayToListByKey($record_info, 'ITEM'); |
||||
foreach ($record_info['ITEM'] as $v) { |
||||
if ($v['VISITNO'] === $reg_serial_no) { |
||||
$info = $v; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (empty($info)) { |
||||
throw new GeneralException('查询不到需要退号的挂号记录,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
$this->info('患者需退号的挂号记录', $info); |
||||
|
||||
// 查询小程序上的挂号记录 |
||||
$reg_record = $this->reg_record_model->getRecordByRegID($reg_serial_no); |
||||
if (empty($reg_record) || empty($reg_record->order()->order_id)) { |
||||
throw new GeneralException('非小程序渠道挂号,请在人工窗口退号退费处理', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
$order_info = &$reg_record->order(); |
||||
$order_id = &$order_info->order_id; |
||||
$fee = &$order_info->self_fee; |
||||
|
||||
$this->info('患者需退号的数据库挂号记录', $reg_record->toArray()); |
||||
|
||||
// 检查是否可以退号 |
||||
$response = $this->his_soap->checkRefundRegisterStatus($reg_serial_no); |
||||
$this->info('检查是否可进行退号', $response); |
||||
|
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '当前挂号记录不可退号!', Response::HTTP_BAD_REQUEST); |
||||
} |
||||
|
||||
// 开始退号 |
||||
$response = $this->his_soap->refundRegister($reg_serial_no, $order_id, date('Y-m-d'), date('H:i:s'), (string) ($fee / 100)); |
||||
$this->info('退号结果', $response); |
||||
|
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '退号失败,请重新再试!', Response::HTTP_BAD_REQUEST); |
||||
} |
||||
|
||||
// 创建退款单 |
||||
$refund_order_id = $this->order_model->getRefundOrderId($order_id); |
||||
$refund_order_info = $this->order_model->createRefundOReverseOrder( |
||||
$order_info->id, |
||||
$refund_order_id, |
||||
PayType::from($order_info->pay_type), |
||||
$fee, |
||||
$this->open_id, |
||||
$patient_id, |
||||
$order_info->patient_name, |
||||
Type::from($order_info->order_type), |
||||
SourceId::from($order_info->source_id) |
||||
); |
||||
$this->info('创建退款订单', ['id' => $refund_order_info->id]); |
||||
|
||||
if (empty($refund_order_info)) { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '退号成功,退费失败,请重新再试!', Response::HTTP_BAD_REQUEST); |
||||
} |
||||
|
||||
// 退款 |
||||
try { |
||||
$refund_order_obj = new RefundOrder($order_id, $refund_order_id, $fee, '患者自行退号退费'); |
||||
$response = Unify::common(env('unify'))->order->refund($refund_order_obj); |
||||
$this->info('退号退费结果', $response); |
||||
|
||||
} catch (ReflectionException $e) { |
||||
$this->order_model->reverseOrderOpera($refund_order_id, $fee, false); |
||||
|
||||
throw new GeneralException($e->getMessage() ?? '退号成功,退费失败,请重新再试!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
if (empty($response) || $response['status'] !== 200 || $response['success'] !== true) { |
||||
$this->order_model->reverseOrderOpera($refund_order_id, $fee, false); |
||||
|
||||
throw new GeneralException($response['msg'] ?? '退号成功,退费失败,请重新再试!', Response::HTTP_BAD_REQUEST); |
||||
} |
||||
|
||||
$this->order_model->reverseOrderOpera($refund_order_id, $fee, true); |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,60 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Http\Logics\Registration; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Services\HisSoap\Client; |
||||
use App\Utils\Traits\Logger; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class ScheduleLogic |
||||
{ |
||||
use Logger; |
||||
|
||||
private Client $his_soap; |
||||
|
||||
/** |
||||
* PatientLogic Construct |
||||
*/ |
||||
public function __construct() |
||||
{ |
||||
$this->his_soap = app('HisSoapService'); |
||||
} |
||||
|
||||
/** |
||||
* 获取科室列表 |
||||
* @param string $date |
||||
* @return array |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDeptLists(string $date): array |
||||
{ |
||||
$response = $this->his_soap->getDepLists('', '','01', $date); |
||||
|
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '暂无科室排班!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
return $response; |
||||
} |
||||
|
||||
/** |
||||
* 获取医生列表 |
||||
* @param string $date 日期 |
||||
* @param string $dept_id 科室ID |
||||
* @return array |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDoctorLists(string $date, string $dept_id): array |
||||
{ |
||||
$type = $date === date('Y-m-d') ? '3' : '1'; |
||||
|
||||
$response = $this->his_soap->getDoctorLists($dept_id, $type, '', $date); |
||||
if (!isset($response['RESULTCODE']) || $response['RESULTCODE'] !== '0') { |
||||
throw new GeneralException($response['ERRORMSG'] ?? '该科室暂无医生排班!', Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
|
||||
return $response; |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Middleware; |
||||
|
||||
use Closure; |
||||
|
||||
class PerformanceDebug |
||||
{ |
||||
public function handle($request, Closure $next) |
||||
{ |
||||
$response = $next($request); |
||||
|
||||
// 确保在开发环境下 |
||||
if (app()->isLocal()) { |
||||
|
||||
// 计算包含了多少文件 |
||||
$included_files_count = count(get_included_files()); |
||||
|
||||
dd($included_files_count); |
||||
} |
||||
|
||||
return $response; |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Middleware; |
||||
|
||||
use Closure; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Response; |
||||
|
||||
class RecordApiLog |
||||
{ |
||||
/** |
||||
* @param Request $request |
||||
* @param Closure $next |
||||
* @return mixed |
||||
*/ |
||||
public function handle(Request $request, Closure $next): mixed |
||||
{ |
||||
$request->attributes->set('start_time', microtime(true)); |
||||
|
||||
return $next($request); |
||||
} |
||||
|
||||
/** |
||||
* @param Request $request |
||||
* @param Response|JsonResponse $response |
||||
*/ |
||||
public function terminate(Request $request, Response|JsonResponse $response): void |
||||
{ |
||||
//结束时间 |
||||
$end = microtime(true); |
||||
$diff = $end - $request->attributes->get('start_time'); |
||||
|
||||
$ip = json_encode($request->ips(),256); |
||||
|
||||
if ($response instanceof JsonResponse) { |
||||
$responseStr = $this->getJsonResponseStr($response); |
||||
} else { |
||||
$responseStr = $this->getResponseStr($response); |
||||
} |
||||
|
||||
recordLog('RecordApiUse', implode("\n", [ |
||||
'请求地址: '. $ip. '|'. $request->method(). '|'. $request->url(), |
||||
'请求入参: '. json_encode(request()->all(), JSON_UNESCAPED_UNICODE), |
||||
'请求出参: '. $responseStr, |
||||
'耗时: '. sprintf("%.6f", $diff). 's' |
||||
])); |
||||
} |
||||
|
||||
/** |
||||
* 获取响应字符串 |
||||
* @param Response $response |
||||
* @return string |
||||
*/ |
||||
protected function getResponseStr(Response $response): string |
||||
{ |
||||
return PHP_EOL. sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatusCode(), Response::$statusTexts[$response->getStatusCode()]). PHP_EOL. |
||||
$response->headers. PHP_EOL. |
||||
json_encode($response->getContent(), JSON_UNESCAPED_UNICODE); |
||||
} |
||||
|
||||
/** |
||||
* 获取json相应字符串 |
||||
* @param JsonResponse $response |
||||
* @return string |
||||
*/ |
||||
protected function getJsonResponseStr(JsonResponse $response): string |
||||
{ |
||||
return PHP_EOL. sprintf('HTTP/%s %s %s', $response->getProtocolVersion(), $response->getStatusCode(), Response::$statusTexts[$response->getStatusCode()]). PHP_EOL. |
||||
$response->headers. PHP_EOL. json_encode($response->getData(), JSON_UNESCAPED_UNICODE); |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Requests\Auth; |
||||
|
||||
use Illuminate\Contracts\Validation\ValidationRule; |
||||
use Illuminate\Foundation\Http\FormRequest; |
||||
|
||||
class LoginRequest extends FormRequest |
||||
{ |
||||
|
||||
/** |
||||
* Determine if the user is authorized to make this request. |
||||
*/ |
||||
public function authorize(): bool |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Get the validation rules that apply to the request. |
||||
* |
||||
* @return array<string, ValidationRule|array|string> |
||||
*/ |
||||
public function rules(): array |
||||
{ |
||||
return [ |
||||
// 'username' => 'required', |
||||
// 'password' => 'required', |
||||
'code' => 'required' |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @return array |
||||
*/ |
||||
public function messages(): array |
||||
{ |
||||
return [ |
||||
'username.required' => '入参错误', |
||||
'password.required' => '入参错误', |
||||
'code.required' => '入参错误' |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,92 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Requests\Patient; |
||||
|
||||
use App\Dictionary\Patient\IdentifyCardType; |
||||
use Illuminate\Contracts\Validation\ValidationRule; |
||||
use Illuminate\Foundation\Http\FormRequest; |
||||
|
||||
class BindPatientRequest extends FormRequest |
||||
{ |
||||
/** |
||||
* Determine if the user is authorized to make this request. |
||||
*/ |
||||
public function authorize(): bool |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Get the validation rules that apply to the request. |
||||
* |
||||
* @return array<string, ValidationRule|array|string> |
||||
*/ |
||||
/** |
||||
* 规则 |
||||
* @return array |
||||
*/ |
||||
public function rules(): array |
||||
{ |
||||
return [ |
||||
'name' => 'required', |
||||
'card_type' => 'required', |
||||
'card_no' => ['required', function ($attribute, $value, $fail) { |
||||
$card_type = getIDCardType($value); |
||||
|
||||
switch ($card_type) { |
||||
// 未知证件,身份证,港澳台社保卡号 |
||||
case 0: |
||||
case 1: |
||||
if (!IdentifyCardType::RESIDENT_ID_CARD->validateNumber($value)) { |
||||
$fail('证件号码格式错误'); |
||||
} |
||||
break; |
||||
case 2: |
||||
if (!IdentifyCardType::SOCIAL_SECURITY_CARD->validateNumber($value)) { |
||||
$fail('证件号码格式错误'); |
||||
} |
||||
break; |
||||
// 2017/2023 版永居证 |
||||
case 3: |
||||
case 4: |
||||
if (!IdentifyCardType::FOREIGNER_PERMANENT_RESIDENCE_PERMIT->validateNumber($value)) { |
||||
$fail('证件号码格式错误'); |
||||
} |
||||
break; |
||||
} |
||||
}], |
||||
'patient_id' => 'required|max:20' |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 错误提示语句 |
||||
* @return array |
||||
*/ |
||||
public function messages(): array |
||||
{ |
||||
return [ |
||||
'name.required' => '必须填写名称', |
||||
'name.max' => '名称限制最大长度为50', |
||||
'card_type.required' => '必须选择证件类型', |
||||
'card_type.enum' => '证件类型选择错误', |
||||
'card_no.required' => '必须填写证件号码', |
||||
'patient_id.required' => '必须填写就诊卡号', |
||||
'patient_id.max' => '就诊卡号长度最大为20' |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 字段名称 |
||||
* @return array |
||||
*/ |
||||
public function attributes(): array |
||||
{ |
||||
return [ |
||||
'name' => '名称', |
||||
'identity_type' => '证件类型', |
||||
'identity_no' => '证件号码', |
||||
'patient_id' => '就诊卡号', |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,99 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Requests\Patient; |
||||
|
||||
use App\Dictionary\Patient\IdentifyCardType; |
||||
use Illuminate\Contracts\Validation\ValidationRule; |
||||
use Illuminate\Foundation\Http\FormRequest; |
||||
|
||||
class CreatePatientRequest extends FormRequest |
||||
{ |
||||
/** |
||||
* Determine if the user is authorized to make this request. |
||||
*/ |
||||
public function authorize(): bool |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Get the validation rules that apply to the request. |
||||
* |
||||
* @return array<string, ValidationRule|array|string> |
||||
*/ |
||||
/** |
||||
* 规则 |
||||
* @return array |
||||
*/ |
||||
public function rules(): array |
||||
{ |
||||
return [ |
||||
'name' => 'required', |
||||
'card_type' => 'required', |
||||
'card_no' => ['required', function ($attribute, $value, $fail) { |
||||
$card_type = getIDCardType($value); |
||||
|
||||
switch ($card_type) { |
||||
// 未知证件,身份证,港澳台社保卡号 |
||||
case 0: |
||||
case 1: |
||||
if (!IdentifyCardType::RESIDENT_ID_CARD->validateNumber($value)) { |
||||
$fail('证件号码格式错误'); |
||||
} |
||||
break; |
||||
case 2: |
||||
if (!IdentifyCardType::SOCIAL_SECURITY_CARD->validateNumber($value)) { |
||||
$fail('证件号码格式错误'); |
||||
} |
||||
break; |
||||
// 2017/2023 版永居证 |
||||
case 3: |
||||
case 4: |
||||
if (!IdentifyCardType::FOREIGNER_PERMANENT_RESIDENCE_PERMIT->validateNumber($value)) { |
||||
$fail('证件号码格式错误'); |
||||
} |
||||
break; |
||||
} |
||||
}], |
||||
'phone' => ['required', function ($attribute, $value, $fail) { |
||||
if (!checkMobilePhone($value)) { |
||||
$fail('联系号码格式错误'); |
||||
} |
||||
}], |
||||
'birthday' => 'required|date_format:Y-m-d', |
||||
'sex' => 'required|in:1,2', |
||||
// 'nation' => 'max:50', |
||||
'address' => 'required|max:100' |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 错误提示语句 |
||||
* @return array |
||||
*/ |
||||
public function messages(): array |
||||
{ |
||||
return [ |
||||
'sex.required' => '必须选择性别' |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 字段名称 |
||||
* @return array |
||||
*/ |
||||
public function attributes(): array |
||||
{ |
||||
return [ |
||||
'name' => '名称', |
||||
'card_type' => '证件类型', |
||||
'card_no' => '证件号码', |
||||
'phone' => '联系号码', |
||||
'sex' => '性别', |
||||
'birthday' => '生日', |
||||
'nationality' => '国籍', |
||||
'nation' => '民族', |
||||
'address' => '住址', |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Dictionary; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class ItemDetailsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
$lists = []; |
||||
foreach ($this->resource['ITEM'] as $v) { |
||||
$lists[] = [ |
||||
'type_name' => $v['TYPENAME'], |
||||
'item_name' => $v['COSTNAME'], |
||||
'unit' => $v['UNIT'], |
||||
'spec' => $v['COSTSPEC'], |
||||
'price' => $v['PRICE'], |
||||
'cd_name' => $v['CDNAME'] ?? '', |
||||
]; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Dictionary; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class ItemListsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
$lists = []; |
||||
foreach ($this->resource['ITEM'] as $v) { |
||||
$lists[] = [ |
||||
'type_id' => (int) $v['TYPEID'], |
||||
'type_name' => $v['TYPENAME'], |
||||
]; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Patient; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class PatientDetailsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
return [ |
||||
'patient_id' => $this->resource['patient_id'], |
||||
'patient_card_id' => $this->resource['patient_card_id'], |
||||
'patient_name' => $this->resource['name'], |
||||
'card_no' => $this->resource['card_no'], |
||||
'sex' => $this->resource['sex'], |
||||
'is_default' => $this->resource['def_status'] |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Patient; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class PatientListsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
$lists = []; |
||||
foreach ($this->resource as $v) { |
||||
$lists[] = [ |
||||
'patient_id' => $v['patient_id'], |
||||
'patient_name' => $v['name'], |
||||
'is_default' => $v['def_status'] |
||||
]; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Registration\Record; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class RecordListsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
$this->resource = xmlArrayToListByKey($this->resource, 'ITEM'); |
||||
|
||||
$lists = []; |
||||
foreach ($this->resource['ITEM'] as $v) { |
||||
$lists[] = [ |
||||
'reg_serial_no' => $v['VISITNO'], |
||||
'reg_type' => $v['FTYPE'], |
||||
'reg_date' => $v['GHDATE'], |
||||
'patient_id' => $v['PATIENTID'], |
||||
'patient_name' => $v['PATIENTNAME'], |
||||
'dept_id' => $v['DEPID'], |
||||
'dept_name' => $v['DEPNAME'], |
||||
'rank_id' => $v['RANKID'], |
||||
'rank_name' => $v['RANKNAME'] ?? '', |
||||
'start_time' => $v['STARTTIME'] ?? '', |
||||
'end_time' => $v['ENDTIME'] ?? '', |
||||
'dept_location' => $v['DEPLOCATION'], |
||||
'reg_fee' => $v['PAYFEE'], |
||||
'trea_id' => $v['TREAID'], |
||||
'tran_snum' => $v['TRANSNUM'], |
||||
'wait_no' => $v['WAITNUM'], |
||||
'reg_status' => $v['STATUS'], |
||||
]; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Registration\Schedule; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class DeptListsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
$this->resource = xmlArrayToListByKey($this->resource, 'ITEM'); |
||||
|
||||
$lists = []; |
||||
foreach ($this->resource['ITEM'] as $v) { |
||||
$lists[] = [ |
||||
'dept_id' => $v['DEPID'], |
||||
'dept_name' => $v['DEPNAME'], |
||||
'dept_intro' => $v['INTRODUCE'] |
||||
]; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
<?php |
||||
|
||||
namespace App\Http\Resources\Registration\Schedule; |
||||
|
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Http\Resources\Json\JsonResource; |
||||
|
||||
class DoctorListsResource extends JsonResource |
||||
{ |
||||
/** |
||||
* Transform the resource into an array. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function toArray(Request $request = null): array |
||||
{ |
||||
$this->resource = xmlArrayToListByKey($this->resource, 'ITEM'); |
||||
|
||||
$lists = []; |
||||
foreach ($this->resource['ITEM'] as $k=>$v) { |
||||
$lists[$k] = [ |
||||
'doctor_id' => $v['DOCTID'], |
||||
'doctor_name' => $v['DOCTNAME'], |
||||
'doctor_title' => $v['TYPENAME'], |
||||
'doctor_intro' => $v['DEPLOCATION'], |
||||
'is_doctor' => (int) $v['ISKSDOC'], |
||||
]; |
||||
|
||||
$v = xmlArrayToListByKey($v, 'SHIFT'); |
||||
foreach ($v['SHIFT'] as $k2=>$v2) { |
||||
$lists[$k]['schedule_lists'][$k2] = [ |
||||
'reg_id' => $v2['REGID'], |
||||
'date' => $v2['FDATE'], |
||||
'rank_id' => $v2['RANKID'], |
||||
'rank_name' => $v2['RANKNAME'], |
||||
'start_time' => $v2['STARTTIME'], |
||||
'end_time' => $v2['ENDTIME'], |
||||
'fee' => $v2['FEE'], |
||||
'fee_code' => $v2['FEECODE'], |
||||
'reg_count' => $v2['REGCOUNT'], |
||||
'no_visit_count' => $v2['JZCOUNT'], |
||||
]; |
||||
} |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Department extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'dept_id', |
||||
'type_id', |
||||
'dept_name', |
||||
'leader_name', |
||||
'image', |
||||
'location', |
||||
'telephone', |
||||
'sort', |
||||
'intro', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'type_id' => 'integer', |
||||
'sort' => 'integer', |
||||
]; |
||||
} |
@ -0,0 +1,36 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class DepartmentType extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'type_id', |
||||
'type_name', |
||||
'sort', |
||||
'icon', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'type_id' => 'integer', |
||||
'sort' => 'integer', |
||||
]; |
||||
} |
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
|
||||
class Doctor extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'doctor_id', |
||||
'doctor_name', |
||||
'dept_id', |
||||
'dept_name', |
||||
'title', |
||||
'image', |
||||
'sort', |
||||
'adept', |
||||
'intro', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'sort' => 'integer', |
||||
]; |
||||
} |
@ -0,0 +1,57 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||||
|
||||
class HealthCardReport extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'relate_order_id', |
||||
'relate_patient_id', |
||||
'scene', |
||||
'report_data', |
||||
'number', |
||||
'status', |
||||
'report_at', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'number' => 'integer', |
||||
'status' => 'integer', |
||||
'report_at' => 'datetime', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Order. |
||||
*/ |
||||
public function order(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Order::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships Patient. |
||||
*/ |
||||
public function patient(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Patient::class, 'relate_patient_id'); |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\HasMany; |
||||
|
||||
class Inpatient extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'open_id', |
||||
'inpatient_id', |
||||
'inpatient_name', |
||||
'in_time', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'in_time' => 'datetime', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships inpatientRechargeRecord. |
||||
*/ |
||||
public function inpatientRechargeRecord(): HasMany |
||||
{ |
||||
return $this->hasMany(InpatientRechargeRecord::class, 'relate_id'); |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||||
|
||||
class InpatientRechargeRecord extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that should be hidden for serialization. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'relate_id', |
||||
'relate_order_id', |
||||
'dept_id', |
||||
'dept_name', |
||||
'doctor_id', |
||||
'doctor_name', |
||||
'recharge_amount', |
||||
'extra_info', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'relate_id' => 'integer', |
||||
'relate_order_id' => 'integer', |
||||
'recharge_amount' => 'integer', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Order. |
||||
*/ |
||||
public function order(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Order::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships Inpatient. |
||||
*/ |
||||
public function inpatient(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Inpatient::class, 'relate_id'); |
||||
} |
||||
} |
@ -0,0 +1,416 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use App\Dictionary\Order\NotifyStatus; |
||||
use App\Dictionary\Order\PayMode; |
||||
use App\Dictionary\Order\PayType; |
||||
use App\Dictionary\Order\SourceId; |
||||
use App\Dictionary\Order\Status; |
||||
use App\Dictionary\Order\Type; |
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||||
use Illuminate\Database\Eloquent\Relations\HasMany; |
||||
use Illuminate\Database\Eloquent\Relations\HasOne; |
||||
|
||||
/** |
||||
* @method where(string $string, string $id) |
||||
* @method create(array $order_info) |
||||
*/ |
||||
class Order extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
protected $table = 'orders'; |
||||
|
||||
/** |
||||
* The attributes that should be hidden for serialization. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'relate_id', |
||||
'order_id', |
||||
'his_order_id', |
||||
'transaction_id', |
||||
'status', |
||||
'notify_status', |
||||
'type', |
||||
'pay_type', |
||||
'pay_mode', |
||||
'fee', |
||||
'self_fee', |
||||
'reduce_fee', |
||||
'refund_fee', |
||||
'open_id', |
||||
'patient_id', |
||||
'patient_name', |
||||
'source_id', |
||||
'payment_at', |
||||
'refunded_at', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'relate_id' => 'integer', |
||||
'status' => 'integer', |
||||
'type' => 'integer', |
||||
'pay_type' => 'integer', |
||||
'pay_mode' => 'integer', |
||||
'fee' => 'integer', |
||||
'self_fee' => 'integer', |
||||
'reduce_fee' => 'integer', |
||||
'refund_fee' => 'integer', |
||||
'source_id' => 'integer', |
||||
'payment_at' => 'datetime', |
||||
'refunded_at' => 'datetime', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Patient. |
||||
*/ |
||||
public function patient(): belongsTo |
||||
{ |
||||
return $this->belongsTo(Patient::class, 'patient_id', 'patient_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships Self Order. |
||||
*/ |
||||
public function order(): HasMany |
||||
{ |
||||
return $this->hasMany(__CLASS__, 'relate_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships RegistrationRecord Model. |
||||
* @return HasOne |
||||
*/ |
||||
public function registrationRecord(): HasOne |
||||
{ |
||||
return $this->hasOne(RegistrationRecord::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships OutpatientPaymentRecord Model. |
||||
* @return HasOne |
||||
*/ |
||||
public function outpatientPaymentRecord(): HasOne |
||||
{ |
||||
return $this->hasOne(OutpatientPaymentRecord::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* 获取订单ID |
||||
* @param PayType $pay_type 支付类型 |
||||
* @param string $user W 微信 D 大机器 X 小机器 H his |
||||
* @return string |
||||
*/ |
||||
public function getOrderId(PayType $pay_type, string $user = 'D'): string |
||||
{ |
||||
$order_id = $pay_type->order(). $user. date('YmdHis'). mt_rand(100, 999); |
||||
if ($this->where('order_id', $order_id)->first()) { |
||||
return $this->getOrderId($pay_type, $user); |
||||
} |
||||
|
||||
return $order_id; |
||||
} |
||||
|
||||
/** |
||||
* 获取退款订单ID |
||||
* @param string $order_id 原订单ID |
||||
* @param string $source_flag 退款来源标志 _ 程序自动冲正 R 人工退费 H His退款 |
||||
* @return string |
||||
*/ |
||||
public function getRefundOrderId(string $order_id, string $source_flag = '_'): string |
||||
{ |
||||
$refund_order_id = $order_id. $source_flag. mt_rand(100, 999); |
||||
if ($this->where('order_id', $refund_order_id)->first()) { |
||||
return $this->getRefundOrderId($order_id); |
||||
} |
||||
|
||||
return $refund_order_id; |
||||
} |
||||
|
||||
/** |
||||
* 获取订单详情by id |
||||
* @param string $id |
||||
* @return mixed |
||||
*/ |
||||
public function getOrderInfoById(string $id): mixed |
||||
{ |
||||
return $this->where('id', $id)->with('patient')->first(); |
||||
} |
||||
|
||||
/** |
||||
* 获取订单详情by order_id |
||||
* @param string $order_id |
||||
* @return mixed |
||||
*/ |
||||
public function getOrderInfoByOrderId(string $order_id): mixed |
||||
{ |
||||
return $this->where('order_id', $order_id)->with('patient')->first(); |
||||
} |
||||
|
||||
/** |
||||
* 创建订单 |
||||
* @param string $order_id |
||||
* @param PayType $pay_type |
||||
* @param float $fee |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @param string $patient_name |
||||
* @param Type $order_type |
||||
* @param SourceId $source_id |
||||
* @param array $reg_info |
||||
* @param array $outpatient_info |
||||
* @return mixed |
||||
*/ |
||||
public function createOrder(string $order_id, PayType $pay_type, float $fee, string $open_id, string $patient_id, string $patient_name, Type $order_type, SourceId $source_id, array $reg_info = [], array $outpatient_info = []): mixed |
||||
{ |
||||
|
||||
$order_info = [ |
||||
'relate_id' => 0, |
||||
'order_id' => $order_id, |
||||
'his_order_id' => '', |
||||
'transaction_id' => '', |
||||
'status' => Status::NORMAL->value, |
||||
'notify_status' => NotifyStatus::NO_ACCEPTED->value, |
||||
'type' => $order_type->value, |
||||
'pay_type' => $pay_type, |
||||
'pay_mode' => PayMode::PAYMENT->value, |
||||
'fee' => $fee, //分 |
||||
'self_fee' => $fee, //分 |
||||
'refund_fee' => 0, |
||||
'open_id' => $open_id, |
||||
'patient_id' => $patient_id, |
||||
'patient_name' => $patient_name, |
||||
'source_id' => $source_id, |
||||
]; |
||||
|
||||
// 操作订单记录进行创建操作 |
||||
if (in_array($order_type->value, [ |
||||
Type::TODAY_REGISTRATION->value, |
||||
Type::APPOINTMENT_REGISTRATION->value, |
||||
Type::OUTPATIENT_PAYMENT->value |
||||
])) { |
||||
$result = $this->create($order_info); |
||||
|
||||
if (!empty($result)) { |
||||
switch ($order_type->value) { |
||||
case Type::TODAY_REGISTRATION->value: |
||||
case Type::APPOINTMENT_REGISTRATION->value: |
||||
$result->registrationRecord()->create($reg_info); |
||||
break; |
||||
case Type::OUTPATIENT_PAYMENT->value: |
||||
$result->outpatientPaymentRecord()->create($outpatient_info); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
return $this->create($order_info); |
||||
} |
||||
|
||||
/** |
||||
* 创建退费/冲正订单 |
||||
* @param int $relate_order_id |
||||
* @param string $order_id |
||||
* @param PayType $pay_type |
||||
* @param float $fee |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @param string $patient_name |
||||
* @param Type $order_type |
||||
* @param SourceId $source_id |
||||
* @return mixed |
||||
*/ |
||||
public function createRefundOReverseOrder(int $relate_order_id, string $order_id, PayType $pay_type, float $fee, string $open_id, string $patient_id, string $patient_name, Type $order_type, SourceId $source_id): mixed |
||||
{ |
||||
$order_info = [ |
||||
'relate_id' => $relate_order_id, |
||||
'order_id' => $order_id, |
||||
'his_order_id' => '', |
||||
'transaction_id' => '', |
||||
'status' => Status::NORMAL->value, |
||||
'notify_status' => NotifyStatus::NO_ACCEPTED->value, |
||||
'type' => $order_type, |
||||
'pay_type' => $pay_type, |
||||
'pay_mode' => PayMode::REFUND->value, |
||||
'fee' => $fee, //分 |
||||
'self_fee' => 0, //分 |
||||
'refund_fee' => 0, |
||||
'open_id' => $open_id, |
||||
'patient_id' => $patient_id, |
||||
'patient_name' => $patient_name, |
||||
'source_id' => $source_id, |
||||
]; |
||||
|
||||
return $this->create($order_info); |
||||
} |
||||
|
||||
/** |
||||
* 订单确认 |
||||
* @param string $order_id |
||||
* @param string $his_order_id |
||||
* @param array $response |
||||
*/ |
||||
public function orderConfirm(string $order_id, string $his_order_id = '', array $response = []): void |
||||
{ |
||||
$order = $this->where('order_id', $order_id)->first(); |
||||
|
||||
!empty($his_order_id) && $order->his_order_id = $his_order_id; |
||||
$order->status = Status::SUCCESS->value; |
||||
$order->save(); |
||||
|
||||
if (in_array($order->type, [Type::TODAY_REGISTRATION->value, Type::APPOINTMENT_REGISTRATION->value, Type::OUTPATIENT_PAYMENT->value]) && !empty($response)) { |
||||
|
||||
switch ($order->type) { |
||||
case Type::TODAY_REGISTRATION->value: |
||||
case Type::APPOINTMENT_REGISTRATION->value: |
||||
$record = $order->registrationRecord; |
||||
$extra_info = json_decode($record->extra_info, true); |
||||
$extra_info['confirm_response'] = $response; |
||||
|
||||
$record->update(['reg_id' => $response['AdmNo'] ?? '', 'extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]); |
||||
break; |
||||
case Type::OUTPATIENT_PAYMENT->value: |
||||
$record = $order->outpatientPaymentREcord; |
||||
$extra_info = json_decode($record->extra_info, true); |
||||
$extra_info['confirm_response'] = $response; |
||||
|
||||
$record->update(['extra_info' => json_encode($extra_info, JSON_UNESCAPED_UNICODE)]); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 修改订单状态 |
||||
* @param string $order_id |
||||
* @param Status $status |
||||
*/ |
||||
public function changeOrderStatus(string $order_id, Status $status): void |
||||
{ |
||||
$order = $this->where('order_id', $order_id)->first(); |
||||
$order->status = $status; |
||||
$order->save(); |
||||
} |
||||
|
||||
/** |
||||
* 订单异常(用户交钱成功,his业务确认异常 |
||||
* @param string $order_id |
||||
*/ |
||||
public function abnormalOrderOpera(string $order_id): void |
||||
{ |
||||
$order = $this->where('order_id', $order_id)->first(); |
||||
$order->status = Status::ABNORMAL->value; |
||||
$order->save(); |
||||
} |
||||
|
||||
/** |
||||
* 订单冲正(用户交钱成功,his业务确认失败) |
||||
* @param string $order_id |
||||
* @param float $refund_fee 此处是元 |
||||
* @param bool $is_success 退款是否成功 |
||||
*/ |
||||
public function reverseOrderOpera(string $order_id, float $refund_fee, bool $is_success): void |
||||
{ |
||||
$r_order = $this->where('order_id', $order_id)->first(); |
||||
|
||||
//原订单 |
||||
if ($is_success) { |
||||
$order = $this->where('id', $r_order->relate_id)->first(); |
||||
$order->refund_fee += $refund_fee * 100; |
||||
$order->status = Status::REVERSE->value; |
||||
$order->save(); |
||||
} |
||||
|
||||
// 保存退费/冲正订单 |
||||
$r_order->status = $is_success ? Status::SUCCESS->value : Status::FAILURE->value; |
||||
$r_order->refunded_at = date('Y-m-d H:i:s'); |
||||
$r_order->save(); |
||||
} |
||||
|
||||
/** |
||||
* 挂号订单解锁 |
||||
* @param string $order_id |
||||
* @return void |
||||
*/ |
||||
public function regOrderUnlock(string $order_id): void |
||||
{ |
||||
$order = $this->where('order_id', $order_id)->with('registrationRecord')->first(); |
||||
|
||||
$order->registrationRecord->lock_status = 2; |
||||
$order->registrationRecord->unlock_at = date('Y-m-d H:i:s'); |
||||
$order->registrationRecord->save(); |
||||
|
||||
$order->status = Status::FAILURE->value; |
||||
$order->save(); |
||||
} |
||||
|
||||
/** |
||||
* 订单取消预结算 |
||||
* @param string $order_id |
||||
* @return void |
||||
*/ |
||||
public function outpatientOderCancelPreSettle(string $order_id): void |
||||
{ |
||||
$order = $this->where('order_id', $order_id)->with('outpatientPaymentRecord')->first(); |
||||
|
||||
$order->outpatientPaymentRecord->pre_settle_status = 2; |
||||
$order->outpatientPaymentRecord->cancel_pre_settle_at = date('Y-m-d H:i:s'); |
||||
$order->outpatientPaymentRecord->save(); |
||||
|
||||
$order->status = Status::FAILURE->value; |
||||
$order->save(); |
||||
} |
||||
|
||||
/** |
||||
* 操作订单冲正 |
||||
* @param string $order_id |
||||
* @param int $order_type |
||||
* @param string $patient_id |
||||
* @param string $patient_name |
||||
* @param PayType $pay_type |
||||
* @param float $fee |
||||
* @param array $pay_params |
||||
* @param array $pay_res_data |
||||
* @return string |
||||
*/ |
||||
public function handleOrderReverse(string $order_id, int $order_type, string $patient_id, string $patient_name, PayType $pay_type, float $fee, array $pay_params, array $pay_res_data) |
||||
{ |
||||
$relate_order_info = $this->getOrderInfoByOrderId($order_id); |
||||
|
||||
// 创建冲正订单 |
||||
$r_order_id = $this->getRefundOrderId($order_id); |
||||
$this->createRefundOReverseOrder($relate_order_info['id'], $r_order_id, $pay_type, $fee * 100, $patient_id, $patient_name, $order_type); |
||||
|
||||
// 退款 |
||||
$refund_res = fastOrderRefund($pay_type, $order_id, $r_order_id, $fee, $pay_params, $pay_res_data); |
||||
$this->addLog('order reverse', '订单冲正', $refund_res); |
||||
|
||||
// 冲正失败 |
||||
if (!$refund_res[0]) { |
||||
$this->reverseOrderOpera($r_order_id, $fee, false); |
||||
return '冲正失败,失败原因:'. $refund_res[1]. ',请前往人工窗口进行退款!'; |
||||
} |
||||
|
||||
$this->reverseOrderOpera($r_order_id, $fee, true); |
||||
return '冲正成功,请稍后再行尝试!'; |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||||
|
||||
class OutpatientPaymentRecord extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'relate_order_id', |
||||
'relate_patient_id', |
||||
'dept_id', |
||||
'dept_name', |
||||
'doctor_id', |
||||
'doctor_name', |
||||
'visit_date', |
||||
'total_amount', |
||||
'pre_settle_status', |
||||
'pre_settle_at', |
||||
'cancel_pre_settle_at', |
||||
'extra_info', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'relate_order_id' => 'integer', |
||||
'relate_patient_id' => 'integer', |
||||
'total_amount' => 'integer', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Order. |
||||
*/ |
||||
public function order(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Order::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships Patient. |
||||
*/ |
||||
public function patient(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Patient::class, 'relate_patient_id'); |
||||
} |
||||
} |
@ -0,0 +1,199 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use App\Dictionary\Patient\Sex; |
||||
use App\Utils\Traits\UniversalEncryption; |
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\HasMany; |
||||
|
||||
/** |
||||
* @method where(string $string, string $open_id) |
||||
* @method create(array $data) |
||||
*/ |
||||
class Patient extends Model |
||||
{ |
||||
use HasFactory; |
||||
use UniversalEncryption; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'union_id', |
||||
'open_id', |
||||
'patient_id', |
||||
'card_type', |
||||
'card_no', |
||||
'name', |
||||
'sex', |
||||
'birthday', |
||||
'mobile_phone', |
||||
'address', |
||||
'qr_code_text', |
||||
'health_card_id', |
||||
'health_card_status', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'card_type' => 'integer', |
||||
'sex' => 'integer', |
||||
'health_card_status' => 'integer', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Order. |
||||
*/ |
||||
public function order(): HasMany |
||||
{ |
||||
return $this->hasMany(Order::class, 'patient_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships RegistrationRecord. |
||||
*/ |
||||
public function registrationRecord(): HasMany |
||||
{ |
||||
return $this->hasMany(Order::class, 'relate_patient_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships outpatientPaymentRecord. |
||||
*/ |
||||
public function outpatientPaymentRecord(): HasMany |
||||
{ |
||||
return $this->hasMany(Order::class, 'relate_patient_id'); |
||||
} |
||||
|
||||
/** |
||||
* 获取绑定患者数量 |
||||
* @param string $open_id |
||||
* @return mixed |
||||
*/ |
||||
public function getBindPatientCount(string $open_id): mixed |
||||
{ |
||||
return $this->where('open_id', $open_id)->count(); |
||||
} |
||||
|
||||
/** |
||||
* 获取患者列表 |
||||
* @param string $open_id |
||||
* @return mixed |
||||
*/ |
||||
public function getBindPatientLists(string $open_id): mixed |
||||
{ |
||||
return $this->where('open_id', $open_id)->orderByDesc('def_status')->get(); |
||||
} |
||||
|
||||
/** |
||||
* 获取默认患者数据 |
||||
* @param string $open_id |
||||
* @return mixed |
||||
*/ |
||||
public function getBindDefaultPatientInfo(string $open_id): mixed |
||||
{ |
||||
return $this->where('open_id', $open_id)->orderByDesc('def_status')->first(); |
||||
} |
||||
|
||||
/** |
||||
* 获取绑定患者信息 |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @return mixed |
||||
*/ |
||||
public function getBindPatientInfo(string $open_id, string $patient_id): mixed |
||||
{ |
||||
return $this->where('open_id', $open_id)->where('patient_id', $patient_id)->first(); |
||||
} |
||||
|
||||
/** |
||||
* 获取绑定患者信息By Id |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @return mixed |
||||
*/ |
||||
public function getBindPatientInfoByPatientId(string $open_id, string $patient_id): mixed |
||||
{ |
||||
return $this->where('open_id', $open_id)->where('patient_id', $patient_id)->first(); |
||||
} |
||||
|
||||
/** |
||||
* 获取绑定患者信息By Patient Id |
||||
* @param string $patient_id |
||||
* @return mixed |
||||
*/ |
||||
public function getPatientInfoByPatientId(string $patient_id): mixed |
||||
{ |
||||
return $this->where('patient_id', $patient_id)->first(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 建档 |
||||
* @param string $union_id |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @param string $name |
||||
* @param Sex $gender |
||||
* @return mixed |
||||
*/ |
||||
public function createPatient(string $union_id, string $open_id, string $patient_id, string $name, Sex $gender): mixed |
||||
{ |
||||
$data = [ |
||||
'union_id' => $union_id, |
||||
'open_id' => $open_id, |
||||
'patient_id' => $patient_id, |
||||
'card_type' => 0, |
||||
'card_no' => '', |
||||
'name' => $name, |
||||
'sex' => $gender->value, |
||||
'birthday' => '', |
||||
'mobile_phone' => '', |
||||
'address' => '', |
||||
'def_status' => 0 |
||||
]; |
||||
|
||||
$count = $this->where('open_id', $open_id)->where('def_status', 1)->count(); |
||||
if (!$count) { |
||||
$data['def_status'] = 1; |
||||
} |
||||
|
||||
return $this->create($data); |
||||
} |
||||
|
||||
/** |
||||
* 设置默认 |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @return bool |
||||
*/ |
||||
public function setDefaultPatient(string $open_id, string $patient_id): bool |
||||
{ |
||||
$this->where('open_id', $open_id)->update(['def_status' => 0]); |
||||
$res = $this->where('open_id', $open_id)->where('patient_id', $patient_id)->update(['def_status' => 1]); |
||||
|
||||
return !!$res; |
||||
} |
||||
|
||||
/** |
||||
* 删卡 |
||||
* @param string $open_id |
||||
* @param string $patient_id |
||||
* @return integer |
||||
*/ |
||||
public function deletePatient(string $open_id, string $patient_id): int |
||||
{ |
||||
return $this->where('open_id', $open_id)->where('patient_id', $patient_id)->delete(); |
||||
} |
||||
} |
@ -0,0 +1,91 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use App\Dictionary\PushMessage\Type; |
||||
use App\Dictionary\WeChat\Official\SubscribeId; |
||||
use App\Dictionary\WeChat\Official\TemplateId; |
||||
use App\Jobs\SendWeChatMessage; |
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||||
use Modules\Official\Structs\Message\CustomMessage; |
||||
use Modules\Official\Structs\Message\SubscribeMessage; |
||||
use Modules\Official\Structs\Message\TemplateData\Common; |
||||
use Modules\Official\Structs\Message\TemplateMessage; |
||||
|
||||
class PushWechatMessage extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'relate_order_id', |
||||
'relate_patient_id', |
||||
'type', |
||||
'template_id', |
||||
'scene', |
||||
'content', |
||||
'number', |
||||
'status', |
||||
'sent_at', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'relate_order_id' => 'integer', |
||||
'relate_patient_id' => 'integer', |
||||
'number' => 'integer', |
||||
'status' => 'integer', |
||||
'sent_at' => 'datetime', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Order. |
||||
*/ |
||||
public function order(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Order::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships Patient. |
||||
*/ |
||||
public function patient(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Patient::class, 'relate_patient_id'); |
||||
} |
||||
|
||||
/** |
||||
* 插入推送消息队列 |
||||
* @param int $relate_order_id |
||||
* @param int $relate_patient_id |
||||
* @param TemplateId|SubscribeId|null $template_id |
||||
* @param TemplateMessage|SubscribeMessage|CustomMessage $message |
||||
* @return mixed |
||||
*/ |
||||
public function insertMessageJobs(int $relate_order_id, int $relate_patient_id, TemplateId|SubscribeId|null $template_id, TemplateMessage|SubscribeMessage|CustomMessage $message): mixed |
||||
{ |
||||
$data = [ |
||||
'relate_order_id' => $relate_order_id, |
||||
'relate_patient_id' => $relate_patient_id, |
||||
'type' => Type::OFFICIAL_TEMPLATE->value, |
||||
'template_id' => $template_id, |
||||
'scene' => '', |
||||
'content' => serialize($message), |
||||
]; |
||||
|
||||
return $this->create($data); |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Database\Eloquent\Model; |
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||||
|
||||
class RegistrationRecord extends Model |
||||
{ |
||||
use HasFactory; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var array<int, string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'relate_order_id', |
||||
'relate_patient_id', |
||||
'reg_id', |
||||
'dept_id', |
||||
'dept_name', |
||||
'dept_location', |
||||
'doctor_id', |
||||
'doctor_name', |
||||
'visit_date', |
||||
'begin_time', |
||||
'end_time', |
||||
'lock_status', |
||||
'lock_at', |
||||
'extra_info', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be cast. |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
protected $casts = [ |
||||
'id' => 'integer', |
||||
'relate_order_id' => 'integer', |
||||
'relate_patient_id' => 'integer', |
||||
'lock_status' => 'integer', |
||||
'lock_at' => 'datetime', |
||||
]; |
||||
|
||||
/** |
||||
* Relationships Order. |
||||
*/ |
||||
public function order(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Order::class, 'relate_order_id'); |
||||
} |
||||
|
||||
/** |
||||
* Relationships Patient. |
||||
*/ |
||||
public function patient(): BelongsTo |
||||
{ |
||||
return $this->belongsTo(Patient::class, 'relate_patient_id'); |
||||
} |
||||
|
||||
/** |
||||
* 获取挂号记录by reg_id |
||||
* @param string $reg_id |
||||
* @return mixed |
||||
*/ |
||||
public function getRecordByRegID(string $reg_id): mixed |
||||
{ |
||||
return $this->where('reg_id', $reg_id)->first(); |
||||
} |
||||
} |
@ -0,0 +1,49 @@ |
||||
<?php |
||||
|
||||
namespace App\Models; |
||||
|
||||
use Database\Factories\UserFactory; |
||||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
use Illuminate\Foundation\Auth\User as Authenticatable; |
||||
use Illuminate\Notifications\Notifiable; |
||||
use Laravel\Sanctum\HasApiTokens; |
||||
|
||||
class User extends Authenticatable |
||||
{ |
||||
/** @use HasFactory<UserFactory> */ |
||||
use HasApiTokens, HasFactory, Notifiable; |
||||
|
||||
/** |
||||
* The attributes that are mass assignable. |
||||
* |
||||
* @var list<string> |
||||
*/ |
||||
protected $fillable = [ |
||||
'name', |
||||
'email', |
||||
'password', |
||||
]; |
||||
|
||||
/** |
||||
* The attributes that should be hidden for serialization. |
||||
* |
||||
* @var list<string> |
||||
*/ |
||||
protected $hidden = [ |
||||
'password', |
||||
'remember_token', |
||||
]; |
||||
|
||||
/** |
||||
* Get the attributes that should be cast. |
||||
* |
||||
* @return array<string, string> |
||||
*/ |
||||
protected function casts(): array |
||||
{ |
||||
return [ |
||||
'email_verified_at' => 'datetime', |
||||
'password' => 'hashed', |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
<?php |
||||
|
||||
namespace App\Providers; |
||||
|
||||
use App\Services\HisSoap\Client; |
||||
use Illuminate\Support\Facades\Route; |
||||
use Illuminate\Routing\UrlGenerator; |
||||
use Illuminate\Support\Facades\Schema; |
||||
use Illuminate\Support\ServiceProvider; |
||||
|
||||
class AppServiceProvider extends ServiceProvider |
||||
{ |
||||
/** |
||||
* Register any application services. |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function register(): void |
||||
{ |
||||
$this->cross(); |
||||
$this->registerHisService(); |
||||
} |
||||
|
||||
/** |
||||
* Bootstrap any application services. |
||||
* |
||||
* @param UrlGenerator $url |
||||
* @return void |
||||
*/ |
||||
public function boot(UrlGenerator $url): void |
||||
{ |
||||
Schema::defaultStringLength(191); |
||||
|
||||
// Route参数表正则绑定 |
||||
Route::pattern('patient_id', '[0-9]+'); |
||||
Route::pattern('serial_no', '[0-9]+'); |
||||
|
||||
// 配置https |
||||
if(env('REDIRECT_HTTPS')) { |
||||
$url->forceScheme('https'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 允许跨域 |
||||
* @return void |
||||
*/ |
||||
protected function cross(): void |
||||
{ |
||||
header("Access-Control-Allow-Origin: *"); |
||||
header("Access-Control-Allow-Methods: GET,PUT,POST,PATCH,DELETE"); |
||||
header('Access-Control-Allow-Headers:x-requested-with,content-type,Authorization'); |
||||
} |
||||
|
||||
protected function registerHisService(): void |
||||
{ |
||||
// His平台服务 |
||||
$this->app->singleton('HisSoapService', function () { |
||||
return new Client(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,393 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Services\HisSoap; |
||||
|
||||
use App\Dictionary\Patient\CardType; |
||||
use App\Dictionary\Patient\Sex; |
||||
use App\Exceptions\GeneralException; |
||||
use App\Utils\Traits\Logger; |
||||
use App\Utils\Transfer\HisSoap\ClientFactory; |
||||
use App\Utils\Transfer\TransferAbstract; |
||||
use Exception; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
|
||||
class Client |
||||
{ |
||||
use Logger; |
||||
|
||||
private string $user_id = 'MINI'; |
||||
|
||||
// his服务 |
||||
private TransferAbstract $service; |
||||
|
||||
public function __construct() |
||||
{ |
||||
$his_name = 'his_soap'; |
||||
$this->service = ClientFactory::getClientTransfer($his_name); |
||||
$this->setChannel($his_name); |
||||
} |
||||
|
||||
/** |
||||
* 请求 |
||||
* @param string $class_name |
||||
* @param string $method_name |
||||
* @param array $params |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
protected function requestHandle(string $class_name, string $method_name, array $params): mixed |
||||
{ |
||||
try { |
||||
return $this->service->transferClass($class_name) |
||||
->transferMethod($method_name, array_values($params)) |
||||
->getResult(); |
||||
|
||||
} catch (Exception $e) { |
||||
$err_msg = "{$e->getMessage()} ON {$e->getFile()}:{$e->getLine()}"; |
||||
$this->error('调用soap接口失败, 错误消息:' . $err_msg, $params); |
||||
|
||||
throw new GeneralException($e->getMessage(), Response::HTTP_SERVICE_UNAVAILABLE); |
||||
} |
||||
} |
||||
|
||||
// Patient Module Start |
||||
|
||||
/** |
||||
* 建档 |
||||
* @param string $card_no |
||||
* @param CardType $card_type |
||||
* @param string $patient_name |
||||
* @param Sex $sex |
||||
* @param string $birthday |
||||
* @param string $id_card_no |
||||
* @param string $mobile |
||||
* @param string $address |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function registerCard(string $card_no, CardType $card_type, string $patient_name, Sex $sex, string $birthday, string $id_card_no, string $mobile, string $address): mixed |
||||
{ |
||||
return $this->requestHandle('Create', 'CreateCardPatInfo', [ |
||||
'CARDNO' => $card_no, |
||||
'CARDTYPE' => $card_type->value, |
||||
'PATIENTNAME' => $patient_name, |
||||
'SEX' => $sex->value, |
||||
'BIRTHDAY' => $birthday, |
||||
'IDCARDNO' => $id_card_no, |
||||
'MOBILE' => $mobile, |
||||
'ADDRESS' => $address, |
||||
'USERID' => $this->user_id, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 获取患者信息 |
||||
* @param string $register_area 挂号区域(默认为 01) |
||||
* @param string $card_no 卡号 |
||||
* @param CardType $card_type 卡类型 |
||||
* @param string $name 姓名 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getPatientInfo(string $register_area, string $card_no, CardType $card_type, string $name): mixed |
||||
{ |
||||
// 默认挂号区域为 "01",如果提供了挂号区域,则使用提供的区域 |
||||
$register_area = empty($register_area) ? '01' : $register_area; |
||||
|
||||
// 调用请求处理方法 |
||||
return $this->requestHandle('Get', 'GetCardInfo', [ |
||||
'REGISTERAREA' => $register_area, |
||||
'CARDNO' => $card_no, |
||||
'CARDTYPE' => $card_type->value, |
||||
'NAME' => $name, |
||||
'USERID' => $this->user_id, |
||||
]); |
||||
} |
||||
|
||||
// Patient Module End |
||||
|
||||
// Registration Module Start |
||||
|
||||
/** |
||||
* 获取科室信息(校验身份证有效卡) |
||||
* @param string $type_id 科室大类编码(如 1 普通门诊,2 急诊门诊,3 专家门诊) |
||||
* @param string $type_name 科室大类名称(如 普通门诊,急诊门诊,专家门诊) |
||||
* @param string $register_area 挂号区域(默认为 01) |
||||
* @param string $date 挂号日期(格式为 yyyy-mm-dd) |
||||
* @param string $rank_id 班次(如 1 上午,2 下午,3 晚上,4 中午) |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDepLists( |
||||
string $type_id, |
||||
string $type_name, |
||||
string $register_area = '01', // 默认挂号区域为 01 |
||||
string $date = '', // 默认日期为空,表示查询所有科室 |
||||
string $rank_id = '' // 默认班次为空,表示查询所有班次 |
||||
): mixed { |
||||
// 调用请求处理方法 |
||||
return $this->requestHandle('Get', 'GetDepType', [ |
||||
'TYPEID' => $type_id, |
||||
'TYPENAME' => $type_name, |
||||
'REGISTERAREA' => $register_area, |
||||
'USERID' => $this->user_id, |
||||
'DATE' => $date, |
||||
'RANKID' => $rank_id, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 查询医生排班信息 |
||||
* @param string $dept_id 科室编码 |
||||
* @param string $is_today 是否返回预约号源(0:当天挂号,1:返回预约明细号源,2:返回预约总号源,3:当天挂号加科室排班信息,4:返回当天挂号总号源,5:返回科室和医生排班信息) |
||||
* @param string $rank_id 班次(1:上午,2:下午,3:晚上,4:中午,默认返回所有班次) |
||||
* @param string $date 排班日期(格式为 yyyy-mm-dd,为空则返回当天以后的排班) |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDoctorLists( |
||||
string $dept_id, |
||||
string $is_today = '0', // 默认返回当天挂号 |
||||
string $rank_id = '', // 默认返回所有班次 |
||||
string $date = '' // 默认返回当天及以后的排班 |
||||
): mixed { |
||||
// 调用请求处理方法 |
||||
return $this->requestHandle('Get', 'GetDoctList', [ |
||||
'DEPID' => $dept_id, |
||||
'ISTODAYREGIST' => $is_today, |
||||
'RANKID' => $rank_id, |
||||
'DATE' => $date, |
||||
'USERID' => $this->user_id, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 查询挂号记录便于就诊 |
||||
* @param string $patient_id 患者ID |
||||
* @param string $start_date 挂号开始日期,默认为空表示从今天起之后的所有挂号记录 |
||||
* @param string $end_date 挂号结束日期,默认为空表示等于开始日期 |
||||
* @param string $type 查询类型(1:当天挂号,2:预约取号),默认为空表示查询所有 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getRegisterRecordLists( |
||||
string $patient_id, |
||||
string $start_date = '', // 可为空,表示从今天起之后的所有挂号记录 |
||||
string $end_date = '', // 可为空,默认等于开始日期 |
||||
string $type = '' // 可为空,默认查询所有类型 |
||||
): mixed { |
||||
return $this->requestHandle('Get', 'GetGHMXList', [ |
||||
'PATIENTID' => $patient_id, |
||||
'DATE' => $start_date, |
||||
'EDATE' => $end_date, |
||||
'TYPE' => $type, |
||||
'USERID' => $this->user_id, |
||||
]); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 检查挂号是否可以取消 |
||||
* @param string $visit_no 挂号流水号 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function checkRefundRegisterStatus(string $visit_no): mixed |
||||
{ |
||||
// 调用请求处理方法 |
||||
return $this->requestHandle('GH', 'GHCancelCheck', [ |
||||
'VISITNO' => $visit_no, |
||||
'USERID' => $this->user_id, // 假设用户 ID 来自当前实例 |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 确认挂号取消(退号) |
||||
* @param string $visit_no 挂号流水号 |
||||
* @param string $order_id 终端号(订单号) |
||||
* @param string $bank_tran_date 银行交易日期(格式:yyyy-mm-dd) |
||||
* @param string $bank_tran_time 银行交易时间(格式:hh24:mi:ss) |
||||
* @param string $bank_tran_amt 银行交易金额 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function refundRegister( |
||||
string $visit_no, |
||||
string $order_id, |
||||
string $bank_tran_date, |
||||
string $bank_tran_time, |
||||
string $bank_tran_amt |
||||
): mixed { |
||||
return $this->requestHandle('GH', 'GHCancelConfirm', [ |
||||
'VISITNO' => $visit_no, |
||||
'ORDERID' => $order_id, |
||||
'BANKTRANDATE' => $bank_tran_date, |
||||
'BANKTRANTIME' => $bank_tran_time, |
||||
'BANKTRANAMT' => $bank_tran_amt, |
||||
'USERID' => $this->user_id, |
||||
]); |
||||
} |
||||
|
||||
// Registration Module End |
||||
|
||||
// Outpatient Module Start |
||||
|
||||
/** |
||||
* 获取待缴费列表 |
||||
* @param string $patient_id |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getPendingLists(string $patient_id): mixed |
||||
{ |
||||
return $this->requestHandle('List', 'ListVisitRec ', [ |
||||
'PATIENTID' => $patient_id, |
||||
'USERID' => $this->user_id, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 查询就诊记录中的所有诊疗单据 |
||||
* @param string $cf_ids 处方号,多个处方号使用逗号分隔 |
||||
* @param string $jz_xh 就诊序号,必填 |
||||
* @param string $user_id 自助设备编码,必填 |
||||
* @param string $reg_id 号源编码,可选 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getPendingDetails( |
||||
string $cf_ids, |
||||
string $jz_xh, |
||||
string $user_id, |
||||
string $reg_id = '' |
||||
): mixed { |
||||
// 调用请求处理方法 |
||||
return $this->requestHandle('List', 'ListRecipe', [ |
||||
'CFID' => $cf_ids, |
||||
'JZXH' => $jz_xh, |
||||
'USERID' => $user_id, |
||||
'REGID' => $reg_id, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 获取门诊费用清单列表 |
||||
* @param string $patient_id 患者ID,必填 |
||||
* @param string $begin_date 开始日期,默认为当天(格式:yyyy-mm-dd) |
||||
* @param string $end_date 结束日期,默认为当天(格式:yyyy-mm-dd) |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getPaidLists( |
||||
string $patient_id, |
||||
string $begin_date = '', // 可为空,默认为当天 |
||||
string $end_date = '' // 可为空,默认为当天 |
||||
): mixed { |
||||
return $this->requestHandle('Outpatient', 'OutpatientExpenseRecord', [ |
||||
'PATIENTID' => $patient_id, |
||||
'BEGINDATE' => $begin_date, |
||||
'ENDDATE' => $end_date, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 获取门诊费用清单详情 |
||||
* @param string $receipt_id |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getPaidDetails(string $receipt_id): mixed { |
||||
return $this->requestHandle('Outpatient', 'OutpatientDetailRecord', [ |
||||
'Rcptid' => $receipt_id |
||||
]); |
||||
} |
||||
|
||||
// Outpatient Module End |
||||
|
||||
// Electron Module Start |
||||
|
||||
|
||||
/** |
||||
* 主动调用接口生成电子发票 |
||||
* @param string $trea_id 就诊编码(结算序号) |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function createElectronInvoice(string $trea_id) |
||||
{ |
||||
return $this->requestHandle('Create', 'CreateOutpatientinvoiceEBill', [ |
||||
'TREAID' => $trea_id |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* 发送电子票据信息给his |
||||
* @param string $treat_id 就诊编码(结算序号),必填 |
||||
* @param string $bill_batch_code 电子票据代码,必填 |
||||
* @param string $bill_no 电子票据号码,必填 |
||||
* @param string $random 电子校验码,必填 |
||||
* @param string $create_time 电子票据生成时间,格式:YYYYMMDDHHMMSSSSS,必填 |
||||
* @param string $bill_qr_code 电子票据二维码图片数据(BASE64编码),必填 |
||||
* @param string $picture_url 电子票据H5页面URL,必填 |
||||
* @param string $picture_net_url 电子票据外网H5页面URL,必填 |
||||
* @param string $wx_card_url 微信插卡URL,必填 |
||||
* @param string $bus_no 业务流水号(机构内部唯一),必填 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function sendElectronInvoiceToHis( |
||||
string $treat_id, |
||||
string $bill_batch_code, |
||||
string $bill_no, |
||||
string $random, |
||||
string $create_time, |
||||
string $bill_qr_code, |
||||
string $picture_url, |
||||
string $picture_net_url, |
||||
string $wx_card_url, |
||||
string $bus_no |
||||
): mixed { |
||||
return $this->requestHandle('Send', 'SendOutpatientinvoiceEBill', [ |
||||
'TREAID' => $treat_id, |
||||
'BILLBATCHCODE' => $bill_batch_code, |
||||
'BILLNO' => $bill_no, |
||||
'RANDOM' => $random, |
||||
'CREATETIME' => $create_time, |
||||
'BILLQRCODE' => $bill_qr_code, |
||||
'PICTUREURL' => $picture_url, |
||||
'PICTURENETURL' => $picture_net_url, |
||||
'WXCARDURL' => $wx_card_url, |
||||
'BUSNO' => $bus_no |
||||
]); |
||||
} |
||||
|
||||
// Electron Module End |
||||
|
||||
// Dictionary Module Start |
||||
|
||||
/** |
||||
* 获取收费项目类别列表 |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDictionaryLists(): mixed |
||||
{ |
||||
return $this->requestHandle('Get', 'GetDictionary', []); |
||||
} |
||||
|
||||
/** |
||||
* 获取收费项目详情 |
||||
* @param int $type_id 类别ID |
||||
* @return mixed |
||||
* @throws GeneralException |
||||
*/ |
||||
public function getDictionaryDetails(int $type_id): mixed |
||||
{ |
||||
return $this->requestHandle('Get', 'GetChargeList', [ |
||||
'TYPEID' => $type_id |
||||
]); |
||||
} |
||||
|
||||
// Dictionary Module End |
||||
} |
@ -0,0 +1,41 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils; |
||||
|
||||
use Monolog\Formatter\LineFormatter; |
||||
use Monolog\Handler\RotatingFileHandler; |
||||
use Monolog\Level; |
||||
use Monolog\Logger; |
||||
|
||||
class GeneralDailyLogger |
||||
{ |
||||
/** |
||||
* 创建一个通用的每日的日志通道 |
||||
* |
||||
* @param array<string, int|string|level> $config |
||||
* |
||||
* @return Logger |
||||
*/ |
||||
public function __invoke(array $config): Logger { |
||||
$service_type = is_string($config['service_type']) ? $config['service_type'] : 'default'; |
||||
$level = $config['level'] instanceof Level ? $config['level'] : Level::Debug; |
||||
$path = sprintf(storage_path(). "/logs/%s/%s.log", $service_type, $level->toPsrLogLevel()); |
||||
$max_file = is_numeric($config['max_files']) ? (int) $config['max_files'] : 0; |
||||
|
||||
// Set Handler |
||||
$handler = new RotatingFileHandler($path, $max_file, $level); |
||||
$handler->setFormatter( |
||||
new LineFormatter( |
||||
"[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n\n", |
||||
'Y-m-d H:i:s.u', |
||||
true, |
||||
true, |
||||
true |
||||
) |
||||
); |
||||
|
||||
return new Logger($service_type, [$handler]); |
||||
} |
||||
} |
@ -0,0 +1,781 @@ |
||||
<?php |
||||
|
||||
use EasyWeChat\MiniApp\Application; |
||||
use Illuminate\Http\JsonResponse; |
||||
use Illuminate\Support\Facades\Route; |
||||
|
||||
if (!function_exists('jsonResponse')) { |
||||
/** |
||||
* json返回 |
||||
* @param int $status_code |
||||
* @param string $msg |
||||
* @param array $data |
||||
* @return JsonResponse |
||||
*/ |
||||
function jsonResponse(int $status_code, string $msg, array $data = []): JsonResponse |
||||
{ |
||||
return response()->json([ |
||||
'message' => $msg, |
||||
'data' => $data, |
||||
'status_code' => $status_code |
||||
], $status_code)->setEncodingOptions(JSON_UNESCAPED_UNICODE); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('jsonResponseToHis')) { |
||||
/** |
||||
* json返回 to his |
||||
* @param int $status_code |
||||
* @param int $code |
||||
* @param string $msg |
||||
* @param array $data |
||||
* @return JsonResponse |
||||
*/ |
||||
function jsonResponseToHis(int $status_code, int $code, string $msg, array $data = []): JsonResponse |
||||
{ |
||||
return response()->json([ |
||||
'code' => $code, |
||||
'msg' => $msg, |
||||
'data' => $data, |
||||
], $status_code)->setEncodingOptions(JSON_UNESCAPED_UNICODE); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('validateIDCard')) { |
||||
/** |
||||
* 校验身份证格式 |
||||
* @param string $id_card |
||||
* @return bool |
||||
*/ |
||||
function validateIDCard(string $id_card): bool |
||||
{ |
||||
$id_card = strtoupper($id_card); |
||||
$regx = "/(^\d{15}$)|(^\d{17}([0-9]|X)$)/"; |
||||
$arr_split = []; |
||||
|
||||
if (!preg_match($regx, $id_card)) { |
||||
return false; |
||||
} |
||||
|
||||
if (15 == strlen($id_card)) { |
||||
//检查15位 |
||||
$regx = "/^(\d{6})+(\d{2})+(\d{2})+(\d{2})+(\d{3})$/"; |
||||
@preg_match($regx, $id_card, $arr_split); |
||||
|
||||
//检查生日日期是否正确 |
||||
$dtm_birth = "19".$arr_split[2] . '/' . $arr_split[3]. '/' .$arr_split[4]; |
||||
|
||||
if (!strtotime($dtm_birth)) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} else { |
||||
//检查18位 |
||||
$regx = "/^(\d{6})+(\d{4})+(\d{2})+(\d{2})+(\d{3})([0-9]|X)$/"; |
||||
@preg_match($regx, $id_card, $arr_split); |
||||
|
||||
//检查生日日期是否正确 |
||||
$dtm_birth = $arr_split[2] . '/' . $arr_split[3]. '/' .$arr_split[4]; |
||||
|
||||
if (!strtotime($dtm_birth)) { |
||||
return false; |
||||
} else { |
||||
//检验18位身份证的校验码是否正确。 |
||||
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。 |
||||
$arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2); |
||||
$arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'); |
||||
$sign = 0; |
||||
|
||||
for ( $i = 0; $i < 17; $i++ ) { |
||||
$b = (int) $id_card[$i]; |
||||
$w = $arr_int[$i]; |
||||
$sign += $b * $w; |
||||
} |
||||
|
||||
$n = $sign % 11; |
||||
$val_num = $arr_ch[$n]; |
||||
|
||||
if ($val_num != substr($id_card,17, 1)) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getGenderByIdCard')) |
||||
{ |
||||
/** |
||||
* 根据 身份证 / 2023 外国人永居证 获取性别 |
||||
* @param string $id_card_no |
||||
* @return int |
||||
*/ |
||||
function getGenderByIdCard(string $id_card_no): int |
||||
{ |
||||
if (strlen($id_card_no) == 18) { |
||||
//18位身份证 第17位 奇男 偶女 |
||||
$number = substr($id_card_no, -2, 1); |
||||
} else { |
||||
//15位身份证 第15位 奇男 偶女 |
||||
$number = substr($id_card_no, -1, 1); |
||||
} |
||||
|
||||
//求余 |
||||
if (intval($number) % 2 !== 0) { |
||||
return 1; |
||||
} else { |
||||
return 2; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('validate2017ForeignersIDCard')) { |
||||
/** |
||||
* 2017 版外国人永居证号码校验 |
||||
* @param string $id_card |
||||
* @return bool |
||||
*/ |
||||
function validate2017ForeignersIDCard(string $id_card): bool |
||||
{ |
||||
//检查15位 |
||||
if (15 !== strlen($id_card)) { |
||||
return false; |
||||
} |
||||
|
||||
// 2017 版外国人永居证 前 3 位是大写字母 后 12 位是数字 |
||||
if (!preg_match( "/^[A-Z]{3}[0-9]{12}$/", $id_card)) { |
||||
return false; |
||||
} |
||||
|
||||
// 除最后一位外都为计算位数 |
||||
$length = 15 - 1; |
||||
// 本体码 |
||||
$local = []; |
||||
// 乘积 |
||||
$product = []; |
||||
// 731 算法,加权因子 |
||||
$widths = [7, 3, 1, 7, 3, 1, 7, 3, 1, 7, 3, 1, 7, 3]; |
||||
|
||||
for ($i = $length; $i > 0; $i--) { |
||||
// 前三位为大写字母,映射为10-35的十进制数字 |
||||
if ($i > $length - 3) { |
||||
$local[$length - $i] = mapLetterToNumber($id_card[$length - $i]); |
||||
} else { |
||||
$local[$length - $i] = intval($id_card[$length - $i]); |
||||
} |
||||
// 乘积 |
||||
$product[$length - $i] = $local[$length - $i] * $widths[$length - $i]; |
||||
} |
||||
// 乘积之和对10取模 |
||||
$modulus = array_sum($product) % 10; |
||||
// 最后一位为校验码 |
||||
$check_digit = (int) $id_card[$length]; |
||||
// 校验码与计算得到结果比对 |
||||
return $modulus == $check_digit; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('mapLetterToNumber')) { |
||||
/** |
||||
* 2017 版外国人永居证 证件前三位拉丁字母映射为 10-35的十进制数字 |
||||
* @param string $letter 单个拉丁字母 |
||||
* @return int 数字 |
||||
*/ |
||||
function mapLetterToNumber(string $letter): int |
||||
{ |
||||
return ord($letter) - ord('A') + 10; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getIDCardType')) { |
||||
/** |
||||
* 判断身份证件类型 |
||||
* @param string $id_card |
||||
* @return int 0 其他, 1 身份证,2 港澳台社保卡号, 3 2017 外国人永居证,4 2023 外国人永居证 |
||||
*/ |
||||
function getIDCardType(string $id_card): int |
||||
{ |
||||
// 身份证 |
||||
$length = strlen($id_card); |
||||
if (($length === 18 || $length === 15) && (int) substr($id_card, 0, 1) !== 9 && validateIDCard($id_card)) { |
||||
return 1; |
||||
} |
||||
|
||||
// 港澳台 社保卡号 |
||||
if (preg_match("/^[HKG|MAC|TWN][0-9]{9}$/", $id_card)) { |
||||
return 2; |
||||
} |
||||
|
||||
// 2017 版外国人永居证 前 3 位是大写字母 后 12 位是数字 |
||||
if (preg_match("/^[A-Z]{3}[0-9]{12}$/", $id_card)) { |
||||
return 3; |
||||
} |
||||
|
||||
// 2023 版外国人永居证第一位是 9 |
||||
if ((int) substr($id_card, 0, 1) === 9) { |
||||
return 4; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getBirthdayByIdCard')) |
||||
{ |
||||
/** |
||||
* 根据 身份证 / 2023 外国人永居证 获取出生日期 |
||||
* @param string $id_card_no |
||||
* @param string $format_rule |
||||
* @return string |
||||
*/ |
||||
function getBirthdayByIdCard(string $id_card_no, string $format_rule = 'Y-m-d'): string |
||||
{ |
||||
if (strlen($id_card_no) == 18) { |
||||
//18位身份证 |
||||
//第7、8、9、10位为出生年份(四位数) |
||||
//第11、第12位为出生月份 |
||||
//第13、14位代表出生日期 |
||||
$year = substr($id_card_no, 6, 4); |
||||
$month = substr($id_card_no, 10, 2); |
||||
$day = substr($id_card_no, 12, 2); |
||||
|
||||
$birthday = $year. '-'. $month. '-'. $day; |
||||
} else { |
||||
//15位身份证 |
||||
//第7、8位为出生年份(两位数) |
||||
//第9、10位为出生月份 |
||||
//第11、12位代表出生日期 |
||||
$year = substr($id_card_no, 6, 2); |
||||
$month = substr($id_card_no, 8, 2); |
||||
$day = substr($id_card_no, 10, 2); |
||||
|
||||
$birthday = '19'. $year. '-'. $month. '-'. $day; |
||||
} |
||||
|
||||
return date($format_rule, strtotime($birthday)); |
||||
} |
||||
} |
||||
|
||||
|
||||
if (!function_exists('getBirthdayBy2017ForeignersIDCard')) |
||||
{ |
||||
/** |
||||
* 根据 2017 外国人永居证 获取出生日期 |
||||
* @param string $id_card_no |
||||
* @param string $format_rule |
||||
* @return string |
||||
*/ |
||||
function getBirthdayBy2017ForeignersIDCard(string $id_card_no, string $format_rule = 'Y-m-d'): string |
||||
{ |
||||
// 2017年外国人永居证 |
||||
// 第8、9位为出生年份(两位数) |
||||
// 第10、11位为出生月份 |
||||
// 第12、13位代表出生日期 |
||||
$year = substr($id_card_no, 7, 2); |
||||
$month = substr($id_card_no, 8, 2); |
||||
$day = substr($id_card_no, 11, 2); |
||||
|
||||
$birthday = '19'. $year. '-'. $month. '-'. $day; |
||||
|
||||
return date($format_rule, strtotime($birthday)); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('checkMobilePhone')) { |
||||
/** |
||||
* 检测手机号码 |
||||
* @param string $mobile_phone |
||||
* @return bool |
||||
*/ |
||||
function checkMobilePhone(string $mobile_phone): bool |
||||
{ |
||||
$mobile_phone = trim($mobile_phone); |
||||
$regex = "/^1(3|4|5|6|7|8|9)\d{9}$/"; |
||||
|
||||
if (!preg_match($regex, $mobile_phone)) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('checkFixedTelephone')) { |
||||
/** |
||||
* 检测固定电话 |
||||
* @param string $fixed_telephone |
||||
* @return bool |
||||
*/ |
||||
function checkFixedTelephone(string $fixed_telephone): bool |
||||
{ |
||||
$fixed_telephone = trim($fixed_telephone); |
||||
$regex = "/^(0[0-9]{2,3})?([2-9][0-9]{6,7})+([0-9]{1,4})?$/"; |
||||
|
||||
if (!preg_match($regex, $fixed_telephone)) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('checkDateFormat')) { |
||||
/** |
||||
* 检查日期格式 |
||||
* @param string $date_str |
||||
* @param string $rules |
||||
* @return bool |
||||
*/ |
||||
function checkDateFormat(string $date_str, string $rules = 'Y-m-d'): bool |
||||
{ |
||||
try { |
||||
return date($rules, strtotime($date_str)) == $date_str; |
||||
} catch (\Exception $e) { |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('xmlArrayToListByKey')) { |
||||
/** |
||||
* xml的array转成lists |
||||
* @param array $data |
||||
* @param string $key |
||||
* @return array |
||||
*/ |
||||
function xmlArrayToListByKey(array $data, string $key): array |
||||
{ |
||||
//判断是否存在0,1,2,3等键值数组 |
||||
if( |
||||
isset($data[$key]) && |
||||
(!isset($data[$key][0]) || reset($data[$key]) !== $data[$key][0]) |
||||
) { |
||||
$data[$key] = [$data[$key]]; |
||||
} |
||||
|
||||
return $data; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('objectToArray')) { |
||||
/** |
||||
* object to array |
||||
* @param object $data |
||||
* @return array |
||||
*/ |
||||
function objectToArray(object $data): array |
||||
{ |
||||
return json_decode(json_encode($data), true); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('recordLog')) { |
||||
/** |
||||
* 保存日志记录 |
||||
* @param string $module_name |
||||
* @param string $content |
||||
*/ |
||||
function recordLog(string $module_name, string $content): void |
||||
{ |
||||
date_default_timezone_set("Asia/Shanghai"); |
||||
|
||||
$file_path = app()->storagePath('logs'). DIRECTORY_SEPARATOR. $module_name. 'Log'. DIRECTORY_SEPARATOR. date('Ym'). DIRECTORY_SEPARATOR; |
||||
$file_name = date('d'). '.log'; |
||||
|
||||
!is_dir($file_path) && mkdir($file_path, 0755, true); |
||||
|
||||
$msg = '['. date('Y-m-d H:i:s'). ']'. PHP_EOL . $content . PHP_EOL . PHP_EOL; |
||||
|
||||
file_put_contents( $file_path. $file_name, $msg, FILE_APPEND); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getCustomConfig')) { |
||||
/** |
||||
* 获取自定义配置 |
||||
* @param string $name |
||||
* @param string $key |
||||
* @return mixed |
||||
*/ |
||||
function getCustomConfig(string $name, string $key): mixed |
||||
{ |
||||
$config = config('custom.'. $name); |
||||
return isset($config[$key]) ? $config[$key] : reset($config); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getMonthDateList')) { |
||||
/** |
||||
* 获取当月列表 |
||||
* @return array |
||||
*/ |
||||
function getMonthDateList(): array |
||||
{ |
||||
$lists = []; |
||||
$first_day = strtotime(date('Y-m-01')); |
||||
$i = 0; |
||||
$last_day = strtotime(date('Y-m-01'). ' +1 month'); |
||||
|
||||
while ($first_day + $i * 86400 < $last_day) { |
||||
$lists[] = date('Y-m-d', $first_day + $i * 86400); |
||||
$i++; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('arrayToXml')) { |
||||
/** |
||||
* 数组转xml |
||||
* @param array $data |
||||
* @return string |
||||
*/ |
||||
function arrayToXml(array $data): string |
||||
{ |
||||
$xml = ''; |
||||
foreach ($data as $key => $val) |
||||
{ |
||||
if (is_array($val)) { |
||||
$xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">"; |
||||
} else { |
||||
$xml .= "<" . $key . ">" . $val . "</" . $key . ">"; |
||||
} |
||||
} |
||||
|
||||
return $xml; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getHisPayTypeByCustomPayType')) { |
||||
/** |
||||
* 获取his支付类型 |
||||
* @param int $pay_type 自定义支付类型 |
||||
* @param bool $is_staff 是否为职工挂号 |
||||
* @return int |
||||
*/ |
||||
function getHisPayTypeByCustomPayType(int $pay_type, bool $is_staff): int |
||||
{ |
||||
return !$is_staff ? (config('custom.pay_type_to_his')[$pay_type] ?? 0) : 4; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getHisPayOrderNoByHisPayType')) { |
||||
/** |
||||
* 获取his支付类型 |
||||
* @param int $his_pay_type his支付类型 |
||||
* @param array $pay_res_data 是否为职工挂号 |
||||
* @return string |
||||
*/ |
||||
function getHisPayOrderNoByHisPayType(int $his_pay_type, array $pay_res_data): string |
||||
{ |
||||
switch ($his_pay_type) { |
||||
case 0: |
||||
case 1: |
||||
if (isset($pay_res_data['orderNo'], $pay_res_data['merchantId'])) { |
||||
// 数字人民币 |
||||
$order_no = $pay_res_data['orderNo']; |
||||
} else { |
||||
// 正常银联支付 |
||||
$order_no = $pay_res_data['retCardNo'] ?? '';// UnMoney.Str2 / retCardNo |
||||
} |
||||
break; |
||||
case 2: |
||||
case 3: |
||||
default: |
||||
$order_no = $pay_res_data['out_trade_no'] ?? ''; |
||||
break; |
||||
case 5: |
||||
if (isset($pay_res_data['hospitalSerialNo']) && strlen($pay_res_data['hospitalSerialNo']) === 20) { |
||||
// 挂号信用付 |
||||
$order_no = $pay_res_data['hospitalSerialNo']; |
||||
} else { |
||||
// 住院信用付 |
||||
$order_no = ''; |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return $order_no; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('routeResource')) { |
||||
/** |
||||
* 设置资源路由 |
||||
* @param Route $router 路由handle |
||||
* @param string $uri 路由名称 |
||||
* @param string $controller 控制器名称 |
||||
* @param array $allow 允许的方法 |
||||
* @return void |
||||
*/ |
||||
function routeResource(Route &$router, string $uri, string $controller, array $allow = ['index', 'store', 'show', 'update', 'destory']): void |
||||
{ |
||||
if (in_array('index', $allow)) { |
||||
$router->get($uri, $controller. '@index'); |
||||
} |
||||
|
||||
if (in_array('store', $allow)) { |
||||
$router->post($uri, $controller. '@store'); |
||||
} |
||||
|
||||
if (in_array('show', $allow)) { |
||||
$router->get($uri.'/{id:[0-9]+}', $controller. '@show'); |
||||
} |
||||
|
||||
if (in_array('update', $allow)) { |
||||
$router->put($uri.'/{id:[0-9]+}', $controller. '@update'); |
||||
$router->patch($uri.'/{id:[0-9]+}', $controller. '@update'); |
||||
} |
||||
|
||||
if (in_array('destory', $allow)) { |
||||
$router->delete($uri . '/{id:[0-9]+}', $controller . '@destroy'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getUrlQueryParams')) { |
||||
/** |
||||
* 获取url参数数组 |
||||
* @param string $url |
||||
* @return array |
||||
*/ |
||||
function getUrlQueryParams(string $url): array |
||||
{ |
||||
$query_param_str = parse_url($url, PHP_URL_QUERY); |
||||
if (empty($query_param_str)) { |
||||
return []; |
||||
} |
||||
|
||||
$params_arr = explode('&', $query_param_str); |
||||
|
||||
$params = []; |
||||
foreach ($params_arr as $k => $v) { |
||||
$arr = explode('=', $v); |
||||
$params[$arr[0]] = $arr[1]; |
||||
} |
||||
|
||||
return $params; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getCsvFileContent')) { |
||||
/** |
||||
* 读取csv文件 |
||||
* @param string $file_path 文件路径 |
||||
* @param int $ignore_head_line 忽略头部行数 |
||||
* @param int $ignore_foot_line 忽略脚部行数 |
||||
* @return array |
||||
*/ |
||||
function getCsvFileContent(string $file_path, int $ignore_head_line = 0, int $ignore_foot_line = 0): array |
||||
{ |
||||
if (!file_exists($file_path)) { |
||||
return [false, '文件不存在']; |
||||
} |
||||
|
||||
$i = 0; |
||||
$data = []; |
||||
$handle = fopen($file_path, 'r'); |
||||
while (($content = fgetcsv($handle)) !== false) { |
||||
// 忽略头部行数 |
||||
if ($i < $ignore_head_line) { |
||||
$i++; |
||||
continue; |
||||
} |
||||
|
||||
$i++; |
||||
$data[] = $content; |
||||
} |
||||
|
||||
// 忽略尾部行数 |
||||
if ($ignore_foot_line > 0) { |
||||
$data = array_chunk($data, $i - $ignore_foot_line - $ignore_head_line); |
||||
if (!is_array($data)) { |
||||
return [true, []]; |
||||
} |
||||
|
||||
$data = $data[0]; |
||||
} |
||||
|
||||
return [true, $data]; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getFormatDateTimeStr')) { |
||||
/** |
||||
* 获取当前格式化后的时间字符串 |
||||
* @param string $format 格式化后的字符串 |
||||
* @param int $pow_num 保留几位秒数 |
||||
* @return string |
||||
*/ |
||||
function getFormatDateTimeStr(string $format = 'Y-m-d H:i:s', int $pow_num = 6): string |
||||
{ |
||||
date_default_timezone_set('Asia/Shanghai'); |
||||
// 带微秒的时间戳 |
||||
$u_timestamp = sprintf("%.6f", microtime(true)); |
||||
|
||||
$timestamp = floor($u_timestamp); |
||||
$microseconds = round(($u_timestamp - $timestamp) * pow(10, $pow_num)); |
||||
|
||||
return date($format, $timestamp) . $microseconds; |
||||
} |
||||
} |
||||
|
||||
if (!file_exists('getPaymentOutTradeOrderId')) { |
||||
/** |
||||
* 根据支付类型返回支付平台订单ID |
||||
* @param int $pay_type 支付类型 |
||||
* @param array $pay_result 支付返回 |
||||
* @return mixed|string |
||||
*/ |
||||
function getPaymentOutTradeOrderId(int $pay_type, array $pay_result): mixed |
||||
{ |
||||
switch ($pay_type) { |
||||
case 2: |
||||
case 5: |
||||
case 9: |
||||
$out_trade_id = $pay_result['retFlowWaterNo'] ?? ''; |
||||
break; |
||||
case 3: |
||||
case 6: |
||||
// 查找顺序 微信支付 -> HIS支付平台 |
||||
$out_trade_id = $pay_result['transaction_id'] ?? ($pay_result['platform_order_no'] ?? ''); |
||||
break; |
||||
case 4: |
||||
case 7: |
||||
// 查找顺序 支付宝支付 -> HIS支付平台 |
||||
$out_trade_id = $pay_result['trade_no'] ?? ($pay_result['platform_order_no'] ?? ''); |
||||
break; |
||||
case 10: |
||||
case 11: |
||||
$out_trade_id = $pay_result['orderNo'] ?? ''; |
||||
break; |
||||
case 12: |
||||
$out_trade_id = $pay_result['transNo'] ?? ''; |
||||
break; |
||||
default: |
||||
$out_trade_id = ''; |
||||
break; |
||||
} |
||||
|
||||
return $out_trade_id; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getArrayByKeyList')) { |
||||
/** |
||||
* 根据键值列表获取数据 |
||||
* @param array $array 原数据 |
||||
* @param array $list 需要取得键值数组 |
||||
* @return array |
||||
*/ |
||||
function getArrayByKeyList(array $array, array $list): array |
||||
{ |
||||
if (empty($array) || empty($list)) { |
||||
return []; |
||||
} |
||||
|
||||
$n_array = []; |
||||
foreach ($list as $k => $v) { |
||||
$n_array[$v] = $array[$v] ?? ''; |
||||
} |
||||
|
||||
return $n_array; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getArrayColumnListsByKey')) { |
||||
/** |
||||
* 根据键值获取数组列的列表 |
||||
* @param $array |
||||
* @param $key |
||||
* @return array |
||||
*/ |
||||
function getArrayColumnListsByKey($array, $key): array |
||||
{ |
||||
if (empty($array)) { |
||||
return []; |
||||
} |
||||
|
||||
$lists = []; |
||||
foreach ($array as $k => $v) { |
||||
if (!isset($v[$key])) { |
||||
continue; |
||||
} |
||||
|
||||
$lists[$v[$key]] = $v; |
||||
} |
||||
|
||||
return $lists; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getElectronHealthConfig')) { |
||||
/** |
||||
* 获取电子健康卡配置 |
||||
* @param string $name |
||||
* @param string $key |
||||
* @return mixed |
||||
*/ |
||||
function getElectronHealthConfig(string $name, string $key): mixed |
||||
{ |
||||
$config = config('health.'. $name); |
||||
return isset($config[$key]) ? $config[$key] : reset($config); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('generateTree')) { |
||||
/** |
||||
* 分类树 |
||||
* @param array $array 分类数据 |
||||
* @param string $s_key 子类IDkey名称 |
||||
* @param string $p_key 父类IDkey名称 |
||||
* @param string $item_key 子类存储key名称 |
||||
* @return array |
||||
*/ |
||||
function generateTree(array $array, string $s_key, string $p_key, string $item_key): array |
||||
{ |
||||
$items = []; |
||||
foreach($array as $v){ |
||||
$items[$v[$s_key]] = $v; |
||||
} |
||||
|
||||
$tree = []; |
||||
foreach($items as $k => $v){ |
||||
if(isset($items[$v[$p_key]])){ |
||||
$items[$v[$p_key]][$item_key][] = &$items[$k]; |
||||
}else{ |
||||
$tree[] = &$items[$k]; |
||||
} |
||||
} |
||||
return $tree; |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('getWeChatMiniProgramApp')) { |
||||
/** |
||||
* 获取小程序app示例 |
||||
* @return Application |
||||
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException |
||||
*/ |
||||
function getWeChatMiniProgramApp(): Application |
||||
{ |
||||
return new Application(config('wechat.mini')); |
||||
} |
||||
} |
||||
|
||||
if (!function_exists('replaceSpecialChar')) { |
||||
/** |
||||
* 过滤特殊字符 |
||||
* @param string $string |
||||
* @return array|string|string[]|null |
||||
*/ |
||||
function replaceSpecialChar(string $string): array|string|null |
||||
{ |
||||
$regex = "-[/~!@#$%^&*()_+{}:<>?\[\],.;`'\-=|]-"; |
||||
return preg_replace($regex, '', $string); |
||||
} |
||||
} |
@ -0,0 +1,76 @@ |
||||
<?php |
||||
|
||||
namespace App\Utils; |
||||
|
||||
use GuzzleHttp\Client; |
||||
use GuzzleHttp\Exception\GuzzleException; |
||||
use GuzzleHttp\Exception\RequestException; |
||||
|
||||
trait ProxyHelpers |
||||
{ |
||||
/** |
||||
* 获取token |
||||
* @param string $username |
||||
* @param string $password |
||||
* @param string $module 模块 |
||||
* @param string $config 配置 |
||||
* @param string $guard 登陆用户组 |
||||
* @return boolean|mixed |
||||
* @throws GuzzleException |
||||
*/ |
||||
public function authenticate(string $username, string $password, string $module, string $config, string $guard = ''): mixed |
||||
{ |
||||
$client = new Client(); |
||||
|
||||
try { |
||||
$url = request()->root() . '/'. $module. '/oauth/token'; |
||||
|
||||
$params = array_merge(config('passport.'. $config), [ |
||||
'username' => $username, |
||||
'password' => $password, |
||||
'provider' => $guard |
||||
]); |
||||
|
||||
$respond = $client->post($url, ['form_params' => $params]); |
||||
|
||||
} catch (RequestException $exception) { |
||||
return false; |
||||
} |
||||
|
||||
if ($respond->getStatusCode() === 401) { |
||||
return false; |
||||
} |
||||
|
||||
return json_decode($respond->getBody()->getContents(), true); |
||||
} |
||||
|
||||
/** |
||||
* 获取刷新token |
||||
* @param string $module 模块 |
||||
* @param string $config 配置 |
||||
* @return boolean|mixed |
||||
* @throws GuzzleException |
||||
*/ |
||||
public function getRefreshToken(string $module, string $config): mixed |
||||
{ |
||||
$client = new Client(); |
||||
|
||||
try { |
||||
$url = request()->root() . '/'. $module. '/oauth/token'; |
||||
|
||||
$params = array_merge(config('passport.'. $config), [ |
||||
'refresh_token' => request('refresh_token'), |
||||
]); |
||||
|
||||
$response = $client->post($url, ['form_params' => $params]); |
||||
} catch (RequestException $exception) { |
||||
return false; |
||||
} |
||||
|
||||
if ($response->getStatusCode() === 401) { |
||||
return false; |
||||
} |
||||
|
||||
return json_decode($response->getBody()->getContents(), true); |
||||
} |
||||
} |
@ -0,0 +1,266 @@ |
||||
<?php |
||||
/** |
||||
* @author Tinywan(ShaoBo Wan) |
||||
* https://github.com/Tinywan/PHP-JAVA-SM4/blob/main/SM4.php |
||||
*/ |
||||
|
||||
namespace App\Utils; |
||||
|
||||
use \Exception; |
||||
|
||||
class SM4 |
||||
{ |
||||
public const SM4_CK = [ |
||||
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, |
||||
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, |
||||
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, |
||||
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, |
||||
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, |
||||
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, |
||||
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, |
||||
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 |
||||
]; |
||||
|
||||
public const SM4_Sbox = [ |
||||
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, |
||||
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, |
||||
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, |
||||
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, |
||||
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, |
||||
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, |
||||
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, |
||||
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, |
||||
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, |
||||
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, |
||||
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, |
||||
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, |
||||
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, |
||||
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, |
||||
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, |
||||
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48 |
||||
]; |
||||
|
||||
/** |
||||
* 系统参数 |
||||
*/ |
||||
public const SM4_FK = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC]; |
||||
|
||||
private $key = []; //16个 HEXHEX格式的数组 16字节 128bits 为了操作方便,直接存成十进制 |
||||
|
||||
private $skey = []; //记录每轮加密的秘钥 记录成十进制 |
||||
|
||||
private $block_size = 32; |
||||
|
||||
/** |
||||
* SM4 constructor. |
||||
* @param $key 32个十六进制的字符 |
||||
* @throws Exception |
||||
*/ |
||||
public function __construct($key) |
||||
{ |
||||
$this->key = $this->preProcess($key); |
||||
$this->setSkey(); |
||||
} |
||||
|
||||
/** |
||||
* 计算每轮加密需要的秘钥 |
||||
*/ |
||||
private function setSkey(): void |
||||
{ |
||||
$skey = []; |
||||
for ($i = 0; $i < 4; $i++) { |
||||
$skey[] = self::SM4_FK[$i] ^ ($this->key[4 * $i] << 24 | $this->key[4 * $i + 1] << 16 | $this->key[4 * $i + 2] << 8 | $this->key[4 * $i + 3]); |
||||
} |
||||
for ($k = 0; $k < 32; $k++) { |
||||
$tmp = $skey[$k + 1] ^ $skey[$k + 2] ^ $skey[$k + 3] ^ self::SM4_CK[$k]; |
||||
|
||||
//非线性化操作 |
||||
$buf = (self::SM4_Sbox[($tmp >> 24) & 0xff]) << 24 | |
||||
(self::SM4_Sbox[($tmp >> 16) & 0xff]) << 16 | |
||||
(self::SM4_Sbox[($tmp >> 8) & 0xff]) << 8 | |
||||
(self::SM4_Sbox[$tmp & 0xff]); |
||||
//线性化操作 |
||||
$skey[] = $skey[$k] ^ ($buf ^ $this->sm4Rotl32($buf, 13) ^ $this->sm4Rotl32($buf, 23)); |
||||
$this->skey[] = $skey[$k + 4]; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 32比特的buffer中循环左移n位 |
||||
* @param $buf int 可以传递进10进制 也可以是0b开头的二进制 |
||||
* @param $n int 向左偏移n位 |
||||
* @return int |
||||
* reference http://blog.csdn.net/w845695652/article/details/6522285 |
||||
*/ |
||||
private function sm4Rotl32(int $buf, int $n): int |
||||
{ |
||||
return (($buf << $n) & 0xffffffff) | ($buf >> (32 - $n)); |
||||
} |
||||
|
||||
/** |
||||
* 对字符串加密 |
||||
* @param string $plain_text |
||||
* @return string |
||||
* @throws Exception |
||||
*/ |
||||
public function encrypt(string $plain_text): string |
||||
{ |
||||
$bytes = bin2hex($plain_text); |
||||
$need_pad_length = $this->block_size - strlen($bytes) % $this->block_size; |
||||
$pad_bytes = str_pad( |
||||
$bytes, |
||||
strlen($bytes) + $need_pad_length, |
||||
sprintf("%02x", $need_pad_length / 2), |
||||
STR_PAD_RIGHT |
||||
); |
||||
$chunks = str_split($pad_bytes, $this->block_size); |
||||
|
||||
return strtolower(implode('', array_map(function ($chunk) { |
||||
return $this->encryptBinary($chunk); |
||||
}, $chunks))); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* SM4加密单个片段(128bit) |
||||
* @param $text string 32个十六进制字符串 |
||||
* @return string |
||||
* @throws Exception |
||||
*/ |
||||
private function encryptBinary(string $text): string |
||||
{ |
||||
$x = $re = []; |
||||
$t = $this->preProcess($text); |
||||
for ($i = 0; $i < 4; $i++) { |
||||
$x[] = $t[$i * 4] << 24 | |
||||
$t[$i * 4 + 1] << 16 | |
||||
$t[$i * 4 + 2] << 8 | |
||||
$t[$i * 4 + 3]; |
||||
} |
||||
|
||||
for ($k = 0; $k < 32; $k++) { |
||||
$tmp = $x[$k + 1] ^ $x[$k + 2] ^ $x[$k + 3] ^ $this->skey[$k]; |
||||
|
||||
$buf = self::SM4_Sbox[($tmp >> 24) & 0xff] << 24 | |
||||
self::SM4_Sbox[($tmp >> 16) & 0xff] << 16 | |
||||
self::SM4_Sbox[($tmp >> 8) & 0xff] << 8 | |
||||
self::SM4_Sbox[$tmp & 0xff]; |
||||
|
||||
$x[$k + 4] = $x[$k] ^ $buf |
||||
^ $this->sm4Rotl32($buf, 2) |
||||
^ $this->sm4Rotl32($buf, 10) |
||||
^ $this->sm4Rotl32($buf, 18) |
||||
^ $this->sm4Rotl32($buf, 24); |
||||
} |
||||
for ($i = 0; $i < 4; $i++) { |
||||
$re[] = ($x[35 - $i] >> 24) & 0xff; |
||||
$re[] = ($x[35 - $i] >> 16) & 0xff; |
||||
$re[] = ($x[35 - $i] >> 8) & 0xff; |
||||
$re[] = $x[35 - $i] & 0xff; |
||||
} |
||||
return $this->wrapResult($re); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 预处理16字节长度的16进制字符串 返回10进制的数组 数组大小为16 |
||||
* @param string $text |
||||
* @return array |
||||
* @throws Exception |
||||
*/ |
||||
private function preProcess(string $text): array |
||||
{ |
||||
preg_match('/[0-9a-f]{32}/', strtolower($text), $re); |
||||
if (empty($re)) { |
||||
throw new Exception('error input format!'); |
||||
} |
||||
$key = $re[0]; |
||||
for ($i = 0; $i < 16; $i++) { |
||||
$result[] = hexdec($key[2 * $i] . $key[2 * $i + 1]); |
||||
} |
||||
|
||||
return $result; |
||||
} |
||||
|
||||
/** |
||||
* 将十进制结果包装成16进制字符串输出 |
||||
* @param array $result |
||||
* @return string |
||||
*/ |
||||
private function wrapResult(array $result): string |
||||
{ |
||||
$hex_str = ''; |
||||
foreach ($result as $v) { |
||||
$tmp = dechex($v); |
||||
$len = strlen($tmp); |
||||
if ($len == 1) //不足两位十六进制的数 在前面补一个0,保证输出也是32个16进制字符 |
||||
{ |
||||
$hex_str .= '0'; |
||||
} |
||||
$hex_str .= $tmp; |
||||
} |
||||
return strtoupper($hex_str); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* SM4解密单个片段(128bits) |
||||
* @param string $text 32个16进制字符串 |
||||
* @return string |
||||
* @throws Exception |
||||
*/ |
||||
private function decrypt_decrypt(string $text): string |
||||
{ |
||||
$x = $re = []; |
||||
$t = $this->preProcess($text); |
||||
for ($i = 0; $i < 4; $i++) { |
||||
$x[] = $t[4 * $i] << 24 | |
||||
$t[4 * $i + 1] << 16 | |
||||
$t[4 * $i + 2] << 8 | |
||||
$t[4 * $i + 3]; |
||||
} |
||||
for ($k = 0; $k < 32; $k++) { |
||||
$tmp = $x[$k + 1] ^ $x[$k + 2] ^ $x[$k + 3] ^ $this->skey[31 - $k]; |
||||
$buf = (self::SM4_Sbox[($tmp >> 24) & 0xff]) << 24 | |
||||
(self::SM4_Sbox[($tmp >> 16) & 0xff]) << 16 | |
||||
(self::SM4_Sbox[($tmp >> 8) & 0xff]) << 8 | |
||||
(self::SM4_Sbox[$tmp & 0xff]); |
||||
$x[$k + 4] = $x[$k] ^ $buf |
||||
^ $this->sm4Rotl32($buf, 2) |
||||
^ $this->sm4Rotl32($buf, 10) |
||||
^ $this->sm4Rotl32($buf, 18) |
||||
^ $this->sm4Rotl32($buf, 24); |
||||
} |
||||
|
||||
for ($i = 0; $i < 4; $i++) { |
||||
$re[] = ($x[35 - $i] >> 24) & 0xff; |
||||
$re[] = ($x[35 - $i] >> 16) & 0xff; |
||||
$re[] = ($x[35 - $i] >> 8) & 0xff; |
||||
$re[] = $x[35 - $i] & 0xff; |
||||
} |
||||
return $this->wrapResult($re); |
||||
} |
||||
|
||||
/** |
||||
* 字符串解密 |
||||
* @param string $cipher_text |
||||
* @return string |
||||
* @throws Exception |
||||
*/ |
||||
public function decrypt(string $cipher_text): string |
||||
{ |
||||
$chunks = str_split($cipher_text, $this->block_size); |
||||
$decrypt_text_data = implode('', array_map(function ($chunk) { |
||||
return $this->decrypt_decrypt($chunk); |
||||
}, $chunks)); |
||||
|
||||
$pad_length = hexdec(substr($decrypt_text_data, -2)); |
||||
|
||||
return hex2bin(preg_replace( |
||||
sprintf("/%s$/", str_repeat(sprintf("%02x", $pad_length), $pad_length)), |
||||
'', |
||||
$decrypt_text_data |
||||
)); |
||||
} |
||||
} |
@ -0,0 +1,265 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Traits; |
||||
|
||||
use GuzzleHttp\Client; |
||||
use GuzzleHttp\Handler\MockHandler; |
||||
use GuzzleHttp\HandlerStack; |
||||
use GuzzleHttp\Psr7\Response; |
||||
use InvalidArgumentException; |
||||
use JsonException; |
||||
use Psr\Http\Message\ResponseInterface; |
||||
|
||||
trait HttpRequest |
||||
{ |
||||
/** |
||||
* Http client. |
||||
* |
||||
* @var Client|null |
||||
*/ |
||||
protected ?Client $httpClient = null; |
||||
|
||||
/** |
||||
* Mock handler. |
||||
* |
||||
* @var MockHandler|null |
||||
*/ |
||||
protected ?MockHandler $mockHandler = null; |
||||
|
||||
/** |
||||
* Http header |
||||
* |
||||
* @var array<string, string> |
||||
*/ |
||||
private array $httpHeader = []; |
||||
|
||||
/** |
||||
* Http client options. |
||||
* |
||||
* @var array<string, mixed> |
||||
*/ |
||||
protected array $httpOptions = [ |
||||
'base_uri' => '', |
||||
'timeout' => 0, |
||||
'connect_timeout' => 0, |
||||
]; |
||||
|
||||
/** |
||||
* Send a GET request. |
||||
* |
||||
* @param string $endpoint 请求路由 |
||||
* @param array<string, mixed> $query GET参数 |
||||
* @param array<string, mixed> $headers 请求header头 |
||||
* |
||||
* @return mixed |
||||
* |
||||
* @throws JsonException |
||||
*/ |
||||
public function get(string $endpoint, array $query = [], array $headers = []): mixed |
||||
{ |
||||
return $this->request('GET', $endpoint, [ |
||||
'headers' => $headers, |
||||
'query' => $query, |
||||
]); |
||||
} |
||||
|
||||
/** |
||||
* Send a POST request. |
||||
* |
||||
* @param string $endpoint 请求路由 |
||||
* @param string|array<string, mixed> $data 请求数据 |
||||
* @param array<string, mixed> $options options选项 |
||||
* |
||||
* @return mixed |
||||
* @throws JsonException |
||||
*/ |
||||
public function post(string $endpoint, string|array $data, array $options = []): mixed |
||||
{ |
||||
if (!is_array($data)) { |
||||
$options['body'] = $data; |
||||
} else { |
||||
$options['form_params'] = $data; |
||||
} |
||||
|
||||
return $this->request('POST', $endpoint, $options); |
||||
} |
||||
|
||||
/** |
||||
* Send request. |
||||
* |
||||
* @param string $method 请求方法 |
||||
* @param string $endpoint 请求路由 |
||||
* @param array<string, mixed> $options options选项 |
||||
* |
||||
* @return mixed |
||||
* |
||||
* @throws JsonException |
||||
*/ |
||||
public function request(string $method, string $endpoint, array $options = []): mixed |
||||
{ |
||||
return $this->unwrapResponse($this->getHttpClient()->{$method}($endpoint, $options)); |
||||
} |
||||
|
||||
/** |
||||
* Convert response. |
||||
* |
||||
* @param ResponseInterface $response 返回的response对象 |
||||
* |
||||
* @return mixed |
||||
* |
||||
* @throws JsonException |
||||
*/ |
||||
public function unwrapResponse(ResponseInterface $response): mixed |
||||
{ |
||||
$contentType = $response->getHeaderLine('Content-Type'); |
||||
$contents = $response->getBody()->getContents(); |
||||
|
||||
if (false !== stripos($contentType, 'json') || stripos($contentType, 'javascript')) { |
||||
return json_decode($contents, true, 512, JSON_THROW_ON_ERROR); |
||||
} |
||||
|
||||
if (false !== stripos($contentType, 'xml')) { |
||||
return json_decode( |
||||
json_encode( |
||||
simplexml_load_string($contents, 'SimpleXMLElement', LIBXML_NOCDATA), |
||||
JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE |
||||
), |
||||
true, |
||||
512, |
||||
JSON_THROW_ON_ERROR |
||||
); |
||||
} |
||||
|
||||
return $contents; |
||||
} |
||||
|
||||
/** |
||||
* Set http client. |
||||
* |
||||
* @param Client $client client请求客户端 |
||||
* |
||||
* @return self |
||||
*/ |
||||
public function setHttpClient(Client $client): self |
||||
{ |
||||
$this->httpClient = $client; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Get http client. |
||||
* |
||||
* @return Client |
||||
*/ |
||||
public function getHttpClient(): Client |
||||
{ |
||||
if (is_null($this->httpClient)) { |
||||
$this->httpClient = $this->getDefaultHttpClient(); |
||||
} |
||||
|
||||
return $this->httpClient; |
||||
} |
||||
|
||||
/** |
||||
* Get default http client. |
||||
* |
||||
* @return Client |
||||
*/ |
||||
public function getDefaultHttpClient(): Client |
||||
{ |
||||
return new Client($this->getOptions()); |
||||
} |
||||
|
||||
/** |
||||
* set mock Handler |
||||
* |
||||
* @param array<int, Response> $mock |
||||
* |
||||
* @return self |
||||
*/ |
||||
public function setMockHandler(array $mock): self |
||||
{ |
||||
array_walk($mock, static function ($value) { |
||||
if (!is_subclass_of($value, ResponseInterface::class)) { |
||||
throw new InvalidArgumentException( |
||||
$value::class . ' must be an instance of ' . ResponseInterface::class |
||||
); |
||||
} |
||||
}); |
||||
|
||||
$this->mockHandler = new MockHandler($mock); |
||||
$handlerStack = HandlerStack::create($this->mockHandler); |
||||
$this->setHttpOptions(['handler' => $handlerStack]); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Get mock handler |
||||
* |
||||
* @return MockHandler|null |
||||
*/ |
||||
public function getMockHandler(): ?MockHandler |
||||
{ |
||||
return $this->mockHandler; |
||||
} |
||||
|
||||
/** |
||||
* Get default options. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function getOptions(): array |
||||
{ |
||||
return $this->getHttpOptions(); |
||||
} |
||||
|
||||
/** |
||||
* Set http header. |
||||
* |
||||
* @param array<string, string> $httpHeader |
||||
* |
||||
* @return self |
||||
*/ |
||||
public function setHttpHeader(array $httpHeader): self |
||||
{ |
||||
$this->httpHeader = array_merge($httpHeader, $this->httpHeader); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* Get http header. |
||||
* |
||||
* @return array<string, string> |
||||
*/ |
||||
public function getHttpHeader(): array |
||||
{ |
||||
return $this->httpHeader; |
||||
} |
||||
|
||||
/** |
||||
* Set http options. |
||||
* |
||||
* @param array<string, HandlerStack|string> $httpOptions |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function setHttpOptions(array $httpOptions): void |
||||
{ |
||||
$this->httpOptions = array_merge($this->httpOptions, $httpOptions); |
||||
} |
||||
|
||||
/** |
||||
* Get http options. |
||||
* |
||||
* @return array<string, mixed> |
||||
*/ |
||||
public function getHttpOptions(): array |
||||
{ |
||||
return $this->httpOptions; |
||||
} |
||||
} |
@ -0,0 +1,114 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Traits; |
||||
|
||||
use Illuminate\Support\Facades\Log; |
||||
use Monolog\Level; |
||||
use Psr\Log\LoggerInterface; |
||||
|
||||
trait Logger |
||||
{ |
||||
|
||||
/** |
||||
* Logger channel name. |
||||
* |
||||
* @var string |
||||
*/ |
||||
public string $channel = 'default'; |
||||
|
||||
/** |
||||
* Logger 实例 |
||||
* |
||||
* @var LoggerInterface|null |
||||
*/ |
||||
public LoggerInterface|null $logger = NULL; |
||||
|
||||
/** |
||||
* UUID |
||||
* @var string |
||||
*/ |
||||
protected string $uuid = ''; |
||||
|
||||
/** |
||||
* Get Logger |
||||
* |
||||
* @return LoggerInterface |
||||
*/ |
||||
public function getLogger(): LoggerInterface |
||||
{ |
||||
if (is_null($this->logger)) { |
||||
$this->logger = $this->createLogger(); |
||||
$this->uuid = $this->uuid(); |
||||
} |
||||
|
||||
return $this->logger; |
||||
} |
||||
|
||||
/** |
||||
* Create Logger. |
||||
* |
||||
* @return LoggerInterface |
||||
*/ |
||||
public function createLogger(): LoggerInterface |
||||
{ |
||||
return Log::channel($this->channel); |
||||
} |
||||
|
||||
/** |
||||
* Set Channel. |
||||
* |
||||
* @param string $channel |
||||
* |
||||
* @return void |
||||
*/ |
||||
public function setChannel(string $channel): void |
||||
{ |
||||
$this->channel = $channel; |
||||
} |
||||
|
||||
/** |
||||
* Create uuid |
||||
* @return string |
||||
*/ |
||||
protected function uuid(): string |
||||
{ |
||||
$chars = md5(uniqid((string)mt_rand(), true)); |
||||
return substr ( $chars, 0, 8 ) . '-' |
||||
. substr ( $chars, 8, 4 ) . '-' |
||||
. substr ( $chars, 12, 4 ) . '-' |
||||
. substr ( $chars, 16, 4 ) . '-' |
||||
. substr ( $chars, 20, 12 ); |
||||
} |
||||
|
||||
public function debug(string $message, array $context = []): void |
||||
{ |
||||
$this->getLogger()->debug('['. $this->uuid. ']'.$message, $context); |
||||
} |
||||
|
||||
|
||||
public function info(string $message, array $context = []): void |
||||
{ |
||||
$this->getLogger()->info('['. $this->uuid. ']'.$message, $context); |
||||
} |
||||
|
||||
|
||||
public function notice(string $message, array $context = []): void |
||||
{ |
||||
$this->getLogger()->notice('['. $this->uuid. ']'.$message, $context); |
||||
} |
||||
|
||||
|
||||
public function warning(string $message, array $context = []): void |
||||
{ |
||||
$this->getLogger()->warning('['. $this->uuid. ']'.$message, $context); |
||||
} |
||||
|
||||
|
||||
public function error(string $message, array $context = []): void |
||||
{ |
||||
$this->getLogger()->error('['. $this->uuid. ']'.$message, $context); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,36 @@ |
||||
<?php |
||||
|
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Utils\Traits; |
||||
|
||||
use Illuminate\Auth\AuthenticationException; |
||||
use Illuminate\Support\Facades\Redis; |
||||
|
||||
trait MiniProgramAuth |
||||
{ |
||||
public string $open_id; |
||||
|
||||
public string $union_id; |
||||
|
||||
public string $session_key; |
||||
|
||||
/** |
||||
* MiniProgramAuth initialize |
||||
* @throws AuthenticationException |
||||
*/ |
||||
public function authInitialize(): void |
||||
{ |
||||
$token = request()->header('authorization'); |
||||
$info = Redis::get(substr($token, 7)); |
||||
|
||||
if(empty($info)) { |
||||
throw new AuthenticationException('Unauthenticated.'); |
||||
} |
||||
|
||||
$info = json_decode($info, true); |
||||
$this->open_id = $info['open_id'] ?? ''; |
||||
$this->union_id = $info['union_id'] ?? ''; |
||||
$this->session_key = $info['session_key'] ?? ''; |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
<?php |
||||
declare(strict_types = 1); |
||||
|
||||
namespace App\Utils\Traits; |
||||
|
||||
use RedisException; |
||||
|
||||
trait RedisLockUtil |
||||
{ |
||||
|
||||
/** |
||||
* 加锁 |
||||
* @param string $lock_str 锁字符串 |
||||
* @param int $expire_time 超时时间,默认300秒 |
||||
* @return false|string |
||||
* @throws RedisException |
||||
*/ |
||||
public function addLock(string $lock_str, int $expire_time = 300): bool|string |
||||
{ |
||||
$redis = app('redis'); |
||||
|
||||
$unique_id = $this->getUniqueLockId(); |
||||
$result = $redis->set($lock_str, $unique_id, 'ex', $expire_time, 'nx'); |
||||
|
||||
return $result ? $unique_id : false; |
||||
} |
||||
/** |
||||
* 解锁 |
||||
* @param string $lock_str 锁字符串 |
||||
* @param string $unique_id 唯一锁ID |
||||
* @return bool |
||||
* @throws RedisException |
||||
*/ |
||||
public function unlock(string $lock_str, string $unique_id): bool |
||||
{ |
||||
$redis = app('redis'); |
||||
|
||||
$redis->watch($lock_str); |
||||
if ($unique_id == $redis->get($lock_str)) { |
||||
$redis->multi()->del($lock_str)->exec(); |
||||
return true; |
||||
} |
||||
$redis->unwatch(); |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 获取唯一锁ID |
||||
* @return string |
||||
*/ |
||||
protected function getUniqueLockId(): string |
||||
{ |
||||
return md5(uniqid((string)mt_rand(), true)); |
||||
} |
||||
} |
@ -0,0 +1,48 @@ |
||||
<?php |
||||
|
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Traits; |
||||
trait UniversalEncryption |
||||
{ |
||||
private string $key; |
||||
|
||||
public function getKey(): string |
||||
{ |
||||
$key = openssl_digest(env('UNIVERSAL_ENCRYPTION_AES_KEY'), 'sha256', true); |
||||
return hash_pbkdf2('sha256', $key, '', 1, 32, true); |
||||
} |
||||
|
||||
/** |
||||
* Encrypt |
||||
* @param string $data |
||||
* @return string |
||||
*/ |
||||
public function encrypt(string $data): string |
||||
{ |
||||
$ivSize = openssl_cipher_iv_length('aes-256-cbc'); // AES-256-CBC需要的IV长度 |
||||
$iv = openssl_random_pseudo_bytes($ivSize); // 生成随机的IV |
||||
|
||||
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $this->getKey(), OPENSSL_RAW_DATA, $iv); |
||||
|
||||
$encryptedWithIv = $iv . $encrypted; |
||||
|
||||
return base64_encode($encryptedWithIv); |
||||
} |
||||
|
||||
/** |
||||
* Decrypt |
||||
* @param string $encryptedData |
||||
* @return bool|string |
||||
*/ |
||||
public function decrypt(string $encryptedData): bool|string |
||||
{ |
||||
$encodedData = base64_decode($encryptedData); |
||||
|
||||
$ivSize = openssl_cipher_iv_length('aes-256-cbc'); |
||||
$iv = mb_substr($encodedData, 0, $ivSize, '8bit'); |
||||
$encryptedData = mb_substr($encodedData, $ivSize, null, '8bit'); |
||||
|
||||
return openssl_decrypt($encryptedData, 'aes-256-cbc', $this->getKey(), OPENSSL_RAW_DATA, $iv); |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Transfer\HisSoap; |
||||
use App\Utils\Transfer\TransferAbstract; |
||||
|
||||
class ClientFactory |
||||
{ |
||||
|
||||
/** |
||||
* Get Client Transfer Class |
||||
* @param string $name |
||||
* @return TransferAbstract |
||||
*/ |
||||
public static function getClientTransfer(string $name): TransferAbstract |
||||
{ |
||||
$is_mock = config('hisservice.'. $name. '.is_mock'); |
||||
|
||||
return match ($is_mock) { |
||||
false => new ClientTransfer($name), |
||||
true => new ClientMockTransfer($name), |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,285 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Transfer\HisSoap; |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Utils\Transfer\TransferAbstract; |
||||
use Exception; |
||||
|
||||
class ClientMockTransfer extends TransferAbstract |
||||
{ |
||||
/** |
||||
* ClientMockTransfer Construct |
||||
* @param string $his_name |
||||
*/ |
||||
public function __construct(string $his_name = "") |
||||
{ |
||||
parent::__construct($his_name); |
||||
} |
||||
|
||||
/** |
||||
* 设置客户端选项 |
||||
* @return array |
||||
*/ |
||||
public function clientOption(): array |
||||
{ |
||||
return []; |
||||
} |
||||
|
||||
/** |
||||
* @param string $class_name |
||||
* @return $this |
||||
*/ |
||||
public function transferClass(string $class_name): static |
||||
{ |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* @throws GeneralException |
||||
*/ |
||||
public function transferMethod(string $method_name, array $request_data = []): self |
||||
{ |
||||
// 使用 match 替代 switch |
||||
return match ($method_name) { |
||||
'CreateCardPatInfo' => $this->mockRegisterCard($request_data), |
||||
'GetCardInfo' => $this->mockGetPatientInfo($request_data), |
||||
'GetDepType' => $this->mockGetDepLists($request_data), |
||||
'GetDoctList' => $this->mockGetDoctorLists($request_data), |
||||
'GetGHMXList' => $this->mockGetRegisterRecordLists($request_data), |
||||
'GHCancelCheck' => $this->mockCheckRefundRegisterStatus($request_data), |
||||
'GHCancelConfirm' => $this->mockRefundRegister($request_data), |
||||
'ListVisitRec' => $this->mockGetPendingLists($request_data), |
||||
'ListRecipe' => $this->mockGetPendingDetails($request_data), |
||||
'OutpatientExpenseRecord' => $this->mockGetPaidLists($request_data), |
||||
'OutpatientDetailRecord' => $this->mockGetPaidDetails($request_data), |
||||
'CreateOutpatientinvoiceEBill' => $this->mockCreateElectronInvoice($request_data), |
||||
'SendOutpatientinvoiceEBill' => $this->mockSendElectronInvoiceToHis($request_data), |
||||
'GetDictionary' => $this->mockGetDictionaryLists($request_data), |
||||
'GetChargeList' => $this->mockGetChargeList($request_data), |
||||
default => throw new GeneralException("Method '{$method_name}' not found"), |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* 响应格式化 |
||||
* @param mixed $data |
||||
* @return mixed |
||||
* @throws Exception |
||||
*/ |
||||
public function responseFormat(mixed $data): mixed |
||||
{ |
||||
try { |
||||
// 此处为xml格式 |
||||
$obj = simplexml_load_string((string)$data, 'SimpleXMLElement', LIBXML_NOCDATA); |
||||
return json_decode((string)json_encode($obj), true); |
||||
|
||||
} catch (Exception $e) { |
||||
throw new Exception($e->getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 获取返回值 |
||||
* @param bool $is_format |
||||
* @return mixed |
||||
* @throws Exception |
||||
*/ |
||||
public function getResult(bool $is_format = true): mixed |
||||
{ |
||||
return $this->responseFormat($this->transfer_response); |
||||
} |
||||
|
||||
/** |
||||
* 返回值字段 |
||||
* @return string |
||||
*/ |
||||
public function transferResponseStr(): string |
||||
{ |
||||
return ''; |
||||
} |
||||
|
||||
/** |
||||
* mockRegisterCard |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockRegisterCard(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>建卡成功</ERRORMSG><PATIENTID></PATIENTID></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockGetPatientInfo |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockGetPatientInfo(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG></ERRORMSG><PATIENTID>1104468</PATIENTID><CARDNO>452323193712153735</CARDNO><NAME>唐超积</NAME><SEX>1</SEX><BIRTHDAY>1937-12-15</BIRTHDAY><CARDSTATUS>0</CARDSTATUS><BRXZ>123</BRXZ><MZHM>299811204468</MZHM></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockGetDepLists |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockGetDepLists(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>Success</ERRORMSG><ITEM><DEPID>12345</DEPID><YBDEPID>67890</YBDEPID><DEPNAME>内科</DEPNAME><FEE>50.00</FEE><FEECODE>001</FEECODE><YSCOUNT>5</YSCOUNT><JZCOUNT>3</JZCOUNT><REGISTERAREA>1</REGISTERAREA><INTRODUCE>内科专注于诊治呼吸、消化、心血管等系统疾病。</INTRODUCE><KSGHXE>5</KSGHXE><KSYGRS>20</KSYGRS><KSKGRS>10</KSKGRS><YSGHXE>10</YSGHXE><YSYGRS>15</YSYGRS><YSKGRS>25</YSKGRS><KYYYSCOUNT>2</KYYYSCOUNT></ITEM><ITEM><DEPID>23456</DEPID><YBDEPID>78901</YBDEPID><DEPNAME>外科</DEPNAME><FEE>60.00</FEE><FEECODE>002</FEECODE><YSCOUNT>8</YSCOUNT><JZCOUNT>4</JZCOUNT><REGISTERAREA>2</REGISTERAREA><INTRODUCE>外科提供专业的手术治疗服务,包括创伤、整形及器官移植。</INTRODUCE><KSGHXE>6</KSGHXE><KSYGRS>30</KSYGRS><KSKGRS>15</KSKGRS><YSGHXE>12</YSGHXE><YSYGRS>20</YSYGRS><YSKGRS>30</YSKGRS><KYYYSCOUNT>3</KYYYSCOUNT></ITEM><ITEM><DEPID>34567</DEPID><YBDEPID>89012</YBDEPID><DEPNAME>儿科</DEPNAME><FEE>40.00</FEE><FEECODE>003</FEECODE><YSCOUNT>6</YSCOUNT><JZCOUNT>2</JZCOUNT><REGISTERAREA>1</REGISTERAREA><INTRODUCE>儿科为0-18岁儿童提供专业的诊疗与健康管理服务。</INTRODUCE><KSGHXE>4</KSGHXE><KSYGRS>25</KSYGRS><KSKGRS>8</KSKGRS><YSGHXE>8</YSGHXE><YSYGRS>10</YSYGRS><YSKGRS>18</YSKGRS><KYYYSCOUNT>4</KYYYSCOUNT></ITEM><ITEM><DEPID>45678</DEPID><YBDEPID>90123</YBDEPID><DEPNAME>皮肤科</DEPNAME><FEE>30.00</FEE><FEECODE>004</FEECODE><YSCOUNT>4</YSCOUNT><JZCOUNT>1</JZCOUNT><REGISTERAREA>1</REGISTERAREA><INTRODUCE>皮肤科诊治常见皮肤病、性病及皮肤美容问题。</INTRODUCE><KSGHXE>3</KSGHXE><KSYGRS>15</KSYGRS><KSKGRS>7</KSKGRS><YSGHXE>6</YSGHXE><YSYGRS>5</YSYGRS><YSKGRS>11</YSKGRS><KYYYSCOUNT>1</KYYYSCOUNT></ITEM></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockGetDoctorLists |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockGetDoctorLists(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>Success</ERRORMSG><ITEM><DOCTID>10001</DOCTID><YBDOCTID>20001</YBDOCTID><DOCTNAME>张三</DOCTNAME><DEPLOCATION>内科一诊室</DEPLOCATION><TYPENAME>主任医师</TYPENAME><ISKSDOC>1</ISKSDOC><SHIFT><DOCTID>10001</DOCTID><REGID>30001</REGID><FDATE>2024-12-27</FDATE><RANKID>1</RANKID><RANKNAME>上午班</RANKNAME><STARTTIME>08:00</STARTTIME><ENDTIME>12:00</ENDTIME><FEE>50.00</FEE><FEECODE>001</FEECODE><REGCOUNT>20</REGCOUNT><JZCOUNT>15</JZCOUNT></SHIFT><SHIFT><DOCTID>10001</DOCTID><REGID>30002</REGID><FDATE>2024-12-28</FDATE><RANKID>2</RANKID><RANKNAME>下午班</RANKNAME><STARTTIME>14:00</STARTTIME><ENDTIME>18:00</ENDTIME><FEE>55.00</FEE><FEECODE>002</FEECODE><REGCOUNT>18</REGCOUNT><JZCOUNT>12</JZCOUNT></SHIFT><SHIFT><DOCTID>10001</DOCTID><REGID>30003</REGID><FDATE>2024-12-29</FDATE><RANKID>3</RANKID><RANKNAME>夜班</RANKNAME><STARTTIME>20:00</STARTTIME><ENDTIME>00:00</ENDTIME><FEE>60.00</FEE><FEECODE>003</FEECODE><REGCOUNT>10</REGCOUNT><JZCOUNT>8</JZCOUNT></SHIFT><XMBH>XM001</XMBH><GJMLBM>1234567890</GJMLBM><XMMC>挂号诊查费</XMMC><JG>50</JG><MCYL>10</MCYL><JE>500</JE></ITEM><ITEM><DOCTID>10002</DOCTID><YBDOCTID>20002</YBDOCTID><DOCTNAME>李四</DOCTNAME><DEPLOCATION>外科二诊室</DEPLOCATION><TYPENAME>副主任医师</TYPENAME><ISKSDOC>0</ISKSDOC><SHIFT><DOCTID>10002</DOCTID><REGID>30004</REGID><FDATE>2024-12-27</FDATE><RANKID>1</RANKID><RANKNAME>上午班</RANKNAME><STARTTIME>08:00</STARTTIME><ENDTIME>12:00</ENDTIME><FEE>60.00</FEE><FEECODE>004</FEECODE><REGCOUNT>25</REGCOUNT><JZCOUNT>20</JZCOUNT></SHIFT><SHIFT><DOCTID>10002</DOCTID><REGID>30005</REGID><FDATE>2024-12-28</FDATE><RANKID>2</RANKID><RANKNAME>下午班</RANKNAME><STARTTIME>14:00</STARTTIME><ENDTIME>18:00</ENDTIME><FEE>65.00</FEE><FEECODE>005</FEECODE><REGCOUNT>20</REGCOUNT><JZCOUNT>18</JZCOUNT></SHIFT><XMBH>XM002</XMBH><GJMLBM>0987654321</GJMLBM><XMMC>挂号诊查费</XMMC><JG>100</JG><MCYL>15</MCYL><JE>1500</JE></ITEM></RESPONSE> |
||||
'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockGetRegisterRecordLists |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockGetRegisterRecordLists(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>成功</ERRORMSG><ITEM><VISITNO>3405227</VISITNO><FTYPE>当天挂号</FTYPE><STATUS>0</STATUS><WAITNUM>143</WAITNUM><TREAID>600240002968</TREAID><GHDATE>2021-07-17</GHDATE><PATIENTID>1103903</PATIENTID><PATIENTNAME>杨尧</PATIENTNAME><RANKID>2</RANKID><RANKNAME>下午</RANKNAME><OPPATNO>600005001000</OPPATNO><DEPLOCATION>门诊一楼</DEPLOCATION><TRANSNUM>0</TRANSNUM><ORDERTYPE>线上预约</ORDERTYPE><PAYFEE>17</PAYFEE><DEPID>16</DEPID><DEPNAME>急诊科</DEPNAME></ITEM><ITEM><VISITNO>3405228</VISITNO><FTYPE>预约挂号</FTYPE><STATUS>1</STATUS><WAITNUM>58</WAITNUM><TREAID>600240002969</TREAID><GHDATE>2021-07-18</GHDATE><PATIENTID>1103904</PATIENTID><PATIENTNAME>李梅</PATIENTNAME><RANKID>1</RANKID><RANKNAME>上午</RANKNAME><OPPATNO>600005001001</OPPATNO><DEPLOCATION>门诊二楼</DEPLOCATION><TRANSNUM>1</TRANSNUM><ORDERTYPE>现场挂号</ORDERTYPE><PAYFEE>25</PAYFEE><DEPID>20</DEPID><DEPNAME>内科</DEPNAME></ITEM><ITEM><VISITNO>3405229</VISITNO><FTYPE>当天挂号</FTYPE><STATUS>0</STATUS><WAITNUM>23</WAITNUM><TREAID>600240002970</TREAID><GHDATE>2021-07-19</GHDATE><PATIENTID>1103905</PATIENTID><PATIENTNAME>张强</PATIENTNAME><RANKID>3</RANKID><RANKNAME>夜间</RANKNAME><OPPATNO>600005001002</OPPATNO><DEPLOCATION>急诊大厅</DEPLOCATION><TRANSNUM>2</TRANSNUM><ORDERTYPE>电话预约</ORDERTYPE><PAYFEE>30</PAYFEE><DEPID>18</DEPID><DEPNAME>儿科</DEPNAME></ITEM><ITEM><VISITNO>3405230</VISITNO><FTYPE>预约挂号</FTYPE><STATUS>1</STATUS><WAITNUM>78</WAITNUM><TREAID>600240002971</TREAID><GHDATE>2021-07-20</GHDATE><PATIENTID>1103906</PATIENTID><PATIENTNAME>王丽</PATIENTNAME><RANKID>1</RANKID><RANKNAME>上午</RANKNAME><OPPATNO>600005001003</OPPATNO><DEPLOCATION>门诊三楼</DEPLOCATION><TRANSNUM>0</TRANSNUM><ORDERTYPE>线上预约</ORDERTYPE><PAYFEE>45</PAYFEE><DEPID>22</DEPID><DEPNAME>眼科</DEPNAME></ITEM></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockCheckRefundRegisterStatus |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockCheckRefundRegisterStatus(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>可退号</ERRORMSG></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockRefundRegister |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockRefundRegister(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG>退号成功</ERRORMSG></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
private function mockGetPendingLists(array $params) |
||||
{ |
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Pending list retrieved successfully.', |
||||
'data' => [ |
||||
[ |
||||
'visit_no' => '12345', |
||||
'patient_id' => $params['PATIENTID'], |
||||
'amount' => '100.00' |
||||
] |
||||
] |
||||
]; |
||||
} |
||||
|
||||
private function mockGetPendingDetails(array $params) |
||||
{ |
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Pending details retrieved successfully.', |
||||
'data' => [ |
||||
'cf_ids' => $params['CFID'], |
||||
'jz_xh' => $params['JZXH'], |
||||
'details' => 'Detailed description of the treatment.' |
||||
] |
||||
]; |
||||
} |
||||
|
||||
private function mockGetPaidLists(array $params) |
||||
{ |
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Paid list retrieved successfully.', |
||||
'data' => [ |
||||
[ |
||||
'receipt_id' => 'R12345', |
||||
'amount' => '200.00', |
||||
'payment_date' => '2024-01-01' |
||||
] |
||||
] |
||||
]; |
||||
} |
||||
|
||||
private function mockGetPaidDetails(array $params) |
||||
{ |
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Paid details retrieved successfully.', |
||||
'data' => [ |
||||
'receipt_id' => $params['Rcptid'], |
||||
'amount' => '200.00', |
||||
'details' => 'Detailed description of the paid service.' |
||||
] |
||||
]; |
||||
} |
||||
|
||||
private function mockCreateElectronInvoice(array $params) |
||||
{ |
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Electron invoice created successfully.', |
||||
'data' => $params |
||||
]; |
||||
} |
||||
|
||||
private function mockSendElectronInvoiceToHis(array $params) |
||||
{ |
||||
return [ |
||||
'status' => 'success', |
||||
'message' => 'Electron invoice sent successfully.', |
||||
'data' => $params |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* mockGetDictionaryLists |
||||
* @param array $params |
||||
* @return self |
||||
*/ |
||||
private function mockGetDictionaryLists(array $params): self |
||||
{ |
||||
$this->transfer_response = '<RESPONSE><RESULTCODE>0</RESULTCODE><ERRORMSG></ERRORMSG><ITEM><TYPEID>1</TYPEID><TYPENAME>手术费</TYPENAME></ITEM><ITEM><TYPEID>2</TYPEID><TYPENAME>治疗费</TYPENAME></ITEM><ITEM><TYPEID>3</TYPEID><TYPENAME>中药费</TYPENAME></ITEM><ITEM><TYPEID>4</TYPEID><TYPENAME>西药费</TYPENAME></ITEM><ITEM><TYPEID>5</TYPEID><TYPENAME>检查费</TYPENAME></ITEM><ITEM><TYPEID>6</TYPEID><TYPENAME>诊查费</TYPENAME></ITEM><ITEM><TYPEID>7</TYPEID><TYPENAME>护理费</TYPENAME></ITEM></RESPONSE>'; |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* mockGetChargeList |
||||
* @param array $params |
||||
* @return 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>'; |
||||
|
||||
return $this; |
||||
} |
||||
} |
@ -0,0 +1,78 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Transfer\HisSoap; |
||||
|
||||
use App\Utils\Transfer\TransferAbstract; |
||||
use Exception; |
||||
use WsdlToPhp\PackageBase\SoapClientInterface; |
||||
|
||||
class ClientTransfer extends TransferAbstract |
||||
{ |
||||
|
||||
/** |
||||
* MediWayTransfer Construct |
||||
* @param string $his_name |
||||
*/ |
||||
public function __construct(string $his_name = "") |
||||
{ |
||||
parent::__construct($his_name); |
||||
} |
||||
|
||||
/** |
||||
* 初始化 |
||||
*/ |
||||
public function initialize(): void |
||||
{ |
||||
parent::initialize(); |
||||
} |
||||
|
||||
/** |
||||
* 设置客户端选项 |
||||
* @return array |
||||
*/ |
||||
public function clientOption(): array |
||||
{ |
||||
return [ |
||||
SoapClientInterface::WSDL_URL => config('hisservice.his_soap.url'), |
||||
SoapClientInterface::WSDL_LOCATION => config('hisservice.his_soap.location'), |
||||
SoapClientInterface::WSDL_CONNECTION_TIMEOUT => 180, |
||||
SoapClientInterface::WSDL_TRACE => 1, |
||||
SoapClientInterface::WSDL_EXCEPTIONS => true, |
||||
SoapClientInterface::WSDL_STREAM_CONTEXT => stream_context_create([ |
||||
'ssl' => [ |
||||
// 'cafile' => base_path('cert/cacert-2024-03-11.pem'), |
||||
'verify_peer' => false, |
||||
'verify_peer_name' => false |
||||
], |
||||
]) |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 响应格式化 |
||||
* @param mixed $data |
||||
* @return mixed |
||||
* @throws Exception |
||||
*/ |
||||
public function responseFormat(mixed $data): mixed |
||||
{ |
||||
try { |
||||
// 此处为xml格式 |
||||
$obj = simplexml_load_string((string)$data, 'SimpleXMLElement', LIBXML_NOCDATA); |
||||
return json_decode((string)json_encode($obj), true); |
||||
|
||||
} catch (Exception $e) { |
||||
throw new Exception($e->getMessage()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 返回值字段 |
||||
* @return string |
||||
*/ |
||||
public function transferResponseStr(): string |
||||
{ |
||||
return $this->transfer_name. 'Result'; |
||||
} |
||||
} |
@ -0,0 +1,258 @@ |
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
namespace App\Utils\Transfer; |
||||
|
||||
use Exception; |
||||
use Illuminate\Support\Facades\Config; |
||||
use InvalidArgumentException; |
||||
use WsdlToPhp\PackageBase\AbstractSoapClientBase; |
||||
use WsdlToPhp\PackageBase\SoapClientInterface; |
||||
|
||||
abstract class TransferAbstract |
||||
{ |
||||
// his客户端 |
||||
private AbstractSoapClientBase $client; |
||||
|
||||
// His接口配置数据 |
||||
private array $his_config; |
||||
|
||||
// 映射类的命名空间 |
||||
protected string $service_type_namespace; |
||||
|
||||
// 映射方法的命名空间 |
||||
protected string $struct_type_namespace; |
||||
|
||||
// 调用接口名称 |
||||
public string $transfer_name; |
||||
|
||||
// 调用接口参数 |
||||
public mixed $transfer_parameter; |
||||
|
||||
// 调用返回结果 |
||||
public mixed $transfer_response; |
||||
|
||||
// 运行时间 |
||||
public array $request_time; |
||||
|
||||
/** |
||||
* Transfer constructor. |
||||
* @param string $his_name |
||||
* @throws InvalidArgumentException |
||||
*/ |
||||
public function __construct(string $his_name = "") |
||||
{ |
||||
// 判断传入的配置名称是否存在 |
||||
$config = Config::get('hisservice.'. $his_name); |
||||
if (!isset($config)) { |
||||
throw new InvalidArgumentException($his_name); |
||||
} |
||||
|
||||
// 获取配置文件中的“WSDL”文档URL |
||||
$this->his_config = $config; |
||||
$this->his_config['his_name'] = $his_name; |
||||
|
||||
$this->service_type_namespace = $this->his_config['service_type_namespace']; |
||||
$this->struct_type_namespace = $this->his_config['struct_type_namespace']; |
||||
|
||||
$this->initialize(); |
||||
} |
||||
|
||||
/** |
||||
* 初始化 |
||||
*/ |
||||
public function initialize(){} |
||||
|
||||
/** |
||||
* 获取配置 |
||||
* @param string $key |
||||
* @return mixed|null |
||||
*/ |
||||
public function getHisConfigByKey(string $key): mixed |
||||
{ |
||||
if (isset($this->his_config[$key])) { |
||||
return $this->his_config[$key]; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 设置客户端选项 |
||||
* @return array |
||||
*/ |
||||
abstract public function clientOption(): array; |
||||
|
||||
/** |
||||
* 设置返回值 |
||||
* @return string |
||||
*/ |
||||
abstract public function transferResponseStr(): string; |
||||
|
||||
/** |
||||
* 需要调用类 |
||||
* @param string $class_name |
||||
* @return $this |
||||
* @throws InvalidArgumentException |
||||
*/ |
||||
public function transferClass(string $class_name): self |
||||
{ |
||||
// 实例化具体操作类 |
||||
$class_name = $this->service_type_namespace . $class_name; |
||||
|
||||
if (!class_exists($class_name)) { |
||||
throw new InvalidArgumentException($class_name. ' CLASS NOT FOUND.'); |
||||
} |
||||
|
||||
$this->client = new $class_name($this->clientOption()); |
||||
|
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* 需要调用的方法 |
||||
* @param string $method_name |
||||
* @param array $request_data |
||||
* @return $this |
||||
* @throws InvalidArgumentException |
||||
* @throws Exception |
||||
*/ |
||||
public function transferMethod(string $method_name, array $request_data = []): self |
||||
{ |
||||
// 需要调用的方法的对象名 |
||||
$method_name_string = $this->struct_type_namespace . $method_name; |
||||
|
||||
// 记录调用的接口名称和参数 |
||||
$this->transfer_name = $method_name; |
||||
$this->transfer_parameter = $request_data; |
||||
|
||||
if (!class_exists($method_name_string)) { |
||||
throw new InvalidArgumentException($method_name_string. ' CLASS NOT FOUND.'); |
||||
} |
||||
|
||||
try { |
||||
$this->request_time['start_time'] = microtime(true); |
||||
$this->transfer_response = $this->client->{$method_name}(new $method_name_string(...$request_data)); |
||||
$this->request_time['end_time'] = microtime(true); |
||||
} catch (Exception $e) { |
||||
!isset($this->request_time['end_time']) && $this->request_time['end_time'] = microtime(true); |
||||
$this->transfer_response = "{$e->getFile()}:{$e->getLine()}:{$e->getMessage()}"; |
||||
$this->recordLog(); |
||||
throw new InvalidArgumentException($e->getMessage()); |
||||
} |
||||
|
||||
// 获取soap错误 |
||||
if ($this->transfer_response === false) { |
||||
$this->recordLog(); |
||||
$soap_fault = $this->client->getLastError(); |
||||
if (!empty($soap_fault)) { |
||||
$soap_fault = reset($soap_fault); |
||||
throw new Exception($soap_fault->getMessage()); |
||||
} |
||||
|
||||
throw new Exception('请求接口失败,请稍后再试'); |
||||
} |
||||
|
||||
$this->recordLog(); |
||||
return $this; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 获取返回值 |
||||
* @param bool $is_format |
||||
* @return mixed |
||||
* @throws Exception |
||||
*/ |
||||
public function getResult(bool $is_format = true): mixed |
||||
{ |
||||
$response_class_str = $this->struct_type_namespace . $this->transfer_name . 'Response'; |
||||
|
||||
if (!class_exists($response_class_str)) { |
||||
throw new Exception("Transfer Class Error: $response_class_str not found"); |
||||
} |
||||
|
||||
$res_str = $this->transferResponseStr(); |
||||
|
||||
if (!property_exists($this->transfer_response, $res_str)) { |
||||
throw new Exception("Transfer Attribute Error: transfer_response->$res_str not found"); |
||||
} |
||||
|
||||
$result_attr_str ='get'. ucfirst($res_str); |
||||
$this->transfer_response = new $response_class_str($this->transfer_response->$res_str); |
||||
$this->transfer_response = $this->transfer_response->$result_attr_str(); |
||||
|
||||
if ($is_format) { |
||||
return $this->responseFormat($this->transfer_response); |
||||
} |
||||
|
||||
return $this->transfer_response; |
||||
} |
||||
|
||||
/** |
||||
* 响应格式化 |
||||
* @param $data |
||||
*/ |
||||
abstract public function responseFormat($data); |
||||
|
||||
/** |
||||
* 保存日志记录 |
||||
* @param string $his_name |
||||
* @param string $content |
||||
*/ |
||||
public function recordRequestLog(string $his_name, string $content): void |
||||
{ |
||||
date_default_timezone_set("Asia/Shanghai"); |
||||
|
||||
$dirname = $this->his_config['his_name']; |
||||
$path = app()->storagePath(). DIRECTORY_SEPARATOR. $dirname. DIRECTORY_SEPARATOR; |
||||
$file_path = $path. $his_name. '_log'. DIRECTORY_SEPARATOR. date('Ym'). DIRECTORY_SEPARATOR; |
||||
$file_name = date('d'). ".log"; |
||||
|
||||
!is_dir($file_path) && mkdir($file_path, 0755, true); |
||||
|
||||
$msg = "[".date('Y-m-d H:i:s')."]". PHP_EOL . $content . PHP_EOL . PHP_EOL; |
||||
|
||||
file_put_contents( $file_path. $file_name, $msg, FILE_APPEND); |
||||
} |
||||
|
||||
/** |
||||
* 魔术方法实现动态调用方法 |
||||
* @param $function |
||||
* @param $args |
||||
* @return $this |
||||
* @throws InvalidArgumentException |
||||
*/ |
||||
public function __call($function, $args): self |
||||
{ |
||||
IF (method_exists($this, $function)) { |
||||
throw new InvalidArgumentException(__CLASS__ . '类的"'. $function .'"方法不存在'); |
||||
} |
||||
|
||||
$this->client = call_user_func($function, ...$args); |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* 记录日志 |
||||
*/ |
||||
public function recordLog(): void |
||||
{ |
||||
// 判断“是否设置日志参数”和“当前调用的方法是否记录到日志” |
||||
if (!empty($this->transfer_name)) { |
||||
$run_time = sprintf("%.6f", ($this->request_time['end_time'] - $this->request_time['start_time'])); |
||||
|
||||
if ( |
||||
empty($this->his_config['not_log_arr']) || |
||||
!in_array($this->transfer_name, $this->his_config['not_log_arr']) |
||||
) { |
||||
// 记录入参和结果 |
||||
$content = '[METHOD NAME] '. $this->transfer_name. 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. |
||||
'[RUN TIME] '. $run_time . "/s"; |
||||
$this->recordRequestLog($this->his_config['his_name'], $content); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
#!/usr/bin/env php |
||||
<?php |
||||
|
||||
use Symfony\Component\Console\Input\ArgvInput; |
||||
|
||||
define('LARAVEL_START', microtime(true)); |
||||
|
||||
// Register the Composer autoloader... |
||||
require __DIR__.'/vendor/autoload.php'; |
||||
|
||||
// Bootstrap Laravel and handle the command... |
||||
$status = (require_once __DIR__.'/bootstrap/app.php') |
||||
->handleCommand(new ArgvInput); |
||||
|
||||
exit($status); |
@ -0,0 +1,78 @@ |
||||
<?php |
||||
|
||||
use App\Exceptions\GeneralException; |
||||
use App\Http\Middleware\RecordApiLog; |
||||
use Illuminate\Auth\AuthenticationException; |
||||
use Illuminate\Foundation\Application; |
||||
use Illuminate\Foundation\Configuration\Exceptions; |
||||
use Illuminate\Foundation\Configuration\Middleware; |
||||
use Illuminate\Http\Request; |
||||
use Illuminate\Validation\ValidationException; |
||||
use Symfony\Component\HttpFoundation\Response; |
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; |
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
||||
|
||||
return Application::configure(basePath: dirname(__DIR__)) |
||||
->withRouting( |
||||
web: __DIR__.'/../routes/web.php', |
||||
api: __DIR__.'/../routes/api.php', |
||||
commands: __DIR__.'/../routes/console.php', |
||||
health: '/up', |
||||
apiPrefix: 'Api', |
||||
) |
||||
->withMiddleware(function (Middleware $middleware) { |
||||
|
||||
$middleware->alias([ |
||||
'apiLog' => RecordApiLog::class |
||||
]); |
||||
}) |
||||
->withExceptions(function (Exceptions $exceptions) { |
||||
$exceptions->dontReport([ |
||||
GeneralException::class, |
||||
]); |
||||
|
||||
$exceptions->render(function (Exception $exception, Request $request) { |
||||
// 错误消息 |
||||
$err_msg = $exception->getMessage(); |
||||
$record_msg = $err_msg. ' in '. $exception->getFile(). ':'. $exception->getLine(); |
||||
|
||||
// 校验入参错误 |
||||
if ($exception instanceof ValidationException) { |
||||
$err_arr = $exception->errors(); |
||||
$err_arr = array_shift($err_arr); |
||||
return jsonResponse(Response::HTTP_BAD_REQUEST, reset($err_arr)); |
||||
} |
||||
|
||||
// 接口请求方式不在路由设置中或不被允许时 |
||||
if($exception instanceof MethodNotAllowedHttpException) { |
||||
return jsonResponse(Response::HTTP_METHOD_NOT_ALLOWED, 'Method Not Allow.'); |
||||
} |
||||
|
||||
// 404异常扩展设置 |
||||
if ($exception instanceof NotFoundHttpException) { |
||||
return jsonResponse(Response::HTTP_NOT_FOUND, 'Not Found.'); |
||||
} |
||||
|
||||
// 权限 |
||||
if ($exception instanceof AuthenticationException) { |
||||
return jsonResponse(Response::HTTP_UNAUTHORIZED, 'Unauthenticated'); |
||||
} |
||||
|
||||
// 数据库错误 |
||||
if($exception instanceof PDOException) { |
||||
recordLog('DBError', $record_msg); |
||||
|
||||
return jsonResponse(Response::HTTP_INTERNAL_SERVER_ERROR, $err_msg); |
||||
} |
||||
|
||||
// 自定义错误 |
||||
if ($exception instanceof GeneralException) { |
||||
return jsonResponse(Response::HTTP_BAD_REQUEST, $err_msg); |
||||
} |
||||
|
||||
// 500 错误拦截 |
||||
recordLog('AppError', $record_msg); |
||||
return jsonResponse(Response::HTTP_INTERNAL_SERVER_ERROR, $record_msg); |
||||
}); |
||||
|
||||
})->create(); |
@ -0,0 +1,2 @@ |
||||
* |
||||
!.gitignore |
@ -0,0 +1,5 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
App\Providers\AppServiceProvider::class |
||||
]; |
@ -0,0 +1,88 @@ |
||||
{ |
||||
"name": "laravel/laravel", |
||||
"type": "project", |
||||
"description": "The skeleton application for the Laravel framework.", |
||||
"keywords": ["laravel", "framework"], |
||||
"license": "MIT", |
||||
"require": { |
||||
"php": "^8.2", |
||||
"ext-libxml": "*", |
||||
"ext-openssl": "*", |
||||
"ext-pdo": "*", |
||||
"ext-redis": "*", |
||||
"ext-simplexml": "*", |
||||
"ext-soap": "*", |
||||
"laravel/framework": "^11.31", |
||||
"laravel/sanctum": "^4.0", |
||||
"laravel/tinker": "^2.9", |
||||
"overtrue/laravel-wechat": "^7.2", |
||||
"wsdltophp/packagegenerator": "^4.1" |
||||
}, |
||||
"require-dev": { |
||||
"fakerphp/faker": "^1.23", |
||||
"laravel/pail": "^1.1", |
||||
"laravel/pint": "^1.13", |
||||
"laravel/sail": "^1.26", |
||||
"mockery/mockery": "^1.6", |
||||
"nunomaduro/collision": "^8.1", |
||||
"phpunit/phpunit": "^11.0.1" |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"App\\": "app/", |
||||
"Database\\Factories\\": "database/factories/", |
||||
"Database\\Seeders\\": "database/seeders/", |
||||
"UnifyPayment\\": "packagist/unify_payment/src" |
||||
}, |
||||
"classmap": [ |
||||
"app/Dictionary", |
||||
"app/Services/", |
||||
"app/Utils/" |
||||
], |
||||
"files":[ |
||||
"app/Utils/Helpers.php" |
||||
] |
||||
}, |
||||
"autoload-dev": { |
||||
"psr-4": { |
||||
"Tests\\": "tests/" |
||||
} |
||||
}, |
||||
"scripts": { |
||||
"post-autoload-dump": [ |
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", |
||||
"@php artisan package:discover --ansi" |
||||
], |
||||
"post-update-cmd": [ |
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force" |
||||
], |
||||
"post-root-package-install": [ |
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" |
||||
], |
||||
"post-create-project-cmd": [ |
||||
"@php artisan key:generate --ansi", |
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"", |
||||
"@php artisan migrate --graceful --ansi" |
||||
], |
||||
"dev": [ |
||||
"Composer\\Config::disableProcessTimeout", |
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite" |
||||
] |
||||
}, |
||||
"extra": { |
||||
"laravel": { |
||||
"dont-discover": [] |
||||
} |
||||
}, |
||||
"config": { |
||||
"optimize-autoloader": true, |
||||
"preferred-install": "dist", |
||||
"sort-packages": true, |
||||
"allow-plugins": { |
||||
"pestphp/pest-plugin": true, |
||||
"php-http/discovery": true |
||||
} |
||||
}, |
||||
"minimum-stability": "stable", |
||||
"prefer-stable": true |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,126 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Application Name |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This value is the name of your application, which will be used when the |
||||
| framework needs to place the application's name in a notification or |
||||
| other UI elements where an application name needs to be displayed. |
||||
| |
||||
*/ |
||||
|
||||
'name' => env('APP_NAME', 'Laravel'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Application Environment |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This value determines the "environment" your application is currently |
||||
| running in. This may determine how you prefer to configure various |
||||
| services the application utilizes. Set this in your ".env" file. |
||||
| |
||||
*/ |
||||
|
||||
'env' => env('APP_ENV', 'production'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Application Debug Mode |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When your application is in debug mode, detailed error messages with |
||||
| stack traces will be shown on every error that occurs within your |
||||
| application. If disabled, a simple generic error page is shown. |
||||
| |
||||
*/ |
||||
|
||||
'debug' => (bool) env('APP_DEBUG', false), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Application URL |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This URL is used by the console to properly generate URLs when using |
||||
| the Artisan command line tool. You should set this to the root of |
||||
| the application so that it's available within Artisan commands. |
||||
| |
||||
*/ |
||||
|
||||
'url' => env('APP_URL', 'http://localhost'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Application Timezone |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may specify the default timezone for your application, which |
||||
| will be used by the PHP date and date-time functions. The timezone |
||||
| is set to "UTC" by default as it is suitable for most use cases. |
||||
| |
||||
*/ |
||||
|
||||
'timezone' => env('APP_TIMEZONE', 'UTC'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Application Locale Configuration |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| The application locale determines the default locale that will be used |
||||
| by Laravel's translation / localization methods. This option can be |
||||
| set to any locale for which you plan to have translation strings. |
||||
| |
||||
*/ |
||||
|
||||
'locale' => env('APP_LOCALE', 'en'), |
||||
|
||||
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), |
||||
|
||||
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Encryption Key |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This key is utilized by Laravel's encryption services and should be set |
||||
| to a random, 32 character string to ensure that all encrypted values |
||||
| are secure. You should do this prior to deploying the application. |
||||
| |
||||
*/ |
||||
|
||||
'cipher' => 'AES-256-CBC', |
||||
|
||||
'key' => env('APP_KEY'), |
||||
|
||||
'previous_keys' => [ |
||||
...array_filter( |
||||
explode(',', env('APP_PREVIOUS_KEYS', '')) |
||||
), |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Maintenance Mode Driver |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| These configuration options determine the driver used to determine and |
||||
| manage Laravel's "maintenance mode" status. The "cache" driver will |
||||
| allow maintenance mode to be controlled across multiple machines. |
||||
| |
||||
| Supported drivers: "file", "cache" |
||||
| |
||||
*/ |
||||
|
||||
'maintenance' => [ |
||||
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), |
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'), |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,115 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Authentication Defaults |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option defines the default authentication "guard" and password |
||||
| reset "broker" for your application. You may change these values |
||||
| as required, but they're a perfect start for most applications. |
||||
| |
||||
*/ |
||||
|
||||
'defaults' => [ |
||||
'guard' => env('AUTH_GUARD', 'web'), |
||||
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Authentication Guards |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Next, you may define every authentication guard for your application. |
||||
| Of course, a great default configuration has been defined for you |
||||
| which utilizes session storage plus the Eloquent user provider. |
||||
| |
||||
| All authentication guards have a user provider, which defines how the |
||||
| users are actually retrieved out of your database or other storage |
||||
| system used by the application. Typically, Eloquent is utilized. |
||||
| |
||||
| Supported: "session" |
||||
| |
||||
*/ |
||||
|
||||
'guards' => [ |
||||
'web' => [ |
||||
'driver' => 'session', |
||||
'provider' => 'users', |
||||
] |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| User Providers |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| All authentication guards have a user provider, which defines how the |
||||
| users are actually retrieved out of your database or other storage |
||||
| system used by the application. Typically, Eloquent is utilized. |
||||
| |
||||
| If you have multiple user tables or models you may configure multiple |
||||
| providers to represent the model / table. These providers may then |
||||
| be assigned to any extra authentication guards you have defined. |
||||
| |
||||
| Supported: "database", "eloquent" |
||||
| |
||||
*/ |
||||
|
||||
'providers' => [ |
||||
'users' => [ |
||||
'driver' => 'eloquent', |
||||
'model' => env('AUTH_MODEL', App\Models\User::class), |
||||
], |
||||
|
||||
// 'users' => [ |
||||
// 'driver' => 'database', |
||||
// 'table' => 'users', |
||||
// ], |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Resetting Passwords |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| These configuration options specify the behavior of Laravel's password |
||||
| reset functionality, including the table utilized for token storage |
||||
| and the user provider that is invoked to actually retrieve users. |
||||
| |
||||
| The expiry time is the number of minutes that each reset token will be |
||||
| considered valid. This security feature keeps tokens short-lived so |
||||
| they have less time to be guessed. You may change this as needed. |
||||
| |
||||
| The throttle setting is the number of seconds a user must wait before |
||||
| generating more password reset tokens. This prevents the user from |
||||
| quickly generating a very large amount of password reset tokens. |
||||
| |
||||
*/ |
||||
|
||||
'passwords' => [ |
||||
'users' => [ |
||||
'provider' => 'users', |
||||
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), |
||||
'expire' => 60, |
||||
'throttle' => 60, |
||||
], |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Password Confirmation Timeout |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may define the amount of seconds before a password confirmation |
||||
| window expires and users are asked to re-enter their password via the |
||||
| confirmation screen. By default, the timeout lasts for three hours. |
||||
| |
||||
*/ |
||||
|
||||
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), |
||||
|
||||
]; |
@ -0,0 +1,108 @@ |
||||
<?php |
||||
|
||||
use Illuminate\Support\Str; |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Cache Store |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option controls the default cache store that will be used by the |
||||
| framework. This connection is utilized if another isn't explicitly |
||||
| specified when running a cache operation inside the application. |
||||
| |
||||
*/ |
||||
|
||||
'default' => env('CACHE_STORE', 'database'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Cache Stores |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may define all of the cache "stores" for your application as |
||||
| well as their drivers. You may even define multiple stores for the |
||||
| same cache driver to group types of items stored in your caches. |
||||
| |
||||
| Supported drivers: "array", "database", "file", "memcached", |
||||
| "redis", "dynamodb", "octane", "null" |
||||
| |
||||
*/ |
||||
|
||||
'stores' => [ |
||||
|
||||
'array' => [ |
||||
'driver' => 'array', |
||||
'serialize' => false, |
||||
], |
||||
|
||||
'database' => [ |
||||
'driver' => 'database', |
||||
'connection' => env('DB_CACHE_CONNECTION'), |
||||
'table' => env('DB_CACHE_TABLE', 'cache'), |
||||
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), |
||||
'lock_table' => env('DB_CACHE_LOCK_TABLE'), |
||||
], |
||||
|
||||
'file' => [ |
||||
'driver' => 'file', |
||||
'path' => storage_path('framework/cache/data'), |
||||
'lock_path' => storage_path('framework/cache/data'), |
||||
], |
||||
|
||||
'memcached' => [ |
||||
'driver' => 'memcached', |
||||
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), |
||||
'sasl' => [ |
||||
env('MEMCACHED_USERNAME'), |
||||
env('MEMCACHED_PASSWORD'), |
||||
], |
||||
'options' => [ |
||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000, |
||||
], |
||||
'servers' => [ |
||||
[ |
||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'), |
||||
'port' => env('MEMCACHED_PORT', 11211), |
||||
'weight' => 100, |
||||
], |
||||
], |
||||
], |
||||
|
||||
'redis' => [ |
||||
'driver' => 'redis', |
||||
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), |
||||
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), |
||||
], |
||||
|
||||
'dynamodb' => [ |
||||
'driver' => 'dynamodb', |
||||
'key' => env('AWS_ACCESS_KEY_ID'), |
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'), |
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), |
||||
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), |
||||
'endpoint' => env('DYNAMODB_ENDPOINT'), |
||||
], |
||||
|
||||
'octane' => [ |
||||
'driver' => 'octane', |
||||
], |
||||
|
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Cache Key Prefix |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache |
||||
| stores, there might be other applications using the same cache. For |
||||
| that reason, you may prefix every cache key to avoid collisions. |
||||
| |
||||
*/ |
||||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), |
||||
|
||||
]; |
@ -0,0 +1,10 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* his 系统值 / 自定义值 |
||||
*/ |
||||
|
||||
return [ |
||||
// 绑定就诊卡数上限 |
||||
'max_bind_patient_count' => 5 |
||||
]; |
@ -0,0 +1,181 @@ |
||||
<?php |
||||
|
||||
use Illuminate\Support\Str; |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Database Connection Name |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may specify which of the database connections below you wish |
||||
| to use as your default connection for database operations. This is |
||||
| the connection which will be utilized unless another connection |
||||
| is explicitly specified when you execute a query / statement. |
||||
| |
||||
*/ |
||||
|
||||
'default' => env('DB_CONNECTION', 'sqlite'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Database Connections |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Below are all of the database connections defined for your application. |
||||
| An example configuration is provided for each database system which |
||||
| is supported by Laravel. You're free to add / remove connections. |
||||
| |
||||
*/ |
||||
|
||||
'connections' => [ |
||||
|
||||
'sqlite' => [ |
||||
'driver' => 'sqlite', |
||||
'url' => env('DB_URL'), |
||||
'database' => env('DB_DATABASE', database_path('database.sqlite')), |
||||
'prefix' => '', |
||||
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), |
||||
'busy_timeout' => null, |
||||
'journal_mode' => null, |
||||
'synchronous' => null, |
||||
], |
||||
|
||||
'mysql' => [ |
||||
'driver' => 'mysql', |
||||
'url' => env('DB_URL'), |
||||
'host' => env('DB_HOST', '127.0.0.1'), |
||||
'port' => env('DB_PORT', '3306'), |
||||
'database' => env('DB_DATABASE', 'laravel'), |
||||
'username' => env('DB_USERNAME', 'root'), |
||||
'password' => env('DB_PASSWORD', ''), |
||||
'unix_socket' => env('DB_SOCKET', ''), |
||||
'charset' => env('DB_CHARSET', 'utf8mb4'), |
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), |
||||
'prefix' => env('DB_PREFIX', ''), |
||||
'prefix_indexes' => true, |
||||
'strict' => true, |
||||
'engine' => null, |
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([ |
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), |
||||
]) : [], |
||||
], |
||||
|
||||
'mariadb' => [ |
||||
'driver' => 'mariadb', |
||||
'url' => env('DB_URL'), |
||||
'host' => env('DB_HOST', '127.0.0.1'), |
||||
'port' => env('DB_PORT', '3306'), |
||||
'database' => env('DB_DATABASE', 'laravel'), |
||||
'username' => env('DB_USERNAME', 'root'), |
||||
'password' => env('DB_PASSWORD', ''), |
||||
'unix_socket' => env('DB_SOCKET', ''), |
||||
'charset' => env('DB_CHARSET', 'utf8mb4'), |
||||
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), |
||||
'prefix' => '', |
||||
'prefix_indexes' => true, |
||||
'strict' => true, |
||||
'engine' => null, |
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([ |
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), |
||||
]) : [], |
||||
], |
||||
|
||||
'pgsql' => [ |
||||
'driver' => 'pgsql', |
||||
'url' => env('DB_URL'), |
||||
'host' => env('DB_HOST', '127.0.0.1'), |
||||
'port' => env('DB_PORT', '5432'), |
||||
'database' => env('DB_DATABASE', 'laravel'), |
||||
'username' => env('DB_USERNAME', 'root'), |
||||
'password' => env('DB_PASSWORD', ''), |
||||
'charset' => env('DB_CHARSET', 'utf8'), |
||||
'prefix' => '', |
||||
'prefix_indexes' => true, |
||||
'search_path' => 'public', |
||||
'sslmode' => 'prefer', |
||||
], |
||||
|
||||
'sqlsrv' => [ |
||||
'driver' => 'sqlsrv', |
||||
'url' => env('DB_URL'), |
||||
'host' => env('DB_HOST', 'localhost'), |
||||
'port' => env('DB_PORT', '1433'), |
||||
'database' => env('DB_DATABASE', 'laravel'), |
||||
'username' => env('DB_USERNAME', 'root'), |
||||
'password' => env('DB_PASSWORD', ''), |
||||
'charset' => env('DB_CHARSET', 'utf8'), |
||||
'prefix' => '', |
||||
'prefix_indexes' => true, |
||||
// 'encrypt' => env('DB_ENCRYPT', 'yes'), |
||||
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), |
||||
], |
||||
|
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Migration Repository Table |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This table keeps track of all the migrations that have already run for |
||||
| your application. Using this information, we can determine which of |
||||
| the migrations on disk haven't actually been run on the database. |
||||
| |
||||
*/ |
||||
|
||||
'migrations' => [ |
||||
'table' => 'migrations', |
||||
'update_date_on_publish' => true, |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Redis Databases |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Redis is an open source, fast, and advanced key-value store that also |
||||
| provides a richer body of commands than a typical key-value system |
||||
| such as Memcached. You may define your connection settings here. |
||||
| |
||||
*/ |
||||
|
||||
'redis' => [ |
||||
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'), |
||||
|
||||
'options' => [ |
||||
'cluster' => env('REDIS_CLUSTER', 'redis'), |
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), |
||||
], |
||||
|
||||
'default' => [ |
||||
'url' => env('REDIS_URL'), |
||||
'host' => env('REDIS_HOST', '127.0.0.1'), |
||||
'username' => env('REDIS_USERNAME'), |
||||
'password' => env('REDIS_PASSWORD'), |
||||
'port' => env('REDIS_PORT', '6379'), |
||||
'database' => env('REDIS_DB', '0'), |
||||
], |
||||
|
||||
'cache' => [ |
||||
'url' => env('REDIS_URL'), |
||||
'host' => env('REDIS_HOST', '127.0.0.1'), |
||||
'username' => env('REDIS_USERNAME'), |
||||
'password' => env('REDIS_PASSWORD'), |
||||
'port' => env('REDIS_PORT', '6379'), |
||||
'database' => env('REDIS_CACHE_DB', '1'), |
||||
], |
||||
|
||||
'session' => [ |
||||
'url' => env('REDIS_URL'), |
||||
'host' => env('REDIS_HOST', '127.0.0.1'), |
||||
'username' => env('REDIS_USERNAME'), |
||||
'password' => env('REDIS_PASSWORD'), |
||||
'port' => env('REDIS_PORT', '6379'), |
||||
'database' => env('REDIS_SESSION_DB', '2'), |
||||
], |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,77 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Filesystem Disk |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may specify the default filesystem disk that should be used |
||||
| by the framework. The "local" disk, as well as a variety of cloud |
||||
| based disks are available to your application for file storage. |
||||
| |
||||
*/ |
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'local'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Filesystem Disks |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Below you may configure as many filesystem disks as necessary, and you |
||||
| may even configure multiple disks for the same driver. Examples for |
||||
| most supported storage drivers are configured here for reference. |
||||
| |
||||
| Supported drivers: "local", "ftp", "sftp", "s3" |
||||
| |
||||
*/ |
||||
|
||||
'disks' => [ |
||||
|
||||
'local' => [ |
||||
'driver' => 'local', |
||||
'root' => storage_path('app/private'), |
||||
'serve' => true, |
||||
'throw' => false, |
||||
], |
||||
|
||||
'public' => [ |
||||
'driver' => 'local', |
||||
'root' => storage_path('app/public'), |
||||
'url' => env('APP_URL').'/storage', |
||||
'visibility' => 'public', |
||||
'throw' => false, |
||||
], |
||||
|
||||
's3' => [ |
||||
'driver' => 's3', |
||||
'key' => env('AWS_ACCESS_KEY_ID'), |
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'), |
||||
'region' => env('AWS_DEFAULT_REGION'), |
||||
'bucket' => env('AWS_BUCKET'), |
||||
'url' => env('AWS_URL'), |
||||
'endpoint' => env('AWS_ENDPOINT'), |
||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), |
||||
'throw' => false, |
||||
], |
||||
|
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Symbolic Links |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may configure the symbolic links that will be created when the |
||||
| `storage:link` Artisan command is executed. The array keys should be |
||||
| the locations of the links and the values should be their targets. |
||||
| |
||||
*/ |
||||
|
||||
'links' => [ |
||||
public_path('storage') => storage_path('app/public'), |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,14 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
'his_soap' => [ |
||||
'url' => '', |
||||
'location' => '', |
||||
'service_type_namespace' => 'HisSoapService\ServiceType\\', |
||||
'struct_type_namespace' => 'HisSoapService\StructType\\', |
||||
// 不记录日志的数组请求 |
||||
'not_log_arr' => [], |
||||
// 是否模拟数据 |
||||
'is_mock' => true, |
||||
], |
||||
]; |
@ -0,0 +1,169 @@ |
||||
<?php |
||||
|
||||
use App\Utils\GeneralDailyLogger; |
||||
use Monolog\Handler\NullHandler; |
||||
use Monolog\Handler\StreamHandler; |
||||
use Monolog\Handler\SyslogUdpHandler; |
||||
use Monolog\Processor\PsrLogMessageProcessor; |
||||
use Monolog\Level; |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Log Channel |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option defines the default log channel that is utilized to write |
||||
| messages to your logs. The value provided here should match one of |
||||
| the channels present in the list of "channels" configured below. |
||||
| |
||||
*/ |
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Deprecations Log Channel |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option controls the log channel that should be used to log warnings |
||||
| regarding deprecated PHP and library features. This allows you to get |
||||
| your application ready for upcoming major versions of dependencies. |
||||
| |
||||
*/ |
||||
|
||||
'deprecations' => [ |
||||
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), |
||||
'trace' => env('LOG_DEPRECATIONS_TRACE', false), |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Log Channels |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may configure the log channels for your application. Laravel |
||||
| utilizes the Monolog PHP logging library, which includes a variety |
||||
| of powerful log handlers and formatters that you're free to use. |
||||
| |
||||
| Available drivers: "single", "daily", "slack", "syslog", |
||||
| "errorlog", "monolog", "custom", "stack" |
||||
| |
||||
*/ |
||||
|
||||
'channels' => [ |
||||
|
||||
'stack' => [ |
||||
'driver' => 'stack', |
||||
'channels' => explode(',', env('LOG_STACK', 'single')), |
||||
'ignore_exceptions' => false, |
||||
], |
||||
|
||||
'single' => [ |
||||
'driver' => 'single', |
||||
'path' => storage_path('logs/laravel.log'), |
||||
'level' => env('LOG_LEVEL', 'debug'), |
||||
'replace_placeholders' => true, |
||||
], |
||||
|
||||
'daily' => [ |
||||
'driver' => 'daily', |
||||
'path' => storage_path('logs/laravel.log'), |
||||
'level' => env('LOG_LEVEL', 'debug'), |
||||
'days' => env('LOG_DAILY_DAYS', 14), |
||||
'replace_placeholders' => true, |
||||
], |
||||
|
||||
'slack' => [ |
||||
'driver' => 'slack', |
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'), |
||||
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), |
||||
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), |
||||
'level' => env('LOG_LEVEL', 'critical'), |
||||
'replace_placeholders' => true, |
||||
], |
||||
|
||||
'papertrail' => [ |
||||
'driver' => 'monolog', |
||||
'level' => env('LOG_LEVEL', 'debug'), |
||||
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), |
||||
'handler_with' => [ |
||||
'host' => env('PAPERTRAIL_URL'), |
||||
'port' => env('PAPERTRAIL_PORT'), |
||||
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), |
||||
], |
||||
'processors' => [PsrLogMessageProcessor::class], |
||||
], |
||||
|
||||
'stderr' => [ |
||||
'driver' => 'monolog', |
||||
'level' => env('LOG_LEVEL', 'debug'), |
||||
'handler' => StreamHandler::class, |
||||
'formatter' => env('LOG_STDERR_FORMATTER'), |
||||
'with' => [ |
||||
'stream' => 'php://stderr', |
||||
], |
||||
'processors' => [PsrLogMessageProcessor::class], |
||||
], |
||||
|
||||
'syslog' => [ |
||||
'driver' => 'syslog', |
||||
'level' => env('LOG_LEVEL', 'debug'), |
||||
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), |
||||
'replace_placeholders' => true, |
||||
], |
||||
|
||||
'errorlog' => [ |
||||
'driver' => 'errorlog', |
||||
'level' => env('LOG_LEVEL', 'debug'), |
||||
'replace_placeholders' => true, |
||||
], |
||||
|
||||
'null' => [ |
||||
'driver' => 'monolog', |
||||
'handler' => NullHandler::class, |
||||
], |
||||
|
||||
'emergency' => [ |
||||
'path' => storage_path('logs/laravel.log'), |
||||
], |
||||
|
||||
// Default |
||||
'default' => [ |
||||
'driver' => 'custom', |
||||
'via' => GeneralDailyLogger::class, |
||||
'service_type' => 'Default', |
||||
'level' => Level::Info, |
||||
'max_files' => 30, |
||||
], |
||||
|
||||
// 通用日志 |
||||
'genera' => [ |
||||
'driver' => 'custom', |
||||
'via' => GeneralDailyLogger::class, |
||||
'service_type' => 'GeneraLog', |
||||
'level' => Level::Info, |
||||
'max_files' => 30, |
||||
], |
||||
|
||||
// HisSoap |
||||
'his_soap' => [ |
||||
'driver' => 'custom', |
||||
'via' => GeneralDailyLogger::class, |
||||
'service_type' => 'HisSoapLog', |
||||
'level' => Level::Info, |
||||
'max_files' => 360, |
||||
], |
||||
|
||||
// 退费相关日志 |
||||
'refund' => [ |
||||
'driver' => 'custom', |
||||
'via' => GeneralDailyLogger::class, |
||||
'service_type' => 'RefundLog', |
||||
'level' => Level::Info, |
||||
'max_files' => 0, |
||||
], |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,116 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Mailer |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option controls the default mailer that is used to send all email |
||||
| messages unless another mailer is explicitly specified when sending |
||||
| the message. All additional mailers can be configured within the |
||||
| "mailers" array. Examples of each type of mailer are provided. |
||||
| |
||||
*/ |
||||
|
||||
'default' => env('MAIL_MAILER', 'log'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Mailer Configurations |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may configure all of the mailers used by your application plus |
||||
| their respective settings. Several examples have been configured for |
||||
| you and you are free to add your own as your application requires. |
||||
| |
||||
| Laravel supports a variety of mail "transport" drivers that can be used |
||||
| when delivering an email. You may specify which one you're using for |
||||
| your mailers below. You may also add additional mailers if needed. |
||||
| |
||||
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", |
||||
| "postmark", "resend", "log", "array", |
||||
| "failover", "roundrobin" |
||||
| |
||||
*/ |
||||
|
||||
'mailers' => [ |
||||
|
||||
'smtp' => [ |
||||
'transport' => 'smtp', |
||||
'url' => env('MAIL_URL'), |
||||
'host' => env('MAIL_HOST', '127.0.0.1'), |
||||
'port' => env('MAIL_PORT', 2525), |
||||
'encryption' => env('MAIL_ENCRYPTION', 'tls'), |
||||
'username' => env('MAIL_USERNAME'), |
||||
'password' => env('MAIL_PASSWORD'), |
||||
'timeout' => null, |
||||
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), |
||||
], |
||||
|
||||
'ses' => [ |
||||
'transport' => 'ses', |
||||
], |
||||
|
||||
'postmark' => [ |
||||
'transport' => 'postmark', |
||||
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), |
||||
// 'client' => [ |
||||
// 'timeout' => 5, |
||||
// ], |
||||
], |
||||
|
||||
'resend' => [ |
||||
'transport' => 'resend', |
||||
], |
||||
|
||||
'sendmail' => [ |
||||
'transport' => 'sendmail', |
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), |
||||
], |
||||
|
||||
'log' => [ |
||||
'transport' => 'log', |
||||
'channel' => env('MAIL_LOG_CHANNEL'), |
||||
], |
||||
|
||||
'array' => [ |
||||
'transport' => 'array', |
||||
], |
||||
|
||||
'failover' => [ |
||||
'transport' => 'failover', |
||||
'mailers' => [ |
||||
'smtp', |
||||
'log', |
||||
], |
||||
], |
||||
|
||||
'roundrobin' => [ |
||||
'transport' => 'roundrobin', |
||||
'mailers' => [ |
||||
'ses', |
||||
'postmark', |
||||
], |
||||
], |
||||
|
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Global "From" Address |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| You may wish for all emails sent by your application to be sent from |
||||
| the same address. Here you may specify a name and address that is |
||||
| used globally for all emails that are sent by your application. |
||||
| |
||||
*/ |
||||
|
||||
'from' => [ |
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), |
||||
'name' => env('MAIL_FROM_NAME', 'Example'), |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,57 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
// 所有支付超时时间 单位 秒 |
||||
'overtime' => 120, |
||||
|
||||
// 微信 |
||||
'wechat' => [ |
||||
// 公众号 APPID |
||||
'app_id' => '', |
||||
|
||||
// 小程序 APPID |
||||
'miniapp_id' => '', |
||||
|
||||
// APP 引用的 APPID |
||||
'appid' => '', |
||||
|
||||
// 子商户 APP APPID |
||||
'sub_appid' => '', |
||||
|
||||
// 微信支付分配的微信商户号 |
||||
'mch_id' => '', |
||||
|
||||
// 子商户商户号 |
||||
'sub_mch_id' => '', |
||||
|
||||
// 微信支付异步通知地址 |
||||
'notify_url' => '', |
||||
|
||||
// 微信支付签名秘钥 |
||||
'key' => 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB', |
||||
|
||||
// 客户端证书路径,退款、红包等需要用到。请填写绝对路径,linux 请确保权限问题。pem 格式。 |
||||
'cert_client' => base_path('pem'. DIRECTORY_SEPARATOR. 'apiclient_cert.pem'), |
||||
|
||||
// 客户端秘钥路径,退款、红包等需要用到。请填写绝对路径,linux 请确保权限问题。pem 格式。 |
||||
'cert_key' => base_path('pem'. DIRECTORY_SEPARATOR. 'apiclient_key.pem'), |
||||
|
||||
// optional 服务商模式 |
||||
'mode' => 'service', |
||||
|
||||
// optional,默认 warning;日志路径为:sys_get_temp_dir().'/logs/yansongda.pay.log' |
||||
'log' => [ // optional |
||||
'file' => storage_path('/logs/wechat.log'), |
||||
'level' => 'info', // 建议生产环境等级调整为 info,开发环境为 debug |
||||
'type' => 'daily', // optional, 可选 daily, daily 时将按时间自动划分文件. |
||||
], |
||||
|
||||
// http, 请求option配置 更多配置项请参考 Guzzle 文档 |
||||
'http' => [ |
||||
'verify' => false, |
||||
'timeout' => 20, // 超时时间 20s |
||||
'connect_timeout' => 5.0, // 连接时间 5s |
||||
], |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,112 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Queue Connection Name |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Laravel's queue supports a variety of backends via a single, unified |
||||
| API, giving you convenient access to each backend using identical |
||||
| syntax for each. The default queue connection is defined below. |
||||
| |
||||
*/ |
||||
|
||||
'default' => env('QUEUE_CONNECTION', 'database'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Queue Connections |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may configure the connection options for every queue backend |
||||
| used by your application. An example configuration is provided for |
||||
| each backend supported by Laravel. You're also free to add more. |
||||
| |
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" |
||||
| |
||||
*/ |
||||
|
||||
'connections' => [ |
||||
|
||||
'sync' => [ |
||||
'driver' => 'sync', |
||||
], |
||||
|
||||
'database' => [ |
||||
'driver' => 'database', |
||||
'connection' => env('DB_QUEUE_CONNECTION'), |
||||
'table' => env('DB_QUEUE_TABLE', 'jobs'), |
||||
'queue' => env('DB_QUEUE', 'default'), |
||||
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), |
||||
'after_commit' => false, |
||||
], |
||||
|
||||
'beanstalkd' => [ |
||||
'driver' => 'beanstalkd', |
||||
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), |
||||
'queue' => env('BEANSTALKD_QUEUE', 'default'), |
||||
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), |
||||
'block_for' => 0, |
||||
'after_commit' => false, |
||||
], |
||||
|
||||
'sqs' => [ |
||||
'driver' => 'sqs', |
||||
'key' => env('AWS_ACCESS_KEY_ID'), |
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'), |
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), |
||||
'queue' => env('SQS_QUEUE', 'default'), |
||||
'suffix' => env('SQS_SUFFIX'), |
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), |
||||
'after_commit' => false, |
||||
], |
||||
|
||||
'redis' => [ |
||||
'driver' => 'redis', |
||||
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), |
||||
'queue' => env('REDIS_QUEUE', 'default'), |
||||
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), |
||||
'block_for' => null, |
||||
'after_commit' => false, |
||||
], |
||||
|
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Job Batching |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| The following options configure the database and table that store job |
||||
| batching information. These options can be updated to any database |
||||
| connection and table which has been defined by your application. |
||||
| |
||||
*/ |
||||
|
||||
'batching' => [ |
||||
'database' => env('DB_CONNECTION', 'sqlite'), |
||||
'table' => 'job_batches', |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Failed Queue Jobs |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| These options configure the behavior of failed queue job logging so you |
||||
| can control how and where failed jobs are stored. Laravel ships with |
||||
| support for storing failed jobs in a simple file or in a database. |
||||
| |
||||
| Supported drivers: "database-uuids", "dynamodb", "file", "null" |
||||
| |
||||
*/ |
||||
|
||||
'failed' => [ |
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), |
||||
'database' => env('DB_CONNECTION', 'sqlite'), |
||||
'table' => 'failed_jobs', |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,83 @@ |
||||
<?php |
||||
|
||||
use Laravel\Sanctum\Sanctum; |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Stateful Domains |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Requests from the following domains / hosts will receive stateful API |
||||
| authentication cookies. Typically, these should include your local |
||||
| and production domains which access your API via a frontend SPA. |
||||
| |
||||
*/ |
||||
|
||||
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( |
||||
'%s%s', |
||||
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', |
||||
Sanctum::currentApplicationUrlWithPort() |
||||
))), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Sanctum Guards |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This array contains the authentication guards that will be checked when |
||||
| Sanctum is trying to authenticate a request. If none of these guards |
||||
| are able to authenticate the request, Sanctum will use the bearer |
||||
| token that's present on an incoming request for authentication. |
||||
| |
||||
*/ |
||||
|
||||
'guard' => ['web'], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Expiration Minutes |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This value controls the number of minutes until an issued token will be |
||||
| considered expired. This will override any values set in the token's |
||||
| "expires_at" attribute, but first-party sessions are not affected. |
||||
| |
||||
*/ |
||||
|
||||
'expiration' => null, |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Token Prefix |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Sanctum can prefix new tokens in order to take advantage of numerous |
||||
| security scanning initiatives maintained by open source platforms |
||||
| that notify developers if they commit tokens into repositories. |
||||
| |
||||
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning |
||||
| |
||||
*/ |
||||
|
||||
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Sanctum Middleware |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When authenticating your first-party SPA with Sanctum you may need to |
||||
| customize some of the middleware Sanctum uses while processing the |
||||
| request. You may change the middleware listed below as required. |
||||
| |
||||
*/ |
||||
|
||||
'middleware' => [ |
||||
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, |
||||
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, |
||||
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,38 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Third Party Services |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This file is for storing the credentials for third party services such |
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto |
||||
| location for this type of information, allowing packages to have |
||||
| a conventional file to locate the various service credentials. |
||||
| |
||||
*/ |
||||
|
||||
'postmark' => [ |
||||
'token' => env('POSTMARK_TOKEN'), |
||||
], |
||||
|
||||
'ses' => [ |
||||
'key' => env('AWS_ACCESS_KEY_ID'), |
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'), |
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), |
||||
], |
||||
|
||||
'resend' => [ |
||||
'key' => env('RESEND_KEY'), |
||||
], |
||||
|
||||
'slack' => [ |
||||
'notifications' => [ |
||||
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), |
||||
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), |
||||
], |
||||
], |
||||
|
||||
]; |
@ -0,0 +1,217 @@ |
||||
<?php |
||||
|
||||
use Illuminate\Support\Str; |
||||
|
||||
return [ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Default Session Driver |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option determines the default session driver that is utilized for |
||||
| incoming requests. Laravel supports a variety of storage options to |
||||
| persist session data. Database storage is a great default choice. |
||||
| |
||||
| Supported: "file", "cookie", "database", "apc", |
||||
| "memcached", "redis", "dynamodb", "array" |
||||
| |
||||
*/ |
||||
|
||||
'driver' => env('SESSION_DRIVER', 'database'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Lifetime |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may specify the number of minutes that you wish the session |
||||
| to be allowed to remain idle before it expires. If you want them |
||||
| to expire immediately when the browser is closed then you may |
||||
| indicate that via the expire_on_close configuration option. |
||||
| |
||||
*/ |
||||
|
||||
'lifetime' => env('SESSION_LIFETIME', 120), |
||||
|
||||
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Encryption |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option allows you to easily specify that all of your session data |
||||
| should be encrypted before it's stored. All encryption is performed |
||||
| automatically by Laravel and you may use the session like normal. |
||||
| |
||||
*/ |
||||
|
||||
'encrypt' => env('SESSION_ENCRYPT', false), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session File Location |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When utilizing the "file" session driver, the session files are placed |
||||
| on disk. The default storage location is defined here; however, you |
||||
| are free to provide another location where they should be stored. |
||||
| |
||||
*/ |
||||
|
||||
'files' => storage_path('framework/sessions'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Database Connection |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When using the "database" or "redis" session drivers, you may specify a |
||||
| connection that should be used to manage these sessions. This should |
||||
| correspond to a connection in your database configuration options. |
||||
| |
||||
*/ |
||||
|
||||
'connection' => env('SESSION_CONNECTION'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Database Table |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When using the "database" session driver, you may specify the table to |
||||
| be used to store sessions. Of course, a sensible default is defined |
||||
| for you; however, you're welcome to change this to another table. |
||||
| |
||||
*/ |
||||
|
||||
'table' => env('SESSION_TABLE', 'sessions'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Cache Store |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| When using one of the framework's cache driven session backends, you may |
||||
| define the cache store which should be used to store the session data |
||||
| between requests. This must match one of your defined cache stores. |
||||
| |
||||
| Affects: "apc", "dynamodb", "memcached", "redis" |
||||
| |
||||
*/ |
||||
|
||||
'store' => env('SESSION_STORE'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Sweeping Lottery |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Some session drivers must manually sweep their storage location to get |
||||
| rid of old sessions from storage. Here are the chances that it will |
||||
| happen on a given request. By default, the odds are 2 out of 100. |
||||
| |
||||
*/ |
||||
|
||||
'lottery' => [2, 100], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Cookie Name |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Here you may change the name of the session cookie that is created by |
||||
| the framework. Typically, you should not need to change this value |
||||
| since doing so does not grant a meaningful security improvement. |
||||
| |
||||
*/ |
||||
|
||||
'cookie' => env( |
||||
'SESSION_COOKIE', |
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session' |
||||
), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Cookie Path |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| The session cookie path determines the path for which the cookie will |
||||
| be regarded as available. Typically, this will be the root path of |
||||
| your application, but you're free to change this when necessary. |
||||
| |
||||
*/ |
||||
|
||||
'path' => env('SESSION_PATH', '/'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Session Cookie Domain |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This value determines the domain and subdomains the session cookie is |
||||
| available to. By default, the cookie will be available to the root |
||||
| domain and all subdomains. Typically, this shouldn't be changed. |
||||
| |
||||
*/ |
||||
|
||||
'domain' => env('SESSION_DOMAIN'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| HTTPS Only Cookies |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| By setting this option to true, session cookies will only be sent back |
||||
| to the server if the browser has a HTTPS connection. This will keep |
||||
| the cookie from being sent to you when it can't be done securely. |
||||
| |
||||
*/ |
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| HTTP Access Only |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Setting this value to true will prevent JavaScript from accessing the |
||||
| value of the cookie and the cookie will only be accessible through |
||||
| the HTTP protocol. It's unlikely you should disable this option. |
||||
| |
||||
*/ |
||||
|
||||
'http_only' => env('SESSION_HTTP_ONLY', true), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Same-Site Cookies |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| This option determines how your cookies behave when cross-site requests |
||||
| take place, and can be used to mitigate CSRF attacks. By default, we |
||||
| will set this value to "lax" to permit secure cross-site requests. |
||||
| |
||||
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value |
||||
| |
||||
| Supported: "lax", "strict", "none", null |
||||
| |
||||
*/ |
||||
|
||||
'same_site' => env('SESSION_SAME_SITE', 'lax'), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Partitioned Cookies |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| Setting this value to true will tie the cookie to the top-level site for |
||||
| a cross-site context. Partitioned cookies are accepted by the browser |
||||
| when flagged "secure" and the Same-Site attribute is set to "none". |
||||
| |
||||
*/ |
||||
|
||||
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), |
||||
|
||||
]; |
@ -0,0 +1,159 @@ |
||||
<?php |
||||
|
||||
return [ |
||||
|
||||
'official' => [ |
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| WeChat Official Account 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| 微信公众号对应配置数据 |
||||
| 详见:https://easywechat.com/6.x/official-account/index.html |
||||
| |
||||
*/ |
||||
'app_id' => env('WECHAT_OFFICIAL_APP_ID', ''), |
||||
'secret' => env('WECHAT_OFFICIAL_APP_SECRET', ''), |
||||
'token' => env('WECHAT_OFFICIAL_TOKEN', ''), |
||||
'aes_key' => env('WECHAT_OFFICIAL_AES_KEY', ''), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| OAuth 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| scopes:公众平台(snsapi_userinfo / snsapi_base),开放平台:snsapi_login |
||||
| callback:OAuth授权完成后的回调页地址 |
||||
| |
||||
*/ |
||||
'oauth' => [ |
||||
'scopes' => ['snsapi_userinfo'], |
||||
'callback' => env('WECHAT_OAUTH_CALLBACK_URL', ''), |
||||
], |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Http 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| 接口请求相关配置,超时时间等,具体可用参数请参考: |
||||
| https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php |
||||
| |
||||
*/ |
||||
'http' => [ |
||||
'timeout' => 5.0, |
||||
// 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri |
||||
// 'base_uri' => 'https://api.weixin.qq.com/', |
||||
|
||||
'retry' => true, // 使用默认重试配置 |
||||
/* 'retry' => [ |
||||
// 仅以下状态码重试 |
||||
'http_codes' => [429, 500] |
||||
// 最大重试次数 |
||||
'max_retries' => 3, |
||||
// 请求间隔 (毫秒) |
||||
'delay' => 1000, |
||||
// 如果设置,每次重试的等待时间都会增加这个系数 |
||||
// (例如. 首次:1000ms; 第二次: 3 * 1000ms; etc.) |
||||
'multiplier' => 3 |
||||
],*/ |
||||
], |
||||
], |
||||
|
||||
'mini' => [ |
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| WeChat Mini Program 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| 微信小程序对应配置数据 |
||||
| 详见:https://easywechat.com/6.x/mini-app/index.html |
||||
| |
||||
*/ |
||||
'app_id' => env('WECHAT_MINI_APP_ID', 'wxccd0c4f642673a6d'), |
||||
'secret' => env('WECHAT_MINI_APP_SECRET', '73f66753cf45336186f8640b6673d5fb'), |
||||
'token' => env('WECHAT_MINI_TOKEN', ''), |
||||
'aes_key' => env('WECHAT_MINI_AES_KEY', ''), |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Http 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| 接口请求相关配置,超时时间等,具体可用参数请参考: |
||||
| https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php |
||||
| |
||||
*/ |
||||
'http' => [ |
||||
// 默认不抛出异常 |
||||
'throw' => false, |
||||
// 超时时间 |
||||
'timeout' => 5.0, |
||||
// 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri |
||||
// 'base_uri' => 'https://api.weixin.qq.com/', |
||||
|
||||
'retry' => true, // 使用默认重试配置 |
||||
/* 'retry' => [ |
||||
// 仅以下状态码重试 |
||||
'http_codes' => [429, 500] |
||||
// 最大重试次数 |
||||
'max_retries' => 3, |
||||
// 请求间隔 (毫秒) |
||||
'delay' => 1000, |
||||
// 如果设置,每次重试的等待时间都会增加这个系数 |
||||
// (例如. 首次:1000ms; 第二次: 3 * 1000ms; etc.) |
||||
'multiplier' => 3 |
||||
],*/ |
||||
], |
||||
], |
||||
|
||||
'payment' => [ |
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| WeChat Payment 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| 微信支付对应配置数据 |
||||
| 详见:https://easywechat.com/6.x/pay/index.html |
||||
| |
||||
*/ |
||||
// V2 |
||||
'app_id' => env('WECHAT_PAYMENT_SP_APP_ID', ''), |
||||
'sub_app_id' => env('WECHAT_PAYMENT_SUB_APP_ID', ''), |
||||
'mch_id' => env('WECHAT_PAYMENT_SP_MCH_ID', ''), |
||||
'sub_mch_id' => env('WECHAT_PAYMENT_SUB_MCH_ID', ''), |
||||
'private_key' => env('WECHAT_PAYMENT_V2_PRIVATE_KEY_PATH', ''), |
||||
'certificate' => env('WECHAT_PAYMENT_V2_CERTIFICATE_PATH', ''), |
||||
'v2_secret_key' => env('WECHAT_PAYMENT_V2_SECRET_KEY', ''), |
||||
|
||||
|
||||
// V3 |
||||
/* |
||||
'sp_app_id' => env('WECHAT_PAYMENT_SP_APP_ID', ''), |
||||
'sub_app_id' => env('WECHAT_PAYMENT_SUB_APP_ID', ''), |
||||
'sp_mch_id' => env('WECHAT_PAYMENT_SP_MCH_ID', ''), |
||||
'sub_mch_id' => env('WECHAT_PAYMENT_SUB_MCH_ID', ''), |
||||
'secret_key' => env('WECHAT_PAYMENT_V3_SECRET_KEY', ''), |
||||
'platform_certs' => [ |
||||
// 请使用绝对路径 |
||||
// '/path/to/wechatpay/cert.pem', |
||||
env('WECHAT_PAYMENT_V3_PRIVATE_KEY_PATH'), |
||||
], |
||||
*/ |
||||
|
||||
/* |
||||
|-------------------------------------------------------------------------- |
||||
| Http 配置 |
||||
|-------------------------------------------------------------------------- |
||||
| |
||||
| 接口请求相关配置,超时时间等,具体可用参数请参考: |
||||
| https://github.com/symfony/symfony/blob/5.3/src/Symfony/Contracts/HttpClient/HttpClientInterface.php |
||||
| |
||||
*/ |
||||
'http' => [ |
||||
'throw' => true, // 状态码非 200、300 时是否抛出异常,默认为开启 |
||||
'timeout' => 5.0, |
||||
// 'base_uri' => 'https://api.mch.weixin.qq.com/', // 如果你在国外想要覆盖默认的 url 的时候才使用,根据不同的模块配置不同的 uri |
||||
], |
||||
] |
||||
]; |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue