Wechatpay.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. <?php
  2. namespace core\pay;
  3. use app\dict\common\ChannelDict;
  4. use app\dict\pay\OnlinePayDict;
  5. use app\dict\pay\RefundDict;
  6. use app\dict\pay\TransferDict;
  7. use core\exception\PayException;
  8. use Psr\Http\Message\MessageInterface;
  9. use Psr\Http\Message\ResponseInterface;
  10. use think\facade\Log;
  11. use think\Response;
  12. use Throwable;
  13. use Yansongda\Artful\Exception\InvalidResponseException;
  14. use Yansongda\Pay\Exception\ContainerException;
  15. use Yansongda\Pay\Exception\InvalidParamsException;
  16. use Yansongda\Pay\Exception\ServiceNotFoundException;
  17. use Yansongda\Pay\Pay;
  18. use Yansongda\Pay\Plugin\Wechat\V3\Marketing\MchTransfer\CancelPlugin;
  19. use Yansongda\Supports\Collection;
  20. /**
  21. * 微信支付管理驱动类 todo 注意:暂时不考虑合单类业务
  22. * Class FileDriver
  23. * @package core\file
  24. */
  25. class Wechatpay extends BasePay
  26. {
  27. /**
  28. * @param array $config
  29. * @return void
  30. * @throws ContainerException
  31. */
  32. protected function initialize(array $config = [])
  33. {
  34. $this->config = $config;
  35. $config['mch_secret_cert'] = url_to_path($config['mch_secret_cert'] ?? '');
  36. $config['mch_public_cert_path'] = url_to_path($config['mch_public_cert_path'] ?? '');
  37. // 选填-默认为正常模式。可选为: MODE_NORMAL, MODE_SERVICE
  38. $config['mode'] = Pay::MODE_NORMAL;
  39. if (!empty($config['wechat_public_cert_path']) && !empty($config['wechat_public_cert_id'])) {
  40. $config['wechat_public_cert_path'] = [
  41. $config['wechat_public_cert_id'] => url_to_path($config['wechat_public_cert_path'])
  42. ];
  43. } else {
  44. unset($config['wechat_public_cert_path']);
  45. unset($config['wechat_public_cert_id']);
  46. }
  47. Pay::config($this->payConfig($config, 'wechat'));
  48. }
  49. /**
  50. * 公众号支付
  51. * @param array $params
  52. * @return mixed|Collection
  53. */
  54. public function mp(array $params)
  55. {
  56. try {
  57. $result = $this->returnFormat(Pay::wechat()->mp([
  58. 'out_trade_no' => $params['out_trade_no'],
  59. 'description' => $params['body'],
  60. 'amount' => [
  61. 'total' => $params['money'],
  62. ],
  63. 'payer' => [
  64. 'openid' => $params['openid'],
  65. ],
  66. ]));
  67. $code = $result['code'] ?? 0;
  68. if ($code == 0) return $result;
  69. //支付错误抛出
  70. throw new PayException($result['message']);
  71. } catch (\Exception $e) {
  72. if ($e instanceof InvalidResponseException) {
  73. throw new PayException($e->response->all()['message'] ?? '');
  74. }
  75. throw new PayException($e->getMessage());
  76. }
  77. }
  78. /**
  79. * 手机网页支付
  80. * @param array $params
  81. * @return mixed
  82. */
  83. public function wap(array $params)
  84. {
  85. try {
  86. $order = [
  87. 'out_trade_no' => $params['out_trade_no'],
  88. 'description' => $params['body'],
  89. 'amount' => [
  90. 'total' => $params['money'],
  91. ],
  92. 'scene_info' => [
  93. 'payer_client_ip' => request()->ip(),
  94. 'h5_info' => [
  95. 'type' => 'Wap',
  96. ]
  97. ],
  98. ];
  99. //这儿有些特殊, 默认情况下,H5 支付所使用的 appid 是微信公众号的 appid,即配置文件中的 mp_app_id 参数,如果想使用关联的小程序的 appid,则只需要在调用参数中增加 ['_type' => 'mini'] 即可
  100. if (!empty($order['type'])) {
  101. $order['_type'] = 'mini'; // 注意这一行
  102. }
  103. return $this->returnFormat(Pay::wechat()->h5($order));
  104. } catch (\Exception $e) {
  105. if ($e instanceof InvalidResponseException) {
  106. throw new PayException($e->response->all()['message'] ?? '');
  107. }
  108. throw new PayException($e->getMessage());
  109. }
  110. }
  111. public function web(array $params)
  112. {
  113. }
  114. /**
  115. * app支付
  116. * @param array $params
  117. * @return mixed|ResponseInterface
  118. */
  119. public function app(array $params)
  120. {
  121. try {
  122. return $this->returnFormat(Pay::wechat()->app([
  123. 'out_trade_no' => $params['out_trade_no'],
  124. 'description' => $params['body'],
  125. 'amount' => [
  126. 'total' => $params['money'],
  127. ],
  128. ]));
  129. } catch (\Exception $e) {
  130. if ($e instanceof InvalidResponseException) {
  131. throw new PayException($e->response->all()['message'] ?? '');
  132. }
  133. throw new PayException($e->getMessage());
  134. }
  135. }
  136. /**
  137. * 小程序支付
  138. * @param array $params
  139. * @return mixed|ResponseInterface
  140. */
  141. public function mini(array $params)
  142. {
  143. try {
  144. return $this->returnFormat(Pay::wechat()->mini([
  145. 'out_trade_no' => $params['out_trade_no'],
  146. 'description' => $params['body'],
  147. 'amount' => [
  148. 'total' => $params['money'],
  149. 'currency' => 'CNY',//一般是人民币
  150. ],
  151. 'payer' => [
  152. 'openid' => $params['openid'],
  153. ]
  154. ]));
  155. } catch (\Exception $e) {
  156. if ($e instanceof InvalidResponseException) {
  157. throw new PayException($e->response->all()['message'] ?? '');
  158. }
  159. throw new PayException($e->getMessage());
  160. }
  161. }
  162. /**
  163. * 付款码支付
  164. * @param array $params
  165. * @return mixed|Collection
  166. */
  167. public function pos(array $params)
  168. {
  169. try {
  170. $order = [
  171. 'out_trade_no' => $params['out_trade_no'],
  172. 'body' => $params['body'],
  173. 'total_fee' => $params['money'],
  174. 'spbill_create_ip' => request()->ip(),
  175. 'auth_code' => $params["auth_code"],
  176. ];
  177. $result = Pay::wechat()->pos($order);
  178. return $this->returnFormat($result);
  179. } catch (\Exception $e) {
  180. if ($e instanceof InvalidResponseException) {
  181. throw new PayException($e->response->all()['message'] ?? '');
  182. }
  183. throw new PayException($e->getMessage());
  184. }
  185. }
  186. /**
  187. * 扫码支付
  188. * @param array $params
  189. * @return mixed|Collection
  190. */
  191. public function scan(array $params)
  192. {
  193. try {
  194. return $this->returnFormat(Pay::wechat()->scan([
  195. 'out_trade_no' => $params['out_trade_no'],
  196. 'description' => $params['body'],
  197. 'amount' => [
  198. 'total' => $params['money'],
  199. ],
  200. ]));
  201. } catch (\Exception $e) {
  202. if ($e instanceof InvalidResponseException) {
  203. throw new PayException($e->response->all()['message'] ?? '');
  204. }
  205. throw new PayException($e->getMessage());
  206. }
  207. }
  208. /**
  209. * 转账(微信的转账是很多笔的)
  210. * @param array $params
  211. * @return array
  212. */
  213. public function transfer(array $params)
  214. {
  215. $to_data = $params['to_no'];//收款人数据
  216. $channel = $to_data['channel'] ?? '';//渠道
  217. $open_id = $to_data['open_id'] ?? '';//openid
  218. $transfer_scene_id = (string)$to_data['transfer_scene_id'] ?? '';//openid
  219. $transfer_scene_report_infos = $to_data['transfer_scene_report_infos'] ?? [];//openid
  220. $user_recv_perception = $to_data['user_recv_perception'] ?? '';//openid
  221. if(empty($this->config['mch_id']) || empty($this->config['mch_secret_key']) || empty($this->config['mch_secret_cert']) || empty($this->config['mch_public_cert_path'])){
  222. throw new PayException('WECHAT_TRANSFER_CONFIG_NOT_EXIST');
  223. }
  224. if(empty($transfer_scene_id)){
  225. throw new PayException('PLEASE_CONTACT_THE_ADMINISTRATOR_TO_CONFIGURE_THE_WECHAT_TRANSFER_SCENARIO_ID');//请联系管理员配置微信转账场景ID');
  226. }
  227. $transfer_no = $params['transfer_no'] ?? '';
  228. $remark = $params['remark'] ?? '';
  229. $order = [
  230. '_action' => 'mch_transfer', // 微信官方老版本下线后,此部分可省略
  231. 'out_bill_no' => $transfer_no,
  232. 'transfer_scene_id' => $transfer_scene_id,
  233. 'openid' => $open_id,
  234. // 'user_name' => '闫嵩达' // 明文传参即可,sdk 会自动加密
  235. 'transfer_amount' => (int)$params['money'],
  236. 'transfer_remark' => $remark,
  237. 'transfer_scene_report_infos' =>$transfer_scene_report_infos,
  238. 'notify_url' => $this->config['notify_url'],
  239. 'user_recv_perception' => $user_recv_perception
  240. ];
  241. if($channel == ChannelDict::WEAPP){
  242. $order['_type'] = 'mini';
  243. }
  244. $tran_status_list = [
  245. 'PROCESSING' => TransferDict::DEALING,
  246. 'ACCEPTED' => TransferDict::DEALING,
  247. 'WAIT_USER_CONFIRM' => TransferDict::WAIT_USER,//等待收款用户确认
  248. 'TRANSFERING' => TransferDict::WAIT_USER_ING,//转账中
  249. 'FAIL' => TransferDict::FAIL,
  250. 'SUCCESS' => TransferDict::SUCCESS,
  251. 'CANCELING' => TransferDict::FAIL_ING,
  252. 'CANCELLED' => TransferDict::FAIL,
  253. ];
  254. try {
  255. $result = $this->returnFormat(Pay::wechat()->transfer($order));
  256. if (!empty($result['code'])) {
  257. // if($result['code'] == 'PARAM_ERROR'){
  258. // throw new PayException();
  259. // }else if($result['code'] == 'INVALID_REQUEST'){
  260. // throw new PayException();
  261. // }
  262. if ($result['code'] == 'INVALID_REQUEST') {
  263. throw new PayException(700010);
  264. }
  265. throw new PayException($result['message']);
  266. }
  267. $result['mch_id'] = $this->config['mch_id'];
  268. $result['appid'] = $channel == ChannelDict::WEAPP ? $this->config['mini_app_id'] : $this->config['mp_app_id'];
  269. return ['out_bill_no' => $result['out_bill_no'], 'transfer_bill_no' => $result['transfer_bill_no'], 'status' => $tran_status_list[$result['state']], 'reason' => $result['fail_reason'] ?? '', 'package_info' => $result['package_info'] ?? [], 'extra' => $result];
  270. } catch (\Exception $e) {
  271. // if($e->getCode() == 9402){
  272. // return ['batch_id' => '', 'out_batch_no' => $order['out_batch_no'], 'status' => TransferDict::DEALING];
  273. // }
  274. if ($e instanceof InvalidResponseException) {
  275. throw new PayException($e->response->all()['message'] ?? '');
  276. }
  277. throw new PayException($e->getMessage());
  278. }
  279. }
  280. /**
  281. * 支付关闭
  282. * @param string $out_trade_no
  283. * @return void
  284. * @throws ContainerException
  285. * @throws InvalidParamsException
  286. * @throws ServiceNotFoundException
  287. */
  288. public function close(string $out_trade_no)
  289. {
  290. try {
  291. $result = Pay::wechat()->close([
  292. 'out_trade_no' => $out_trade_no,
  293. ]);
  294. return $this->returnFormat($result);
  295. }catch(Throwable $e){
  296. return false;
  297. }
  298. return true;
  299. }
  300. /**
  301. * 退款
  302. * @param array $params
  303. * @return array
  304. * @throws ContainerException
  305. * @throws InvalidParamsException
  306. * @throws ServiceNotFoundException
  307. */
  308. public function refund(array $params)
  309. {
  310. $out_trade_no = $params['out_trade_no'];
  311. $money = $params['money'];
  312. $total = $params['total'];
  313. $refund_no = $params['refund_no'];
  314. $result = Pay::wechat()->refund([
  315. 'out_trade_no' => $out_trade_no,
  316. 'out_refund_no' => $refund_no,
  317. 'amount' => [
  318. 'refund' => $money,
  319. 'total' => $total,
  320. 'currency' => 'CNY',
  321. ],
  322. ]);
  323. $result = $this->returnFormat($result);
  324. $refund_status_array = [
  325. 'SUCCESS' => RefundDict::SUCCESS,
  326. 'CLOSED' => RefundDict::FAIL,
  327. 'PROCESSING' => RefundDict::DEALING,
  328. 'ABNORMAL' => RefundDict::FAIL,
  329. ];
  330. return [
  331. 'status' => $refund_status_array[$result['status']],
  332. 'refund_no' => $refund_no,
  333. 'out_trade_no' => $out_trade_no,
  334. 'pay_refund_no' => $result['refund_id']
  335. ];
  336. }
  337. /**
  338. * 异步回调
  339. * @param string $action
  340. * @param callable $callback
  341. * @return ResponseInterface|Response
  342. */
  343. public function notify(string $action, callable $callback)
  344. {
  345. try {
  346. Log::write('wechat_start'.$action);
  347. $result = $this->returnFormat(Pay::wechat()->callback());
  348. Log::write('wechat_start_1');
  349. Log::write($result);
  350. Log::write('wechat_start_1');
  351. if ($action == 'pay') {//支付
  352. if ($result['event_type'] == 'TRANSACTION.SUCCESS') {
  353. $pay_trade_data = $result['resource']['ciphertext'];
  354. $temp_params = [
  355. 'trade_no' => $pay_trade_data['transaction_id'],
  356. 'mch_id' => $pay_trade_data['mchid'],
  357. 'status' => OnlinePayDict::getWechatPayStatus($pay_trade_data['trade_state'])
  358. ];
  359. $callback_result = $callback($pay_trade_data['out_trade_no'], $temp_params);
  360. if (is_bool($callback_result) && $callback_result) {
  361. return Pay::wechat()->success();
  362. }
  363. }
  364. } else if ($action == 'refund') {//退款
  365. if ($result['event_type'] == 'REFUND.SUCCESS') {
  366. $refund_trade_data = $result['resource']['ciphertext'];
  367. $refund_status_array = [
  368. 'SUCCESS' => RefundDict::SUCCESS,
  369. 'CLOSED' => RefundDict::FAIL,
  370. 'PROCESSING' => RefundDict::DEALING,
  371. 'ABNORMAL' => RefundDict::FAIL,
  372. ];
  373. $temp_params = [
  374. 'trade_no' => $refund_trade_data['transaction_id'],
  375. 'mch_id' => $refund_trade_data['mchid'],
  376. 'refund_no' => $refund_trade_data['out_refund_no'],
  377. 'status' => $refund_status_array[$refund_trade_data['refund_status']],
  378. ];
  379. $callback_result = $callback($refund_trade_data['out_trade_no'], $temp_params);
  380. if (is_bool($callback_result) && $callback_result) {
  381. return Pay::wechat()->success();
  382. }
  383. }
  384. }else if ($action == 'transfer') {//转账
  385. if ($result['event_type'] == 'MCHTRANSFER.BILL.FINISHED') {
  386. $refund_trade_data = $result['resource']['ciphertext'];
  387. $tran_status_list = [
  388. 'PROCESSING' => TransferDict::DEALING,
  389. 'ACCEPTED' => TransferDict::DEALING,
  390. 'WAIT_USER_CONFIRM' => TransferDict::WAIT_USER,//等待收款用户确认
  391. 'TRANSFERING' => TransferDict::WAIT_USER_ING,//转账中
  392. 'FAIL' => TransferDict::FAIL,
  393. 'SUCCESS' => TransferDict::SUCCESS,
  394. 'CANCELING' => TransferDict::FAIL_ING,
  395. 'CANCELLED' => TransferDict::FAIL,
  396. ];
  397. $temp_params = [
  398. // 'out_bill_no' => $refund_trade_data['out_bill_no'],
  399. 'mch_id' => $refund_trade_data['mch_id'],
  400. 'out_bill_no' => $refund_trade_data['out_bill_no'] ?? '',
  401. 'transfer_bill_no' => $refund_trade_data['transfer_bill_no'] ?? '',
  402. 'status' => $tran_status_list[$refund_trade_data['state']],
  403. 'reason' => $refund_trade_data['fail_reason'] ?? '',
  404. ];
  405. Log::write('wechat_start_2');
  406. Log::write($temp_params);
  407. Log::write('wechat_start_2');
  408. $callback_result = $callback($refund_trade_data['out_bill_no'], $temp_params);
  409. if (is_bool($callback_result) && $callback_result) {
  410. return Pay::wechat()->success();
  411. }
  412. }
  413. }
  414. return $this->fail();
  415. } catch ( Throwable $e ) {
  416. // throw new PayException($e->getMessage());
  417. Log::write('wechat_error'.$e->getMessage().$e->getLine().$e->getFile());
  418. return $this->fail($e->getMessage());
  419. }
  420. }
  421. /**
  422. * 查询普通支付订单
  423. * @param array $params
  424. * @return array|MessageInterface|Collection|null
  425. * @throws ContainerException
  426. * @throws InvalidParamsException
  427. * @throws ServiceNotFoundException
  428. */
  429. public function getOrder(array $params = [])
  430. {
  431. $out_trade_no = $params['out_trade_no'];
  432. $transaction_id = $params['transaction_id'] ?? '';
  433. $order = [
  434. ];
  435. if (!empty($out_trade_no)) {
  436. $order['out_trade_no'] = $out_trade_no;
  437. }
  438. if (!empty($transaction_id)) {
  439. $order['transaction_id'] = $transaction_id;
  440. }
  441. $result = Pay::wechat()->query($order);
  442. if (empty($result))
  443. return $result;
  444. $result = $this->returnFormat($result);
  445. return [
  446. 'status' => OnlinePayDict::getWechatPayStatus($result['trade_state']),
  447. ];
  448. }
  449. /**
  450. * 查询退款单据
  451. * @param string|null $out_trade_no
  452. * @param string|null $refund_no
  453. * @return array|Collection|MessageInterface|null
  454. * @throws ContainerException
  455. * @throws InvalidParamsException
  456. * @throws ServiceNotFoundException
  457. */
  458. public function getRefund(?string $out_trade_no, ?string $refund_no = '')
  459. {
  460. $order = [
  461. '_action' => 'refund',
  462. 'transaction_id' => $out_trade_no,
  463. 'out_refund_no' => $refund_no,
  464. ''
  465. ];
  466. $result = Pay::wechat()->query($order);
  467. if (empty($result))
  468. return $result;
  469. $result = $this->returnFormat($result);
  470. $refund_status_array = [
  471. 'SUCCESS' => RefundDict::SUCCESS,
  472. 'CLOSED' => RefundDict::FAIL,
  473. 'PROCESSING' => RefundDict::DEALING,
  474. 'ABNORMAL' => RefundDict::FAIL,
  475. ];
  476. return [
  477. 'status' => $refund_status_array[$result['status']],
  478. 'refund_no' => $refund_no,
  479. 'out_trade_no' => $out_trade_no
  480. ];
  481. }
  482. /**
  483. * 获取转账订单(todo 切勿调用)
  484. * @param string $transfer_no
  485. * @return array
  486. * @throws ContainerException
  487. * @throws InvalidParamsException
  488. */
  489. public function getTransfer(string $transfer_no, $out_batch_no = '')
  490. {
  491. $order = [
  492. 'out_bill_no' => $transfer_no,
  493. 'transfer_bill_no' => $out_batch_no,
  494. '_action' => 'transfer',
  495. ];
  496. $tran_status_list = [
  497. 'PROCESSING' => TransferDict::DEALING,
  498. 'ACCEPTED' => TransferDict::DEALING,
  499. 'WAIT_USER_CONFIRM' => TransferDict::WAIT_USER,//等待收款用户确认
  500. 'TRANSFERING' => TransferDict::WAIT_USER_ING,//转账中
  501. 'FAIL' => TransferDict::FAIL,
  502. 'SUCCESS' => TransferDict::SUCCESS,
  503. 'CANCELING' => TransferDict::FAIL_ING,
  504. 'CANCELLED' => TransferDict::FAIL,
  505. ];
  506. try {
  507. $result = Pay::wechat()->query($order);
  508. $result = $this->returnFormat($result);
  509. //微信转账状态
  510. // $transfer_status_array = [
  511. // 'INIT' => TransferDict::DEALING,//初始态。 系统转账校验中
  512. // 'WAIT_PAY' => TransferDict::DEALING,
  513. // 'PROCESSING' => TransferDict::DEALING,
  514. // 'FAIL' => TransferDict::FAIL,
  515. // 'SUCCESS' => TransferDict::SUCCESS,
  516. // ];
  517. return [
  518. 'status' => $tran_status_list[$result['state']],
  519. 'transfer_no' => $transfer_no,
  520. 'reason' => $result['fail_reason'] ?? '',
  521. 'out_bill_no' => $result['out_bill_no'] ?? '',
  522. 'transfer_bill_no' => $result['transfer_bill_no'] ?? ''
  523. ];
  524. }catch(Throwable $e){
  525. return [
  526. 'status' => TransferDict::DEALING,
  527. 'transfer_no' => $transfer_no,
  528. 'reason' => $e->getMessage(),
  529. ];
  530. }
  531. }
  532. /**
  533. * 转账取消
  534. * @param array $params
  535. * @return array
  536. */
  537. public function transferCancel(array $params)
  538. {
  539. if(empty($this->config['mch_id']) || empty($this->config['mch_secret_key']) || empty($this->config['mch_secret_cert']) || empty($this->config['mch_public_cert_path'])){
  540. throw new PayException('WECHAT_TRANSFER_CONFIG_NOT_EXIST');
  541. }
  542. $transfer_no = $params['transfer_no'] ?? '';
  543. $tran_status_list = [
  544. 'CANCELING' => TransferDict::FAIL_ING,
  545. 'CANCELLED' => TransferDict::FAIL,
  546. ];
  547. $order = [
  548. '_action' => 'cancel', // 微信官方老版本下线后,此部分可省略
  549. 'out_bill_no' => $transfer_no,
  550. 'notify_url' => $this->config['notify_url'],
  551. ];
  552. try {
  553. $allPlugins = Pay::wechat()->mergeCommonPlugins([CancelPlugin::class]);
  554. $result = Pay::wechat()->pay($allPlugins, $order);
  555. // $result = $this->returnFormat(Pay::wechat()->transfer($order));
  556. if (!empty($result['code'])) {
  557. //
  558. if ($result['code'] == 'INVALID_REQUEST') {
  559. throw new PayException(700010);
  560. }
  561. throw new PayException($result['message']);
  562. }
  563. return ['out_bill_no' => $result['out_bill_no'], 'transfer_bill_no' => $result['transfer_bill_no'], 'status' => $tran_status_list[$result['state']]];
  564. } catch (\Exception $e) {
  565. if ($e instanceof InvalidResponseException) {
  566. throw new PayException($e->response->all()['message'] ?? '');
  567. }
  568. throw new PayException($e->getMessage());
  569. }
  570. }
  571. public function fail($message = '')
  572. {
  573. $response = [
  574. 'code' => 'FAIL',
  575. 'message' => $message ?: '失败',
  576. ];
  577. return response($response, 400, [], 'json');
  578. }
  579. }