diff --git a/src/addon/huaweipay/config/diy_view.php b/src/addon/huaweipay/config/diy_view.php
new file mode 100644
index 000000000..0c5d86650
--- /dev/null
+++ b/src/addon/huaweipay/config/diy_view.php
@@ -0,0 +1,33 @@
+ '页面类型名称', 'name' => '页面标识', 'path' => '页面路径', 'value' => '页面数据,json格式' ]
+ 'template' => [],
+
+ // 后台自定义组件——装修
+ 'util' => [],
+
+ // 自定义页面路径
+ 'link' => [],
+
+ // 自定义图标库
+ 'icon_library' => [],
+
+ // uni-app 组件,格式:[ 'name' => '组件名称/文件夹名称', 'path' => '文件路径/目录路径' ],多个逗号隔开,自定义组件名称前缀必须是diy-,也可以引用第三方组件
+ 'component' => [],
+
+ // uni-app 页面,多个逗号隔开
+ 'pages' => [],
+
+ // 模板信息,格式:'title' => '模板名称', 'name' => '模板标识', 'cover' => '模板封面图', 'preview' => '模板预览图', 'desc' => '模板描述'
+ 'info' => [],
+
+ // 主题风格配色,格式可以自由定义扩展,【在uni-app中通过:this.themeStyle... 获取定义的颜色字段,例如:this.themeStyle.main_color】
+ 'theme' => [],
+
+ // 自定义页面数据,格式:[ 'title' => '页面名称', 'name' => "页面标识", 'value' => [页面数据,json格式] ]
+ 'data' => []
+];
diff --git a/src/addon/huaweipay/config/event.php b/src/addon/huaweipay/config/event.php
new file mode 100644
index 000000000..a18ada701
--- /dev/null
+++ b/src/addon/huaweipay/config/event.php
@@ -0,0 +1,45 @@
+ [
+
+ ],
+
+ 'listen' => [
+ //支付异步回调
+ 'PayNotify' => [
+ 'addon\huaweipay\event\PayNotify'
+ ],
+ //支付方式,后台查询
+ 'PayType' => [
+ 'addon\huaweipay\event\PayType'
+ ],
+ //支付,前台应用
+ 'Pay' => [
+ 'addon\huaweipay\event\Pay'
+ ],
+ 'PayClose' => [
+ 'addon\huaweipay\event\PayClose'
+ ],
+ 'PayRefund' => [
+ 'addon\huaweipay\event\PayRefund'
+ ],
+ 'PayTransfer' => [
+ 'addon\huaweipay\event\PayTransfer'
+ ],
+ 'TransferType' => [
+ 'addon\huaweipay\event\TransferType'
+ ],
+ 'AuthcodePay' => [
+ 'addon\huaweipay\event\AuthcodePay'
+ ],
+ 'PayOrderQuery' => [
+ 'addon\huaweipay\event\PayOrderQuery'
+ ],
+ ],
+
+ 'subscribe' => [
+ ],
+];
diff --git a/src/addon/huaweipay/config/info.php b/src/addon/huaweipay/config/info.php
new file mode 100644
index 000000000..96ac182f8
--- /dev/null
+++ b/src/addon/huaweipay/config/info.php
@@ -0,0 +1,15 @@
+ 'huaweipay',
+ 'title' => '华为支付',
+ 'description' => '华为支付功能',
+ 'type' => 'system', //插件类型 system :系统插件(自动安装), business:业务插件 promotion:扩展营销插件 tool:工具插件
+ 'status' => 1,
+ 'author' => '',
+ 'version' => '5.3.1',
+ 'version_no' => '525231212001',
+ 'content' => '',
+];
diff --git a/src/addon/huaweipay/config/menu_shop.php b/src/addon/huaweipay/config/menu_shop.php
new file mode 100644
index 000000000..2a2c18eba
--- /dev/null
+++ b/src/addon/huaweipay/config/menu_shop.php
@@ -0,0 +1,18 @@
+ 'HUAWEI_PAY_CONFIG',
+ 'title' => '华为支付编辑',
+ 'url' => 'huaweipay://shop/pay/config',
+ 'parent' => 'CONFIG_PAY',
+ 'is_show' => 0,
+ 'is_control' => 1,
+ 'is_icon' => 0,
+ 'picture' => '',
+ 'picture_select' => '',
+ 'sort' => 1,
+ ],
+];
diff --git a/src/addon/huaweipay/data/sdk/HuaweiPayClient.php b/src/addon/huaweipay/data/sdk/HuaweiPayClient.php
new file mode 100644
index 000000000..6e4bf3e9f
--- /dev/null
+++ b/src/addon/huaweipay/data/sdk/HuaweiPayClient.php
@@ -0,0 +1,291 @@
+config = $config;
+
+ // 根据配置设置网关地址
+ if (isset($config['sandbox']) && $config['sandbox']) {
+ $this->gatewayUrl = 'https://pay-drcn.cloud.huawei.com/gateway/api/pay';
+ }
+ }
+
+ /**
+ * 生成签名
+ * @param array $params 请求参数
+ * @return string 签名结果
+ */
+ private function generateSign($params)
+ {
+ // 移除空值和签名参数
+ $params = array_filter($params, function($value) {
+ return $value !== null && $value !== '';
+ });
+ unset($params['sign']);
+ unset($params['sign_type']);
+
+ // 按键名排序
+ ksort($params);
+
+ // 拼接参数
+ $stringToSign = '';
+ foreach ($params as $key => $value) {
+ $stringToSign .= $key . '=' . $value . '&';
+ }
+ $stringToSign = rtrim($stringToSign, '&');
+
+ // 根据签名类型生成签名
+ switch ($this->signType) {
+ case 'RSA2':
+ $privateKey = $this->config['private_key'];
+ $privateKey = "-----BEGIN PRIVATE KEY-----\n" . wordwrap($privateKey, 64, "\n", true) . "\n-----END PRIVATE KEY-----";
+ openssl_sign($stringToSign, $sign, $privateKey, OPENSSL_ALGO_SHA256);
+ break;
+ case 'RSA':
+ $privateKey = $this->config['private_key'];
+ $privateKey = "-----BEGIN PRIVATE KEY-----\n" . wordwrap($privateKey, 64, "\n", true) . "\n-----END PRIVATE KEY-----";
+ openssl_sign($stringToSign, $sign, $privateKey, OPENSSL_ALGO_SHA1);
+ break;
+ default:
+ throw new \Exception('不支持的签名类型');
+ }
+
+ return base64_encode($sign);
+ }
+
+ /**
+ * 验证签名
+ * @param array $params 响应参数
+ * @return bool 验证结果
+ */
+ public function verifySign($params)
+ {
+ // 保存签名
+ $sign = $params['sign'] ?? '';
+ unset($params['sign']);
+ unset($params['sign_type']);
+
+ // 移除空值
+ $params = array_filter($params, function($value) {
+ return $value !== null && $value !== '';
+ });
+
+ // 按键名排序
+ ksort($params);
+
+ // 拼接参数
+ $stringToSign = '';
+ foreach ($params as $key => $value) {
+ $stringToSign .= $key . '=' . $value . '&';
+ }
+ $stringToSign = rtrim($stringToSign, '&');
+
+ // 验证签名
+ $huaweiPublicKey = $this->config['huawei_public_key'];
+ $huaweiPublicKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($huaweiPublicKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
+
+ switch ($this->signType) {
+ case 'RSA2':
+ $result = openssl_verify($stringToSign, base64_decode($sign), $huaweiPublicKey, OPENSSL_ALGO_SHA256);
+ break;
+ case 'RSA':
+ $result = openssl_verify($stringToSign, base64_decode($sign), $huaweiPublicKey, OPENSSL_ALGO_SHA1);
+ break;
+ default:
+ throw new \Exception('不支持的签名类型');
+ }
+
+ return $result === 1;
+ }
+
+ /**
+ * 发送HTTP请求
+ * @param string $url 请求地址
+ * @param array $params 请求参数
+ * @param string $method 请求方法
+ * @return array 响应结果
+ */
+ private function httpRequest($url, $params, $method = 'POST')
+ {
+ $ch = curl_init();
+
+ // 设置请求头
+ $headers = [
+ 'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
+ ];
+
+ // 生成签名
+ $params['app_id'] = $this->config['app_id'];
+ $params['sign_type'] = $this->signType;
+ $params['sign'] = $this->generateSign($params);
+
+ if ($method === 'POST') {
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
+ } else {
+ $url .= '?' . http_build_query($params);
+ }
+
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+
+ $response = curl_exec($ch);
+
+ if (curl_errno($ch)) {
+ throw new \Exception('HTTP请求错误: ' . curl_error($ch));
+ }
+
+ curl_close($ch);
+
+ // 解析响应
+ parse_str($response, $result);
+
+ return $result;
+ }
+
+ /**
+ * H5支付
+ * @param array $params 支付参数
+ * @param string $returnUrl 同步回调地址
+ * @param string $notifyUrl 异步回调地址
+ * @return array 支付结果
+ */
+ public function h5Pay($params, $returnUrl, $notifyUrl)
+ {
+ $requestParams = [
+ 'method' => 'h5pay.createPayment',
+ 'version' => '1.0',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'out_trade_no' => $params['out_trade_no'],
+ 'subject' => $params['subject'],
+ 'total_amount' => $params['total_amount'],
+ 'body' => $params['body'],
+ 'return_url' => $returnUrl,
+ 'notify_url' => $notifyUrl,
+ 'scene' => 'h5',
+ ];
+
+ return $this->httpRequest($this->gatewayUrl, $requestParams);
+ }
+
+ /**
+ * APP支付
+ * @param array $params 支付参数
+ * @param string $notifyUrl 异步回调地址
+ * @return array 支付结果
+ */
+ public function appPay($params, $notifyUrl)
+ {
+ $requestParams = [
+ 'method' => 'apppay.createPayment',
+ 'version' => '1.0',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'out_trade_no' => $params['out_trade_no'],
+ 'subject' => $params['subject'],
+ 'total_amount' => $params['total_amount'],
+ 'body' => $params['body'],
+ 'notify_url' => $notifyUrl,
+ ];
+
+ return $this->httpRequest($this->gatewayUrl, $requestParams);
+ }
+
+ /**
+ * 查询订单
+ * @param array $params 查询参数
+ * @return array 查询结果
+ */
+ public function queryOrder($params)
+ {
+ $requestParams = [
+ 'method' => 'unifiedorder.query',
+ 'version' => '1.0',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ ];
+
+ // 支持通过商户订单号或华为交易号查询
+ if (isset($params['out_trade_no'])) {
+ $requestParams['out_trade_no'] = $params['out_trade_no'];
+ } elseif (isset($params['trade_no'])) {
+ $requestParams['trade_no'] = $params['trade_no'];
+ } else {
+ throw new \Exception('查询参数错误,必须提供out_trade_no或trade_no');
+ }
+
+ return $this->httpRequest($this->gatewayUrl, $requestParams);
+ }
+
+ /**
+ * 关闭订单
+ * @param array $params 关闭参数
+ * @return array 关闭结果
+ */
+ public function closeOrder($params)
+ {
+ $requestParams = [
+ 'method' => 'unifiedorder.close',
+ 'version' => '1.0',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'out_trade_no' => $params['out_trade_no'],
+ ];
+
+ return $this->httpRequest($this->gatewayUrl, $requestParams);
+ }
+
+ /**
+ * 退款
+ * @param array $params 退款参数
+ * @return array 退款结果
+ */
+ public function refund($params)
+ {
+ $requestParams = [
+ 'method' => 'refund.apply',
+ 'version' => '1.0',
+ 'timestamp' => date('Y-m-d H:i:s'),
+ 'out_trade_no' => $params['out_trade_no'],
+ 'trade_no' => $params['trade_no'],
+ 'refund_amount' => $params['refund_amount'],
+ 'out_request_no' => $params['out_request_no'],
+ 'refund_reason' => $params['refund_reason'] ?? '',
+ ];
+
+ return $this->httpRequest($this->gatewayUrl, $requestParams);
+ }
+
+ /**
+ * 验证回调签名
+ * @param array $params 回调参数
+ * @return bool 验证结果
+ */
+ public function verifyNotify($params)
+ {
+ return $this->verifySign($params);
+ }
+}
diff --git a/src/addon/huaweipay/event/AuthcodePay.php b/src/addon/huaweipay/event/AuthcodePay.php
new file mode 100644
index 000000000..126d9c665
--- /dev/null
+++ b/src/addon/huaweipay/event/AuthcodePay.php
@@ -0,0 +1,26 @@
+authcodePay($param);
+ return $res;
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/Pay.php b/src/addon/huaweipay/event/Pay.php
new file mode 100644
index 000000000..f409ede05
--- /dev/null
+++ b/src/addon/huaweipay/event/Pay.php
@@ -0,0 +1,28 @@
+pay($param);
+ return $res;
+ }
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/PayClose.php b/src/addon/huaweipay/event/PayClose.php
new file mode 100644
index 000000000..e64cbb86b
--- /dev/null
+++ b/src/addon/huaweipay/event/PayClose.php
@@ -0,0 +1,26 @@
+close($param);
+ return $res;
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/PayNotify.php b/src/addon/huaweipay/event/PayNotify.php
new file mode 100644
index 000000000..0d19202b6
--- /dev/null
+++ b/src/addon/huaweipay/event/PayNotify.php
@@ -0,0 +1,26 @@
+notify($param);
+ return $res;
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/PayOrderQuery.php b/src/addon/huaweipay/event/PayOrderQuery.php
new file mode 100644
index 000000000..e689e39e5
--- /dev/null
+++ b/src/addon/huaweipay/event/PayOrderQuery.php
@@ -0,0 +1,26 @@
+query($param);
+ return $res;
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/PayRefund.php b/src/addon/huaweipay/event/PayRefund.php
new file mode 100644
index 000000000..0484a075e
--- /dev/null
+++ b/src/addon/huaweipay/event/PayRefund.php
@@ -0,0 +1,26 @@
+refund($param);
+ return $res;
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/PayTransfer.php b/src/addon/huaweipay/event/PayTransfer.php
new file mode 100644
index 000000000..ec11831cb
--- /dev/null
+++ b/src/addon/huaweipay/event/PayTransfer.php
@@ -0,0 +1,26 @@
+transfer($param);
+ return $res;
+ }
+ }
+}
diff --git a/src/addon/huaweipay/event/PayType.php b/src/addon/huaweipay/event/PayType.php
new file mode 100644
index 000000000..b44f66d02
--- /dev/null
+++ b/src/addon/huaweipay/event/PayType.php
@@ -0,0 +1,44 @@
+getPayConfig($param[ 'site_id' ]);
+ $config = $config_result[ "data" ][ "value" ] ?? [];
+ $pay_status = $config[ "pay_status" ] ?? 0;
+ if ($pay_status == 0) {
+ return '';
+ }
+ }
+ $info = array (
+ "pay_type" => "huaweipay",
+ "pay_type_name" => "华为支付",
+ "edit_url" => "huaweipay://shop/pay/config",
+ "shop_url" => "huaweipay://shop/pay/config",
+ "logo" => "addon/huaweipay/icon.png",
+ "desc" => "华为支付(www.huawei.com) 是华为公司提供的网上支付平台。"
+ );
+ return $info;
+ }
+}
diff --git a/src/addon/huaweipay/event/TransferType.php b/src/addon/huaweipay/event/TransferType.php
new file mode 100644
index 000000000..6c5ce03c0
--- /dev/null
+++ b/src/addon/huaweipay/event/TransferType.php
@@ -0,0 +1,25 @@
+ "huaweipay",
+ "pay_type_name" => "华为支付",
+ "logo" => "addon/huaweipay/icon.png",
+ );
+ return $info;
+ }
+}
diff --git a/src/addon/huaweipay/icon.png b/src/addon/huaweipay/icon.png
new file mode 100644
index 000000000..a676d699d
Binary files /dev/null and b/src/addon/huaweipay/icon.png differ
diff --git a/src/addon/huaweipay/model/Config.php b/src/addon/huaweipay/model/Config.php
new file mode 100644
index 000000000..cedc099a7
--- /dev/null
+++ b/src/addon/huaweipay/model/Config.php
@@ -0,0 +1,79 @@
+getPayConfig($site_id)[ 'data' ][ 'value' ] ?? [];
+
+ // 检测数据是否发生变化,如果没有变化,则保持未加密前的数据
+ if (!empty($data[ 'app_id' ]) && $data[ 'app_id' ] == $this->encrypt) {
+ $data[ 'app_id' ] = $original_config[ 'app_id' ]; // 应用ID
+ }
+ if (!empty($data[ 'private_key' ]) && $data[ 'private_key' ] == $this->encrypt) {
+ $data[ 'private_key' ] = $original_config[ 'private_key' ]; // 应用私钥
+ }
+ if (!empty($data[ 'public_key' ]) && $data[ 'public_key' ] == $this->encrypt) {
+ $data[ 'public_key' ] = $original_config[ 'public_key' ]; // 应用公钥
+ }
+ if (!empty($data[ 'huawei_public_key' ]) && $data[ 'huawei_public_key' ] == $this->encrypt) {
+ $data[ 'huawei_public_key' ] = $original_config[ 'huawei_public_key' ]; // 华为公钥
+ }
+
+ $res = $config->setConfig($data, '华为支付配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'HUAWEI_PAY_CONFIG' ] ]);
+ return $res;
+ }
+
+ /**
+ * 获取支付配置
+ * @param int $site_id
+ * @param string $app_module
+ * @param bool $need_encrypt 是否需要加密数据,true:加密、false:不加密
+ * @return array
+ */
+ public function getPayConfig($site_id = 0, $app_module = 'shop', $need_encrypt = false)
+ {
+ $config = new ConfigModel();
+ $res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'HUAWEI_PAY_CONFIG' ] ]);
+ if ($need_encrypt) {
+ // 加密敏感信息
+ if (!empty($res[ 'data' ][ 'value' ][ 'app_id' ])) {
+ $res[ 'data' ][ 'value' ][ 'app_id' ] = $this->encrypt; // 应用ID
+ }
+ if (!empty($res[ 'data' ][ 'value' ][ 'private_key' ])) {
+ $res[ 'data' ][ 'value' ][ 'private_key' ] = $this->encrypt; // 应用私钥
+ }
+ if (!empty($res[ 'data' ][ 'value' ][ 'public_key' ])) {
+ $res[ 'data' ][ 'value' ][ 'public_key' ] = $this->encrypt; // 应用公钥
+ }
+ if (!empty($res[ 'data' ][ 'value' ][ 'huawei_public_key' ])) {
+ $res[ 'data' ][ 'value' ][ 'huawei_public_key' ] = $this->encrypt; // 华为公钥
+ }
+ }
+ return $res;
+ }
+}
diff --git a/src/addon/huaweipay/model/Pay.php b/src/addon/huaweipay/model/Pay.php
new file mode 100644
index 000000000..f90c69a2a
--- /dev/null
+++ b/src/addon/huaweipay/model/Pay.php
@@ -0,0 +1,252 @@
+getPayConfig($site_id)['data']['value'];
+
+ if (!empty($config_info)) {
+ // 初始化华为支付客户端
+ $this->hwpay_client = new HuaweiPayClient($config_info);
+ }
+ } catch (\Exception $e) {
+ return $this->error('', '华为支付配置错误: ' . $e->getMessage());
+ }
+ }
+
+ /**
+ * 生成支付
+ * @param $param 支付参数
+ * @return array
+ */
+ public function pay($param)
+ {
+ try {
+ // 构造华为支付请求参数
+ $parameter = array(
+ "out_trade_no" => $param["out_trade_no"],
+ "subject" => substr($param["pay_body"], 0, 15),
+ "total_amount" => (float)$param["pay_money"],
+ "body" => substr($param["pay_body"], 0, 60),
+ );
+
+ // 绑定商户数据
+ $pay_model = new PayModel();
+ $pay_model->bindMchPay($param["out_trade_no"], []);
+
+ // 根据不同的应用类型调用不同的华为支付API
+ switch ($param["app_type"]) {
+ case "h5":
+ // H5支付
+ $result = $this->hwpay_client->h5Pay($parameter, $param["return_url"], $param["notify_url"]);
+ if ($result['code'] == '0') {
+ return $this->success([
+ 'type' => 'url',
+ 'data' => $result['pay_url']
+ ]);
+ } else {
+ return $this->error('', $result['msg'] ?? '华为支付请求失败');
+ }
+ break;
+ case "app":
+ // APP支付
+ $result = $this->hwpay_client->appPay($parameter, $param["notify_url"]);
+ if ($result['code'] == '0') {
+ return $this->success([
+ 'type' => 'params',
+ 'data' => $result
+ ]);
+ } else {
+ return $this->error('', $result['msg'] ?? '华为支付请求失败');
+ }
+ break;
+ default:
+ // 默认返回错误
+ return $this->error('', '不支持的支付类型');
+ }
+ } catch (\Exception $e) {
+ Log::error('华为支付生成支付失败: ' . $e->getMessage());
+ return $this->error('', $e->getMessage());
+ }
+ }
+
+ /**
+ * 支付关闭
+ * @param $param 关闭订单参数
+ * @return array
+ */
+ public function close($param)
+ {
+ try {
+ $parameter = array(
+ "out_trade_no" => $param["out_trade_no"]
+ );
+
+ // 调用华为支付关闭订单API
+ $result = $this->hwpay_client->closeOrder($parameter);
+
+ if ($result['code'] == '0') {
+ return $this->success();
+ } else {
+ return $this->error('', $result['msg'] ?? '关闭订单失败');
+ }
+ } catch (\Exception $e) {
+ Log::error('华为支付关闭订单失败: ' . $e->getMessage());
+ return $this->error('', $e->getMessage());
+ }
+ }
+
+ /**
+ * 华为支付退款
+ * @param array $param 退款参数
+ * @return array
+ */
+ public function refund($param)
+ {
+ try {
+ $pay_info = $param["pay_info"];
+ $refund_no = $param["refund_no"];
+ $out_trade_no = $pay_info["out_trade_no"] ?? '';
+ $trade_no = $pay_info["trade_no"] ?? '';
+ $refund_fee = $param["refund_fee"];
+
+ $parameter = array(
+ 'out_trade_no' => $out_trade_no,
+ 'trade_no' => $trade_no,
+ 'refund_amount' => sprintf("%.2f", $refund_fee),
+ 'out_request_no' => $refund_no,
+ 'refund_reason' => $param["refund_desc"] ?? ''
+ );
+
+ // 调用华为支付退款API
+ $result = $this->hwpay_client->refund($parameter);
+
+ if ($result['code'] == '0') {
+ return $this->success();
+ } else {
+ return $this->error('', $result['msg'] ?? '退款失败');
+ }
+ } catch (\Exception $e) {
+ Log::error('华为支付退款失败: ' . $e->getMessage());
+ return $this->error('', $e->getMessage());
+ }
+ }
+
+ /**
+ * 华为支付转账
+ * @param $param 转账参数
+ * @return array
+ */
+ public function transfer($param)
+ {
+ try {
+ // 华为支付转账功能需要根据实际API进行实现
+ // 目前华为支付客户端未实现转账功能,需要根据官方文档扩展
+ return $this->error('', '华为支付转账功能暂未实现');
+ } catch (\Exception $e) {
+ Log::error('华为支付转账失败: ' . $e->getMessage());
+ return $this->error('', $e->getMessage());
+ }
+ }
+
+ /**
+ * 异步完成支付
+ * @param $param 回调参数
+ */
+ public function notify($param)
+ {
+ try {
+ // 验证华为支付回调签名
+ $is_valid = $this->hwpay_client->verifyNotify($param);
+
+ if ($is_valid) { // 验证成功
+ $out_trade_no = $param['out_trade_no'];
+ // 华为支付交易号
+ $trade_no = $param['trade_no'];
+ // 交易状态
+ $trade_status = $param['trade_status'];
+ $pay_common = new PayCommon();
+
+ if ($trade_status == "TRADE_SUCCESS") {
+ $retval = $pay_common->onlinePay($out_trade_no, "huaweipay", $trade_no, "huaweipay");
+ }
+ echo "success";
+ } else {
+ // 验证失败
+ Log::error('华为支付回调签名验证失败: ' . json_encode($param));
+ echo "fail";
+ }
+ } catch (\Exception $e) {
+ Log::error('华为支付回调处理失败: ' . $e->getMessage());
+ echo "fail";
+ }
+ }
+
+ /**
+ * 授权码支付
+ * @param $param 授权码支付参数
+ * @return array|mixed|void
+ */
+ public function authcodePay($param)
+ {
+ try {
+ // 华为支付授权码支付功能需要根据实际API进行实现
+ // 目前华为支付客户端未实现授权码支付功能,需要根据官方文档扩展
+ return $this->error('', '华为支付授权码支付功能暂未实现');
+ } catch (\Exception $e) {
+ Log::error('华为支付授权码支付失败: ' . $e->getMessage());
+ return $this->error('', $e->getMessage());
+ }
+ }
+
+ /**
+ * 查询订单信息
+ * @param $param 查询参数
+ * @return array
+ */
+ public function query($param)
+ {
+ try {
+ // 构造查询请求参数
+ $parameter = array(
+ "out_trade_no" => $param["out_trade_no"],
+ );
+
+ // 调用华为支付查询订单API
+ $result = $this->hwpay_client->queryOrder($parameter);
+
+ if ($result['code'] == '0') {
+ return $this->success($result['data']);
+ } else {
+ return $this->error('', $result['msg'] ?? '查询订单失败');
+ }
+ } catch (\Exception $e) {
+ Log::error('华为支付查询订单失败: ' . $e->getMessage());
+ return $this->error('', $e->getMessage());
+ }
+ }
+}
diff --git a/src/addon/huaweipay/shop/controller/Pay.php b/src/addon/huaweipay/shop/controller/Pay.php
new file mode 100644
index 000000000..296f634f8
--- /dev/null
+++ b/src/addon/huaweipay/shop/controller/Pay.php
@@ -0,0 +1,82 @@
+isJson()) {
+ $app_id = input("app_id", "");//华为应用ID, // PETALPAY.APPID, 商户号关联的APPID
+ $mch_id = input("mch_id", "");//商户号, // PETALPAY.MERC_NO, 商户号
+ $private_key = input("private_key", "");//商户应用私钥, // PETALPAY.MERC_PRIVATE_KEY, 商户应用私钥
+ $mch_auth_id = input("mch_auth_id", "");//商户证书id, // PETALPAY.MERC_AUTH_ID, 商户证书id
+ $sign_type = input("sign_type", "RSA");//商户公私钥签名类型, // PETALPAY.SIGN_TYPE, 签名类型, 默认使用RSA
+ $huawei_public_key = input("huawei_public_key", ""); //华为公钥, // PETALPAY.HW_PAY_PUBLIC_KEY_FOR_CALLBACK, 华为公钥
+ $app_type = input("app_type", "");//支持端口 如web app
+ $pay_status = input("pay_status", 0);//支付启用状态
+ $refund_status = input("refund_status", 0);//退款启用状态
+ $transfer_status = input("transfer_status", 0);//转账启用状态
+
+ $data = array (
+ "app_id" => $app_id,
+ "mch_id" => $mch_id,
+ "private_key" => $private_key,
+ "mch_auth_id" => $mch_auth_id,
+ "sign_type" => $sign_type,
+ "huawei_public_key" => $huawei_public_key,
+ "refund_status" => $refund_status,
+ "pay_status" => $pay_status,
+ "transfer_status" => $transfer_status,
+ "app_type" => $app_type
+ );
+ $result = $config_model->setPayConfig($data, $this->site_id, $this->app_module);
+ return $result;
+ } else {
+ $info = $config_model->getPayConfig($this->site_id, $this->app_module, true)[ 'data' ][ 'value' ] ?? [];
+
+ if (!empty($info)) {
+ $app_type_arr = [];
+ if (!empty($info[ 'app_type' ])) {
+ $app_type_arr = explode(',', $info[ 'app_type' ]);
+ }
+ $info[ 'app_type_arr' ] = $app_type_arr;
+ }
+ $this->assign("info", $info);
+ $this->assign("app_type", Config::get("app_type"));
+
+ return $this->fetch("pay/config");
+ }
+ }
+
+ /**
+ * 上传华为支付证书
+ */
+ public function uploadHuaweiCrt()
+ {
+ $upload_model = new Upload();
+ $site_id = request()->siteid();
+ $name = input("name", "");
+ $extend_type = [ 'crt', 'pem' ];
+ $param = array (
+ "name" => "file",
+ "extend_type" => $extend_type
+ );
+
+ $site_id = max($site_id, 0);
+ $result = $upload_model->setPath("common/huaweipay/crt/" . $site_id . "/")->file($param);
+ return $result;
+ }
+}
diff --git a/src/addon/huaweipay/shop/view/pay/config.html b/src/addon/huaweipay/shop/view/pay/config.html
new file mode 100644
index 000000000..0d8b5537b
--- /dev/null
+++ b/src/addon/huaweipay/shop/view/pay/config.html
@@ -0,0 +1,219 @@
+
+
+
+
+
diff --git a/src/addon/offlinepay/api/controller/Pay.php b/src/addon/offlinepay/api/controller/Pay.php
new file mode 100644
index 000000000..092a2536b
--- /dev/null
+++ b/src/addon/offlinepay/api/controller/Pay.php
@@ -0,0 +1,71 @@
+getPayConfig($this->site_id);
+ return $this->response($res);
+ }
+
+ /**
+ * 信息
+ */
+ public function info()
+ {
+ $token = $this->checkToken();
+ if ($token[ 'code' ] < 0) return $this->response($token);
+
+ $out_trade_no = $this->params['out_trade_no'] ?? '';
+ $pay_model = new PayModel();
+ $res = $pay_model->getInfo([['out_trade_no', '=', $out_trade_no], ['member_id', '=', $this->member_id]]);
+ return $this->response($res);
+ }
+
+ /**
+ * 支付
+ */
+ public function pay()
+ {
+ $token = $this->checkToken();
+ if ($token[ 'code' ] < 0) return $this->response($token);
+
+ $pay_model = new PayModel();
+ $res = $pay_model->pay([
+ 'member_id' => $this->member_id,
+ 'out_trade_no' => $this->params['out_trade_no'] ?? '',
+ 'imgs' => $this->params['imgs'] ?? '',
+ 'desc' => $this->params['desc'] ?? ''
+ ]);
+ return $this->response($res);
+ }
+
+ /**
+ * 图片上传
+ */
+ public function uploadImg()
+ {
+ $upload_model = new UploadModel(0);
+ $param = [
+ 'thumb_type' => '',
+ 'name' => 'file',
+ 'cloud' => 1,
+ ];
+ $result = $upload_model->setPath('offlinepay/' . date('Ymd') . '/')->image($param);
+ return $this->response($result);
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/config/diy_view.php b/src/addon/offlinepay/config/diy_view.php
new file mode 100644
index 000000000..e36ca9b7d
--- /dev/null
+++ b/src/addon/offlinepay/config/diy_view.php
@@ -0,0 +1,30 @@
+ '页面类型名称', 'name' => '页面标识', 'path' => '页面路径', 'value' => '页面数据,json格式' ]
+ 'template' => [],
+
+ // 后台自定义组件——装修
+ 'util' => [],
+
+ // 自定义页面路径
+ 'link' => [],
+
+ // 自定义图标库
+ 'icon_library' => [],
+
+ // uni-app 组件,格式:[ 'name' => '组件名称/文件夹名称', 'path' => '文件路径/目录路径' ],多个逗号隔开,自定义组件名称前缀必须是diy-,也可以引用第三方组件
+ 'component' => [],
+
+ // uni-app 页面,多个逗号隔开
+ 'pages' => [],
+
+ // 模板信息,格式:'title' => '模板名称', 'name' => '模板标识', 'cover' => '模板封面图', 'preview' => '模板预览图', 'desc' => '模板描述'
+ 'info' => [],
+
+ // 主题风格配色,格式可以自由定义扩展,【在uni-app中通过:this.themeStyle... 获取定义的颜色字段,例如:this.themeStyle.main_color】
+ 'theme' => [],
+
+ // 自定义页面数据,格式:[ 'title' => '页面名称', 'name' => "页面标识", 'value' => [页面数据,json格式] ]
+ 'data' => []
+];
\ No newline at end of file
diff --git a/src/addon/offlinepay/config/event.php b/src/addon/offlinepay/config/event.php
new file mode 100644
index 000000000..e6ecfb2f8
--- /dev/null
+++ b/src/addon/offlinepay/config/event.php
@@ -0,0 +1,30 @@
+ [
+
+ ],
+
+ 'listen' => [
+ //支付方式,后台查询
+ 'PayType' => [
+ 'addon\offlinepay\event\PayType'
+ ],
+ 'Pay' => [
+ 'addon\offlinepay\event\Pay'
+ ],
+ 'PayClose' => [
+ 'addon\offlinepay\event\PayClose'
+ ],
+ 'PayRefund' => [
+ 'addon\offlinepay\event\PayRefund'
+ ],
+ 'SendMessageTemplate' => [
+ 'addon\offlinepay\event\MessageOfflinepayWaitAudit',
+ 'addon\offlinepay\event\MessageOfflinepayAuditRefuse',
+ ],
+ ],
+
+ 'subscribe' => [
+ ],
+];
diff --git a/src/addon/offlinepay/config/info.php b/src/addon/offlinepay/config/info.php
new file mode 100644
index 000000000..a8f8555a0
--- /dev/null
+++ b/src/addon/offlinepay/config/info.php
@@ -0,0 +1,12 @@
+ 'offlinepay',
+ 'title' => '线下支付',
+ 'description' => '线下支付功能',
+ 'type' => 'system', //插件类型 system :系统插件(自动安装), business:业务插件 promotion:扩展营销插件 tool:工具插件
+ 'status' => 1,
+ 'author' => '',
+ 'version' => '5.5.2',
+ 'version_no' => '552250604001',
+ 'content' => '',
+];
\ No newline at end of file
diff --git a/src/addon/offlinepay/config/menu_shop.php b/src/addon/offlinepay/config/menu_shop.php
new file mode 100644
index 000000000..947859243
--- /dev/null
+++ b/src/addon/offlinepay/config/menu_shop.php
@@ -0,0 +1,49 @@
+ 'OFFLINE_PAY_CONFIG',
+ 'title' => '线下支付编辑',
+ 'url' => 'offlinepay://shop/pay/config',
+ 'parent' => 'CONFIG_PAY',
+ 'is_show' => 0,
+ 'is_control' => 1,
+ 'is_icon' => 0,
+ 'sort' => 1,
+ 'type' => 'button',
+ ],
+ [
+ 'name' => 'OFFLINE_PAY_LIST',
+ 'title' => '线下支付',
+ 'url' => 'offlinepay://shop/pay/lists',
+ 'parent' => 'ORDER_MANAGE',
+ 'is_show' => 1,
+ 'is_control' => 1,
+ 'is_icon' => 0,
+ 'sort' => 8,
+ 'child_list' => [
+ [
+ 'name' => 'OFFLINE_PAY_AUDIT_PASS',
+ 'title' => '审核通过',
+ 'url' => 'offlinepay://shop/pay/auditpass',
+ 'is_show' => 0,
+ 'is_control' => 1,
+ 'is_icon' => 0,
+ 'sort' => 1,
+ 'type' => 'button',
+ ],
+ [
+ 'name' => 'OFFLINE_PAY_AUDIT_REFUSE',
+ 'title' => '审核拒绝',
+ 'url' => 'offlinepay://shop/pay/auditrefuse',
+ 'is_show' => 0,
+ 'is_control' => 1,
+ 'is_icon' => 0,
+ 'sort' => 2,
+ 'type' => 'button',
+ ],
+ ]
+ ],
+];
diff --git a/src/addon/offlinepay/event/Install.php b/src/addon/offlinepay/event/Install.php
new file mode 100644
index 000000000..f55504021
--- /dev/null
+++ b/src/addon/offlinepay/event/Install.php
@@ -0,0 +1,17 @@
+messageAuditRefuse($param);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/event/MessageOfflinepayWaitAudit.php b/src/addon/offlinepay/event/MessageOfflinepayWaitAudit.php
new file mode 100644
index 000000000..0fc2678dd
--- /dev/null
+++ b/src/addon/offlinepay/event/MessageOfflinepayWaitAudit.php
@@ -0,0 +1,16 @@
+messageWaitAudit($param);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/event/Pay.php b/src/addon/offlinepay/event/Pay.php
new file mode 100644
index 000000000..6935069e3
--- /dev/null
+++ b/src/addon/offlinepay/event/Pay.php
@@ -0,0 +1,24 @@
+clearMchPay($params[ "out_trade_no" ], 'offlinepay');
+ if($clear_res['code'] < 0) return $clear_res;
+ return success();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/event/PayClose.php b/src/addon/offlinepay/event/PayClose.php
new file mode 100644
index 000000000..42b14820b
--- /dev/null
+++ b/src/addon/offlinepay/event/PayClose.php
@@ -0,0 +1,27 @@
+close([['out_trade_no', '=', $params['out_trade_no']]]);
+ return $result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/event/PayRefund.php b/src/addon/offlinepay/event/PayRefund.php
new file mode 100644
index 000000000..ce8d98a71
--- /dev/null
+++ b/src/addon/offlinepay/event/PayRefund.php
@@ -0,0 +1,24 @@
+refund($params['pay_info']['out_trade_no'], $params['refund_fee']);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/event/PayType.php b/src/addon/offlinepay/event/PayType.php
new file mode 100644
index 000000000..a9a96fa49
--- /dev/null
+++ b/src/addon/offlinepay/event/PayType.php
@@ -0,0 +1,44 @@
+getPayConfig($params[ 'site_id' ] ?? 1);
+ $config = $config_result[ "data" ][ "value" ] ?? [];
+ $pay_status = $config[ "pay_status" ] ?? 0;
+
+ $app_type = $params['app_type'] ?? '';
+ if (!empty($app_type)) {
+ $app_type_array = [ 'h5', 'wechat', 'weapp', 'pc' ];
+ if (!in_array($app_type, $app_type_array)) {
+ return '';
+ }
+ if ($pay_status == 0) {
+ return '';
+ }
+ }
+ $info = array (
+ "pay_type" => "offlinepay",
+ "pay_type_name" => "线下支付",
+ "edit_url" => "offlinepay://shop/pay/config",
+ "shop_url" => "offlinepay://shop/pay/config",
+ "logo" => "addon/offlinepay/icon.png",
+ "desc" => "通过银行卡、支付宝或微信收款码线下收款。",
+ "pay_status" => $pay_status
+ );
+ return $info;
+
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/event/UnInstall.php b/src/addon/offlinepay/event/UnInstall.php
new file mode 100644
index 000000000..63e703c43
--- /dev/null
+++ b/src/addon/offlinepay/event/UnInstall.php
@@ -0,0 +1,17 @@
+handleConfigData($data);
+ $config = new ConfigModel();
+ $res = $config->setConfig($data, '线下支付配置', 1, [ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'OFFLINE_PAY_CONFIG' ] ]);
+ return $res;
+ }
+
+ /**
+ * 获取支付配置
+ * @param $site_id
+ * @param $app_module
+ * @return array
+ */
+ public function getPayConfig($site_id = 0, $app_module = 'shop')
+ {
+ $config = new ConfigModel();
+ $res = $config->getConfig([ [ 'site_id', '=', $site_id ], [ 'app_module', '=', $app_module ], [ 'config_key', '=', 'OFFLINE_PAY_CONFIG' ] ]);
+ $res['data']['value'] = $this->handleConfigData($res['data']['value']);
+ return $res;
+ }
+
+ /**
+ * 处理配置数据
+ * @param $data
+ * @return mixed
+ */
+ protected function handleConfigData($data)
+ {
+ $default_config = [
+ 'pay_status' => 0,//支付状态
+ 'bank' => [
+ 'status' => 0,//是否开启
+ 'bank_name' => '',//银行名称
+ 'account_name' => '',//账户名称
+ 'account_number' => '',//账号
+ 'branch_name' => '',//支行名称
+ ],
+ 'wechat' => [
+ 'status' => 0,//是否开启
+ 'account_name' => '',//账户名称
+ 'payment_code' => '',//收款码
+ ],
+ 'alipay' => [
+ 'status' => 0,//是否开启
+ 'account_name' => '',//账户名称
+ 'payment_code' => '',//收款码
+ ],
+ ];
+ return assignData($data, $default_config);
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/model/Pay.php b/src/addon/offlinepay/model/Pay.php
new file mode 100644
index 000000000..2284f179a
--- /dev/null
+++ b/src/addon/offlinepay/model/Pay.php
@@ -0,0 +1,489 @@
+ self::STATUS_WAIT_AUDIT,
+ 'name' => '待审核',
+ 'const' => 'WAIT_AUDIT',
+ ],
+ [
+ 'id' => self::STATUS_AUDIT_PASS,
+ 'name' => '审核通过',
+ 'const' => 'AUDIT_PASS',
+ ],
+ [
+ 'id' => self::STATUS_AUDIT_REFUSE,
+ 'name' => '审核拒绝',
+ 'const' => 'AUDIT_REFUSE',
+ ],
+ [
+ 'id' => self::STATUS_CLOSE,
+ 'name' => '已关闭',
+ 'const' => 'CLOSE',
+ ],
+ ];
+ if(isset($arr[0][$key])){
+ $arr = array_column($arr, null, $key);
+ }
+ return $arr;
+ }
+
+ /**
+ * 支付操作
+ * @param $param
+ * @return array
+ */
+ public function pay($param)
+ {
+ $member_id = $param['member_id'] ?? 0;
+ $out_trade_no = $param['out_trade_no'] ?? '';
+ $imgs = $param['imgs'] ?? '';
+ $desc = $param['desc'] ?? '';
+
+ if(empty($member_id)) return $this->error(null, '用户id不可为空');
+ if(empty($out_trade_no)) return $this->error(null, '外部交易号不可为空');
+ if(empty($imgs)) return $this->error(null, '请上传支付凭证');
+
+ $pay_model = new PayModel();
+ $pay_info = $pay_model->getPayInfo($out_trade_no)['data'];
+ if(empty($pay_info)) return $this->error(null, '支付信息有误');
+ if(!in_array($pay_info['pay_status'], [PayModel::PAY_STATUS_NOT, PayModel::PAY_STATUS_IN_PROCESS])){
+ return $this->error(null, '支付状态有误');
+ }
+
+ $offline_pay_info = model('pay_offline')->getInfo([['out_trade_no', '=', $out_trade_no], ['member_id', '=', $member_id]]);
+ if(!empty($offline_pay_info) && $offline_pay_info['status'] != self::STATUS_AUDIT_REFUSE){
+ return $this->error(null, '当前状态不可修改');
+ }
+
+ //记录线下支付信息
+ $data = [
+ 'member_id' => $member_id,
+ 'out_trade_no' => $out_trade_no,
+ 'imgs' => $imgs,
+ 'desc' => $desc,
+ 'status' => self::STATUS_WAIT_AUDIT,
+ 'update_time' => time(),
+ ];
+
+ model('pay_offline')->startTrans();
+ try{
+ if(empty($offline_pay_info)){
+ $data['create_time'] = time();
+ model('pay_offline')->add($data);
+ //绑定支付数据
+ $pay_model->bindMchPay($out_trade_no, [
+ "pay_type" => 'offlinepay',
+ ]);
+ }else{
+ model('pay_offline')->update($data, [['id', '=', $offline_pay_info['id']]]);
+ }
+
+ //支付信息修改
+ $update_data = ['pay_type' => self::PAY_TYPE, 'pay_status' => PayModel::PAY_STATUS_IN_PROCESS];
+ $pay_model->edit($update_data, [['out_trade_no', '=', $out_trade_no]]);
+ $pay_info = array_merge($pay_info, $update_data);
+
+ //具体业务处理
+ event('OfflinePay', $pay_info);
+
+ //发送消息
+ $message_model = new Message();
+ $message_model->sendMessage(['keywords' => 'OFFLINEPAY_WAIT_AUDIT', 'pay_info' => $pay_info, 'site_id' => $pay_info['site_id']]);
+
+ model('pay_offline')->commit();
+ return $this->success();
+ }catch(\Exception $e){
+ model('pay_offline')->rollback();
+ return $this->error(['file' => $e->getFile(), 'line' => $e->getLine(), 'message' => $e->getMessage()], $e->getMessage());
+ }
+ }
+
+ /**
+ * 审核通过
+ * @param $condition
+ * @return array|mixed|null
+ */
+ public function auditPass($condition)
+ {
+ $offline_pay_info = $this->getInfo($condition)['data'];
+ if(empty($offline_pay_info)) return $this->error(null, '支付信息有误');
+ if($offline_pay_info['status'] != self::STATUS_WAIT_AUDIT) return $this->error(null, '不是待审核状态');
+
+ model('pay_offline')->startTrans();
+ try{
+ model('pay_offline')->update([
+ 'status' => self::STATUS_AUDIT_PASS,
+ 'update_time' => time(),
+ ], $condition);
+
+ $pay_model = new PayModel();
+ $pay_res = $pay_model->onlinePay($offline_pay_info['out_trade_no'], self::PAY_TYPE, $offline_pay_info['out_trade_no'], 'offlinepay');
+ if($pay_res['code'] < 0){
+ model('pay_offline')->rollback();
+ return $pay_res;
+ }
+
+ model('pay_offline')->commit();
+ return $this->success();
+ }catch(\Exception $e){
+ model('pay_offline')->rollback();
+ return $this->error(['file' => $e->getFile(), 'line' => $e->getLine(), 'message' => $e->getMessage()], $e->getMessage());
+ }
+ }
+
+ /**
+ * 审核拒绝
+ * @param $condition
+ * @param $audit_remark
+ * @return array
+ */
+ public function auditRefuse($condition, $audit_remark)
+ {
+ $offline_pay_info = $this->getInfo($condition)['data'];
+ if(empty($offline_pay_info)) return $this->error(null, '支付信息有误');
+ if($offline_pay_info['status'] != self::STATUS_WAIT_AUDIT) return $this->error(null, '不是待审核状态');
+
+ $pay_model = new PayModel();
+ $pay_info = $pay_model->getPayInfo($offline_pay_info['out_trade_no'])['data'];
+ if(empty($pay_info)) return $this->error(null, '支付信息有误');
+
+ model('pay_offline')->update([
+ 'status' => self::STATUS_AUDIT_REFUSE,
+ 'audit_remark' => $audit_remark,
+ 'update_time' => time(),
+ ], $condition);
+
+ //发送消息
+ $message_model = new Message();
+ $message_model->sendMessage(['keywords' => 'OFFLINEPAY_AUDIT_REFUSE', 'pay_info' => $pay_info, 'site_id' => $pay_info['site_id']]);
+
+ return $this->success();
+ }
+
+ /**
+ * 订单关闭取消处理
+ * @param $condition
+ * @return array
+ */
+ public function close($condition)
+ {
+ $offline_pay_info = $this->getInfo($condition)['data'];
+ if(empty($offline_pay_info)) return $this->success();
+ if($offline_pay_info['status'] == self::STATUS_AUDIT_PASS) return $this->error(null, '线下支付审核通过不可以关闭');
+ if($offline_pay_info['status'] == self::STATUS_WAIT_AUDIT) return $this->error(null, '线下支付单据审核中不可以关闭');
+
+ model('pay_offline')->update([
+ 'status' => self::STATUS_CLOSE,
+ 'update_time' => time(),
+ ], $condition);
+
+ return $this->success();
+ }
+
+ /**
+ * 退款
+ * @param $out_trade_no
+ * @param $refund_money
+ * @return array
+ */
+ public function refund($out_trade_no, $refund_money)
+ {
+ $offline_pay_info = $this->getInfo([['out_trade_no', '=', $out_trade_no]])['data'];
+ if(empty($offline_pay_info)) return $this->error(null, '线下支付信息有误');
+
+ $pay_model = new PayModel();
+ $pay_info = $pay_model->getPayInfo($out_trade_no)['data'];
+ if(empty($pay_info)) return $this->error(null, '支付信息有误');
+
+ $member_account_model = new MemberAccount();
+ return $member_account_model->addMemberAccount($pay_info['site_id'], $offline_pay_info['member_id'], AccountDict::balance_money, $refund_money, 'refund', $pay_info['relate_id'], '订单退款返还!');
+ }
+
+ /**
+ * 获取信息
+ * @param $condition
+ * @param $field
+ * @return array
+ */
+ public function getInfo($condition, $field = '*')
+ {
+ $info = model('pay_offline')->getInfo($condition, $field);
+ $info = $this->handleInfo($info);
+ return $this->success($info);
+ }
+
+ /**
+ * 获取分页列表
+ * @param $condition
+ * @param $page
+ * @param $page_size
+ * @param $order
+ * @param $field
+ * @param $alias
+ * @param $join
+ * @return array
+ * @throws \think\db\exception\DataNotFoundException
+ * @throws \think\db\exception\DbException
+ * @throws \think\db\exception\ModelNotFoundException
+ */
+ public function getPageList($condition = [], $page = 1, $page_size = PAGE_LIST_ROWS, $order = '', $field = '*', $alias = 'a', $join = [])
+ {
+ $res = model('pay_offline')->pageList($condition, $field, $order, $page, $page_size, $alias, $join);
+ foreach($res['list'] as $key=>$val){
+ $res['list'][$key] = $this->handleInfo($val);
+ }
+ return $this->success($res);
+ }
+
+ /**
+ * 获取列表
+ * @param $condition
+ * @param $order
+ * @param $field
+ * @param $alias
+ * @param $join
+ * @param $group
+ * @return array
+ */
+ public function getList($condition, $order = '', $field = '*', $alias = 'a', $join = [], $group = '')
+ {
+ $list = model('pay_offline')->getList($condition, $field, $order, $alias, $join, $group);
+ foreach($list as $key=>$val){
+ $list[$key] = $this->handleInfo($val);
+ }
+ return $this->success($list);
+ }
+
+ public function handleInfo($info)
+ {
+ if(isset($info['status'])){
+ $status_list = self::getStatus('id');
+ $info['status_info'] = $status_list[$info['status']] ?? null;
+ }
+ return $info;
+ }
+
+ /**
+ * 处理用户订单信息
+ * @param $order_info
+ * @return array
+ */
+ public function handleMemberOrderInfo($order_info)
+ {
+ //字段检测
+ $fields = ['order_status','pay_type','out_trade_no','action'];
+ foreach($fields as $field){
+ if(!isset($order_info[$field])){
+ return $order_info;
+ }
+ }
+
+ if($order_info['order_status'] == OrderCommon::ORDER_CREATE && $order_info['pay_type'] == self::PAY_TYPE){
+ $offline_pay_info = $this->getInfo([['out_trade_no', '=', $order_info['out_trade_no']]])['data'];
+ if(!empty($offline_pay_info)){
+ $order_info['offline_pay_info'] = $offline_pay_info;
+ if(in_array($offline_pay_info['status'], [self::STATUS_WAIT_AUDIT, self::STATUS_AUDIT_REFUSE])){
+ foreach($order_info['action'] as $key=>$val){
+ if($val['action'] == 'orderPay'){
+ unset($order_info['action'][$key]);
+ }
+ }
+ }
+ if($offline_pay_info['status'] == self::STATUS_WAIT_AUDIT){
+ $order_info['order_status_name'] = '待审核';
+ }else if($offline_pay_info['status'] == self::STATUS_AUDIT_REFUSE){
+ $order_info['order_status_name'] = '审核拒绝';
+ $order_info['action'][] = [
+ 'action' => 'orderOfflinePay',
+ 'title' => '线下支付',
+ 'color' => '',
+ ];
+ }
+ $order_info['action'] = array_values($order_info['action']);
+ }
+ }
+ return $order_info;
+ }
+
+ /**
+ * 处理用户订单信息
+ * @param $order_info
+ * @return array
+ */
+ public function handleAdminOrderInfo($order_info)
+ {
+ //字段检测
+ $fields = ['order_status','order_status_action','pay_type','out_trade_no'];
+ foreach($fields as $field){
+ if(!isset($order_info[$field])){
+ return $order_info;
+ }
+ }
+
+ if($order_info['order_status'] == OrderCommon::ORDER_CREATE){
+ $order_status_info = json_decode($order_info['order_status_action'], true);
+ if($order_info['pay_type'] == self::PAY_TYPE){
+ $offline_pay_info = $this->getInfo([['out_trade_no', '=', $order_info['out_trade_no']]])['data'];
+ $order_info['offline_pay_info'] = $offline_pay_info;
+ if(!empty($offline_pay_info)){
+ if($offline_pay_info['status'] == self::STATUS_WAIT_AUDIT){
+ $order_info['order_status_name'] = '待审核';
+ $order_status_info['action'][] = [
+ 'action' => 'offlinePayAudit',
+ 'title' => '支付审核',
+ 'color' => '',
+ ];
+ }else if($offline_pay_info['status'] == self::STATUS_AUDIT_REFUSE){
+ $order_info['status_name'] = '审核拒绝';
+ }
+ }
+ }else{
+ $order_status_info['action'][] = [
+ 'action' => 'offlinePay',
+ 'title' => '线下支付',
+ 'color' => '',
+ ];
+ }
+ $order_info['order_status_action'] = json_encode($order_status_info);
+ }
+ return $order_info;
+ }
+
+ /**
+ * 发送消息
+ * @param $param
+ * @throws \GuzzleHttp\Exception\GuzzleException
+ */
+ public function messageWaitAudit($param)
+ {
+ $pay_info = $param['pay_info'];
+ $sms_model = new Sms();
+ $wechat_model = new WechatMessage();
+
+ $shop_accept_message_model = new ShopAcceptMessage();
+ $list = $shop_accept_message_model->getShopAcceptMessageList([['site_id', '=', $pay_info['site_id']]])['data'];
+ if (!empty($list)) {
+ foreach ($list as $v) {
+ if(!empty($v['mobile'])){
+ $message_data = [
+ 'var_parse' => [
+ 'order_name' => str_sub(replaceSpecialChar($pay_info[ 'pay_body' ]), 25),
+ 'pay_money' => $pay_info['pay_money'],
+ 'out_trade_no' => $pay_info['out_trade_no'],
+ ],
+ 'sms_account' => $v[ 'mobile' ],
+ ];
+ $sms_model->sendMessage(array_merge($param, $message_data));
+ }
+
+ if (!empty($v[ 'wx_openid' ])) {
+ $message_data = [
+ 'openid' => $v[ 'wx_openid' ],
+ 'template_data' => [
+ 'thing10' => str_sub($pay_info['pay_body'], 20),
+ 'amount4' => $pay_info['pay_money'],
+ 'character_string1' => $pay_info['out_trade_no'],
+ ],
+ 'page' => '',
+ ];
+ $wechat_model->sendMessage(array_merge($param, $message_data));
+ }
+ }
+ }
+ }
+
+ /**
+ * 发送消息
+ * @param $param
+ * @throws \GuzzleHttp\Exception\GuzzleException
+ */
+ public function messageAuditRefuse($param)
+ {
+ $pay_info = $param['pay_info'];
+ $sms_model = new Sms();
+ $wechat_model = new WechatMessage();
+ $weapp_model = new WeappMessage();
+
+ $member_model = new Member();
+ $member_info = $member_model->getMemberInfo([ [ 'member_id', '=', $pay_info[ 'member_id' ] ] ])[ 'data' ];
+
+ if(!empty($member_info['mobile'])){
+ $message_data = [
+ 'var_parse' => [
+ 'order_name' => str_sub(replaceSpecialChar($pay_info[ 'pay_body' ]), 25),
+ 'pay_money' => $pay_info['pay_money'],
+ 'out_trade_no' => $pay_info['out_trade_no'],
+ ],
+ 'sms_account' => $member_info[ 'mobile' ],
+ ];
+ $sms_model->sendMessage(array_merge($param, $message_data));
+ }
+
+ if (!empty($member_info[ 'wx_openid' ])) {
+ $message_data = [
+ 'openid' => $member_info[ 'wx_openid' ],
+ 'template_data' => [
+ 'thing10' => str_sub($pay_info['pay_body'], 20),
+ 'amount6' => $pay_info['pay_money'],
+ 'character_string5' => $pay_info['out_trade_no'],
+ ],
+ 'page' => 'pages/order/detail?order_id='.$pay_info['relate_id'],
+ ];
+ $wechat_model->sendMessage(array_merge($param, $message_data));
+ }
+
+ if (!empty($member_info[ 'weapp_openid' ])) {
+ $message_data = [
+ 'openid' => $member_info[ 'weapp_openid' ],
+ 'template_data' => [
+ 'thing2' => [
+ 'value' => str_sub($pay_info['pay_body'], 20)
+ ],
+ 'amount3' => [
+ 'value' => $pay_info['pay_money']
+ ],
+ 'character_string1' => [
+ 'value' => $pay_info['out_trade_no']
+ ],
+ 'thing5' => [
+ 'value' => '线下支付审核拒绝'
+ ],
+ ],
+ 'page' => 'pages/order/detail?order_id='.$pay_info['relate_id'],
+ ];
+ $weapp_model->sendMessage(array_merge($param, $message_data));
+ }
+ }
+}
diff --git a/src/addon/offlinepay/shop/controller/Pay.php b/src/addon/offlinepay/shop/controller/Pay.php
new file mode 100644
index 000000000..d60932730
--- /dev/null
+++ b/src/addon/offlinepay/shop/controller/Pay.php
@@ -0,0 +1,172 @@
+isJson()) {
+ $data = [
+ 'pay_status' => input('pay_status', 0),//支付状态
+ 'bank' => [
+ 'status' => input('bank_status', 0),//是否开启
+ 'bank_name' => input('bank_bank_name', ''),//银行名称
+ 'account_name' => input('bank_account_name', ''),//账户名称
+ 'account_number' => input('bank_account_number', ''),//账号
+ 'branch_name' => input('bank_branch_name', ''),//支行名称
+ ],
+ 'wechat' => [
+ 'status' => input('wechat_status', 0),//是否开启
+ 'account_name' => input('wechat_account_name', ''),//账户名称
+ 'payment_code' => input('wechat_payment_code', ''),//收款码
+ ],
+ 'alipay' => [
+ 'status' => input('alipay_status', 0),//是否开启
+ 'account_name' => input('alipay_account_name', ''),//账户名称
+ 'payment_code' => input('alipay_payment_code', ''),//收款码
+ ],
+ ];
+ $result = $config_model->setPayConfig($data, $this->site_id, $this->app_module);
+ return $result;
+ } else {
+ $config_info = $config_model->getPayConfig($this->site_id, $this->app_module)[ 'data' ][ 'value' ];
+ $this->assign("config_info", $config_info);
+ return $this->fetch("pay/config");
+ }
+ }
+
+ public function lists()
+ {
+ if (request()->isJson()) {
+ $page_index = input('page', 1);
+ $page_size = input('page_size', PAGE_LIST_ROWS);
+ $status = input('status', 0);
+ $search_field = input('search_field', '');
+ $search_field_value = input('search_field_value', '');
+ $out_trade_no = input('out_trade_no', '');
+
+ $alias = 'po';
+ $join = [
+ ['member m', 'm.member_id = po.member_id', 'left'],
+ ['pay p', 'p.out_trade_no = po.out_trade_no', 'left'],
+ ];
+ $field = [
+ 'po.*',
+ 'm.nickname,m.mobile',
+ 'p.pay_detail,p.pay_money,p.event,p.relate_id',
+ ];
+ $condition = [];
+ if($status !== 'all'){
+ $condition[] = ['po.status', '=', $status];
+ }
+ if($search_field_value != ''){
+ $condition[] = [$search_field, 'like', '%'.$search_field_value.'%'];
+ }
+ if($out_trade_no){
+ $condition[] = ['po.out_trade_no', '=', $out_trade_no];
+ }
+ $order = 'po.create_time desc';
+
+
+ $pay_model = new PayModel();
+ $res = $pay_model->getPageList($condition, $page_index, $page_size, $order, $field, $alias, $join);
+
+ //各种状态统计
+ foreach ($condition as $key=>$val){ if($val[0] == 'po.status') unset($condition[$key]); }
+ $condition = array_values($condition);
+ $status_num_list = $pay_model->getList($condition, '', 'count(*) as num, po.status', $alias, $join, 'po.status')['data'];
+
+ $status_num_data = array_column($status_num_list, 'num', 'status');
+ $res['data']['status_num_data'] = $status_num_data;
+$res['c'] = $condition;
+ return $res;
+ } else {
+ $status_list = PayModel::getStatus();
+ $this->assign('status_list', $status_list);
+
+ $out_trade_no = input('out_trade_no', '');
+ $this->assign('out_trade_no', $out_trade_no);
+
+ return $this->fetch('pay/lists');
+ }
+ }
+
+ public function auditPass()
+ {
+ if(request()->isJson()){
+ $id = input('id', 0);
+ $pay_model = new PayModel();
+ return $pay_model->auditPass([['id', '=', $id]]);
+ }
+ }
+
+ public function auditRefuse()
+ {
+ if(request()->isJson()){
+ $id = input('id', 0);
+ $audit_remark = input('audit_remark', '');
+ $pay_model = new PayModel();
+ return $pay_model->auditRefuse([['id', '=', $id]], $audit_remark);
+ }
+ }
+
+ public function pay()
+ {
+ if(request()->isJson()){
+ $imgs = input('imgs', '');
+ $desc = input('desc', '');
+ $out_trade_no = input('out_trade_no', '');
+ $member_id = input('member_id', 0);
+ $pay_model = new PayModel();
+ //支付
+ $pay_res = $pay_model->pay([
+ 'member_id' => $member_id,
+ 'out_trade_no' => $out_trade_no,
+ 'imgs' => $imgs,
+ 'desc' => $desc,
+ ]);
+ if($pay_res['code'] < 0) return $pay_res;
+ //审核
+ $audit_res = $pay_model->auditPass([
+ ['out_trade_no', '=', $out_trade_no],
+ ['member_id', '=', $member_id],
+ ]);
+ return $audit_res;
+ }else{
+ $out_trade_no = input('out_trade_no', '');
+ $this->assign("out_trade_no", $out_trade_no);
+ $member_id = input('member_id', 0);
+ $this->assign("member_id", $member_id);
+ return $this->fetch("pay/pay");
+ }
+ }
+
+ public function test()
+ {
+ $out_trade_no = '171997599310581711000';
+ $member_id = 171;
+ $imgs = join(',', [
+ 'http://b2cv4.com/upload/1/common/images/20240618/20240618105545171867934599817_BIG.jpg',
+ 'http://b2cv4.com/upload/1/common/goods_grab/images/20240527/20240527032610171679477043213_BIG.jpg',
+ 'http://b2cv4.com/upload/1/common/images/20240618/20240618105545171867934599817_BIG.jpg',
+ ]);
+ $desc = '支付了33333次';
+ $pay_model = new PayModel();
+ $res = $pay_model->pay([
+ 'member_id' => $member_id,
+ 'out_trade_no' => $out_trade_no,
+ 'imgs' => $imgs,
+ 'desc' => $desc,
+ ]);
+ dd($res);
+ }
+}
\ No newline at end of file
diff --git a/src/addon/offlinepay/shop/view/pay/config.html b/src/addon/offlinepay/shop/view/pay/config.html
new file mode 100644
index 000000000..02f35d845
--- /dev/null
+++ b/src/addon/offlinepay/shop/view/pay/config.html
@@ -0,0 +1,193 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/addon/offlinepay/shop/view/pay/lists.html b/src/addon/offlinepay/shop/view/pay/lists.html
new file mode 100644
index 000000000..600552c9d
--- /dev/null
+++ b/src/addon/offlinepay/shop/view/pay/lists.html
@@ -0,0 +1,356 @@
+
+
+
+
+
+
+ {foreach $status_list as $key=>$status_info}
+ - {$status_info.name}(0)
+ {/foreach}
+ - 全部
+
+
+
+
+
+
+
+
+
+
diff --git a/src/addon/offlinepay/shop/view/pay/pay.html b/src/addon/offlinepay/shop/view/pay/pay.html
new file mode 100644
index 000000000..5a94c9d59
--- /dev/null
+++ b/src/addon/offlinepay/shop/view/pay/pay.html
@@ -0,0 +1,73 @@
+
+
+
\ No newline at end of file
diff --git a/src/app/common.php b/src/app/common.php
index 322b37b33..163d98f4d 100644
--- a/src/app/common.php
+++ b/src/app/common.php
@@ -321,7 +321,6 @@ function date_to_time($date)
/**
* 获取唯一随机字符串
- * 创建时间:2018年8月7日15:54:16
*/
function unique_random($len = 10)
{
@@ -375,6 +374,8 @@ function http($url, $timeout = 30, $header = array ())
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727;)');
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 关闭 SSL 证书校验
+
if (!empty($header)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
@@ -423,9 +424,8 @@ function replace_array_element($array, $replace)
/**
* 过滤特殊符号
- * 创建时间:2018年1月30日15:39:32
- * @param unknown $string
- * @return mixed
+ * @param $string
+ * @return array|string|string[]|null
*/
function ihtmlspecialchars($string)
{
@@ -693,13 +693,13 @@ function success($code = 0, $message = '', $data = '')
/**
* 实例化Model
- *
- * @param string $name
- * Model名称
+ * @param string $table
+ * @param array $option
+ * @return \app\model\Model
*/
-function model($table = '')
+function model($table = '', $option = [])
{
- return new \app\model\Model($table);
+ return new \app\model\Model($table, $option);
}
/**
@@ -1164,12 +1164,27 @@ function string_split($string, $delimiter, $value)
* $str为要进行截取的字符串,$length为截取长度(汉字算一个字,字母算半个字
* @param $str
* @param int $length
- * @param bool $is_need_apostrophe
+ * @param boolean $is_need_apostrophe 是否需要省略号
+ * @param string $apostrophe_pos 省略号位置 end 结尾 center 中间
* @return string
*/
-function str_sub($str, $length = 10, $is_need_apostrophe = true)
+function str_sub($str, $length = 10, $is_need_apostrophe = false, $apostrophe_pos = 'end')
{
- return mb_substr($str, 0, $length, 'UTF-8') . ( $is_need_apostrophe ? '...' : '' );
+ $encoding = 'UTF-8';
+ $res_str = $str;
+ if(mb_strlen($str, $encoding) > $length){
+ if($is_need_apostrophe){
+ if($apostrophe_pos == 'end'){
+ $res_str = mb_substr($str, 0, $length, $encoding) . '...';
+ }else{
+ $half_length = floor($length / 2);
+ $res_str = mb_substr($str, 0, $half_length, $encoding) . '...' . mb_substr($str, mb_strlen($str, $encoding) - $half_length, $half_length, $encoding);
+ }
+ }else{
+ $res_str = mb_substr($str, 0, $length, 'UTF-8');
+ }
+ }
+ return $res_str;
}
/**
@@ -1879,6 +1894,199 @@ function paramFilter($param)
return preg_replace($filter_rule, '', $param);
}
+//最小公倍数
+function getLeastCommonMultiple($a, $b) {
+ return $a * $b / getGreatestCommonDivisor($a, $b);
+}
+//最大公约数
+function getGreatestCommonDivisor($a, $b) {
+ if ($b === 0) return $a;
+ return getGreatestCommonDivisor($b, $a % $b);
+}
+
+
+/**
+ * 关联数组变为索引数组
+ * @param array $list
+ * @return array
+ */
+function keyArrToIndexArr($list, $child = 'children'){
+ $list = array_values($list);
+ foreach($list as $key=>$val){
+ if(isset($val[$child]) && !empty($val[$child])){
+ $list[$key][$child] = keyArrToIndexArr($val[$child], $child);
+ }
+ }
+ return $list;
+}
+
+/**
+ * 索引数组变为关联数组
+ * @param $list
+ * @param $pk
+ * @param string $child
+ * @return array
+ */
+function indexArrToKeyArr($list, $pk, $child = 'children'){
+ $new_list = [];
+ foreach($list as $val){
+ if(isset($val[$child]) && !empty($val[$child])){
+ $val[$child] = indexArrToKeyArr($val[$child], $pk, $child);
+ }
+ if(isset($val[$pk])){
+ $new_list[$val[$pk]] = $val;
+ }
+ }
+ return $new_list;
+}
+
+/**
+ * 获取树的末端节点
+ * @param $list
+ * @param $pk
+ * @param $child
+ * @return array
+ */
+function getTreeLeaf($list, $pk = 'id', $child = 'child')
+{
+ $leaf_arr = [];
+ foreach($list as $val){
+ if(empty($val[$child])){
+ $leaf_arr[] = $val[$pk];
+ }else{
+ $leaf_arr = array_merge($leaf_arr, getTreeLeaf($val[$child], $pk, $child));
+ }
+ }
+ return $leaf_arr;
+}
+
+/**
+ * 覆盖数据
+ * @param $source_data
+ * @param $target_data
+ * @return mixed
+ */
+function assignData($source_data, $target_data)
+{
+ if(is_array($target_data)){
+ foreach($target_data as $key=>$val){
+ if(isset($source_data[$key])){
+ $target_data[$key] = assignData($source_data[$key], $val);
+ }
+ }
+ }else{
+ $target_data = $source_data;
+ }
+ return $target_data;
+}
+
+//使用htmlpurifier防范xss攻击
+function removeXss($string)
+{
+ //相对index.php入口文件,引入HTMLPurifier.auto.php核心文件
+ //require_once './plugins/htmlpurifier/HTMLPurifier.auto.php';
+ // 生成配置对象
+ $cfg = HTMLPurifier_Config::createDefault();
+ // 以下就是配置:
+ $cfg->set('Core.Encoding', 'UTF-8');
+ // 设置允许使用的HTML标签
+ $cfg->set('HTML.Allowed', 'div,b,strong,i,em,a[href|title],ul,ol,li,br,p[style],span[style],img[width|height|alt|src],table,tbody,tr[class],th,td[width|valign|style]');
+ // 设置允许出现的CSS样式属性
+ //$cfg->set('CSS.AllowedProperties', 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align');
+ // 设置a标签上是否允许使用target="_blank"
+ $cfg->set('HTML.TargetBlank', TRUE);
+ // 使用配置生成过滤用的对象
+ $obj = new HTMLPurifier($cfg);
+ // 过滤字符串
+ $array = json_decode($string, true);
+ if(is_array($array)){
+ $array = recursiveDealWithArrayString($array, function ($str) use($obj){
+ return $obj->purify($str);
+ });
+ $string = json_encode($array, JSON_UNESCAPED_UNICODE);
+ }else{
+ $string = $obj->purify($string);
+ }
+ return $string;
+}
+
+/**
+ * 递归处理数组中的字符串
+ * @param $array
+ * @param $callback
+ * @return mixed
+ */
+function recursiveDealWithArrayString($array, $callback){
+ foreach($array as $key=>$val){
+ if(is_string($val)){
+ $val = $callback($val);
+ }else if(is_array($val)){
+ $val = recursiveDealWithArrayString($val, $callback);
+ }
+ $array[$key] = $val;
+ }
+ return $array;
+}
+
+function exceptionData(\Exception $e){
+ return [
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'message' => $e->getMessage(),
+ ];
+}
+
+function getCertKey($str)
+{
+ return require "extend/cert/".$str.".php";
+}
+
+if(!function_exists('http_url')){
+ function http_url($url,$data,$headers = [],$type = 'POST') {
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type);
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_URL, $url);
+ $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36';
+ curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); # 在HTTP请求中包含一个"User-Agent: "头的字符串,声明用什么浏览器来打开目标网页
+ if(!empty($headers)) {
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+ }
+ if (1 == strpos("$".$url, "https://"))
+ {
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+ }
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($ch, CURLOPT_AUTOREFERER, true);
+ curl_setopt($ch, CURLOPT_ENCODING, '');
+ if($type == 'POST') {
+ curl_setopt($ch, CURLOPT_POST, true);
+ if(is_array($data)) {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
+ }else {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+ }
+ }
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // ssl 访问核心参数
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // ssl 访问核心参数
+ $result = curl_exec($ch);
+ curl_close($ch);
+ return $result;
+ }
+
+ function secondsToTime($seconds) {
+ $hours = floor($seconds / 3600);
+ $minutes = floor(($seconds % 3600) / 60);
+ $seconds = $seconds % 60;
+
+ // 格式化为两位数
+ return sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
+ }
+}
+
/**
* 格式化数据为日志友好的字符串(保持中文可读性)
*