mirror of
https://gitee.com/technical-laohu/mpay.git
synced 2025-12-26 01:15:58 +08:00
首次提交
This commit is contained in:
1
app/.htaccess
Normal file
1
app/.htaccess
Normal file
@@ -0,0 +1 @@
|
||||
deny from all
|
||||
22
app/AppService.php
Normal file
22
app/AppService.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\Service;
|
||||
|
||||
/**
|
||||
* 应用服务类
|
||||
*/
|
||||
class AppService extends Service
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
// 服务注册
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
// 服务启动
|
||||
}
|
||||
}
|
||||
93
app/BaseController.php
Normal file
93
app/BaseController.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\Validate;
|
||||
|
||||
/**
|
||||
* 控制器基础类
|
||||
*/
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
* Request实例
|
||||
* @var \think\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* 应用实例
|
||||
* @var \think\App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 是否批量验证
|
||||
* @var bool
|
||||
*/
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 控制器中间件
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = ['Auth'];
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
* @param App $app 应用对象
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->request = $this->app->request;
|
||||
|
||||
// 控制器初始化
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
// 初始化
|
||||
protected function initialize() {}
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
* @access protected
|
||||
* @param array $data 数据
|
||||
* @param string|array $validate 验证器名或者验证规则数组
|
||||
* @param array $message 提示信息
|
||||
* @param bool $batch 是否批量验证
|
||||
* @return array|string|true
|
||||
* @throws ValidateException
|
||||
*/
|
||||
protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false)
|
||||
{
|
||||
if (is_array($validate)) {
|
||||
$v = new Validate();
|
||||
$v->rule($validate);
|
||||
} else {
|
||||
if (strpos($validate, '.')) {
|
||||
// 支持场景
|
||||
[$validate, $scene] = explode('.', $validate);
|
||||
}
|
||||
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
|
||||
$v = new $class();
|
||||
if (!empty($scene)) {
|
||||
$v->scene($scene);
|
||||
}
|
||||
}
|
||||
|
||||
$v->message($message);
|
||||
|
||||
// 是否批量验证
|
||||
if ($batch || $this->batchValidate) {
|
||||
$v->batch(true);
|
||||
}
|
||||
|
||||
return $v->failException(true)->check($data);
|
||||
}
|
||||
}
|
||||
18
app/BaseModel.php
Normal file
18
app/BaseModel.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
/**
|
||||
* @mixin \think\Model
|
||||
*/
|
||||
class BaseModel extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
}
|
||||
58
app/ExceptionHandle.php
Normal file
58
app/ExceptionHandle.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
namespace app;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\Handle;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\ValidateException;
|
||||
use think\Response;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 应用异常处理类
|
||||
*/
|
||||
class ExceptionHandle extends Handle
|
||||
{
|
||||
/**
|
||||
* 不需要记录信息(日志)的异常类列表
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreReport = [
|
||||
HttpException::class,
|
||||
HttpResponseException::class,
|
||||
ModelNotFoundException::class,
|
||||
DataNotFoundException::class,
|
||||
ValidateException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录异常信息(包括日志或者其它方式记录)
|
||||
*
|
||||
* @access public
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception): void
|
||||
{
|
||||
// 使用内置的方式记录异常日志
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
// 添加自定义异常处理机制
|
||||
|
||||
// 其他错误交给系统处理
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
}
|
||||
8
app/Request.php
Normal file
8
app/Request.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
namespace app;
|
||||
|
||||
// 应用请求对象类
|
||||
class Request extends \think\Request
|
||||
{
|
||||
|
||||
}
|
||||
10
app/common.php
Normal file
10
app/common.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// 应用公共文件
|
||||
function backMsg($code = 0, $msg = '', $data = []): array
|
||||
{
|
||||
$back_msg = ['code' => $code, 'msg' => $msg];
|
||||
if ($data) {
|
||||
$back_msg['data'] = $data;
|
||||
}
|
||||
return $back_msg;
|
||||
}
|
||||
29
app/controller/ConsoleController.php
Normal file
29
app/controller/ConsoleController.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\View;
|
||||
|
||||
class ConsoleController extends BaseController
|
||||
{
|
||||
// 后台主页
|
||||
public function index()
|
||||
{
|
||||
return View::fetch();
|
||||
}
|
||||
// 管理菜单
|
||||
public function menu()
|
||||
{
|
||||
// 加载菜单配置
|
||||
$menu = \think\facade\Config::load("extendconfig/menu", 'extendconfig');
|
||||
return \json($menu);
|
||||
}
|
||||
// 首页仪表盘
|
||||
public function console()
|
||||
{
|
||||
return View::fetch();
|
||||
}
|
||||
}
|
||||
17
app/controller/IndexController.php
Normal file
17
app/controller/IndexController.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use think\facade\View;
|
||||
|
||||
class IndexController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
if (session('?nickname')) {
|
||||
$nickname = session('nickname');
|
||||
View::assign('nickname', $nickname);
|
||||
}
|
||||
return View::fetch();
|
||||
}
|
||||
}
|
||||
33
app/controller/OrderController.php
Normal file
33
app/controller/OrderController.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use app\model\Order;
|
||||
use think\facade\View;
|
||||
|
||||
class OrderController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$servertime = date('Y-m-d H:i:s', time());
|
||||
// 加载配置文件
|
||||
$option = \think\facade\Config::load("extendconfig/platform", 'extendconfig');
|
||||
View::assign('servertime', $servertime);
|
||||
View::assign('options', $option);
|
||||
return View::fetch();
|
||||
}
|
||||
public function showOrder()
|
||||
{
|
||||
$id = $this->request->get('id');
|
||||
$order = Order::showOrderDetail($id);
|
||||
if ($order) {
|
||||
View::assign($order);
|
||||
return View::fetch();
|
||||
} else {
|
||||
return '订单不存在';
|
||||
}
|
||||
}
|
||||
}
|
||||
364
app/controller/PayController.php
Normal file
364
app/controller/PayController.php
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use think\Request;
|
||||
use think\facade\View;
|
||||
use app\model\User;
|
||||
use app\model\Order;
|
||||
use app\model\PayChannel;
|
||||
|
||||
class PayController
|
||||
{
|
||||
// 提交订单
|
||||
public function submit(Request $request)
|
||||
{
|
||||
$req_method = $request->method();
|
||||
$req_data = match ($req_method) {
|
||||
'GET' => $request->get(),
|
||||
'POST' => $request->post(),
|
||||
default => []
|
||||
};
|
||||
if (!$req_data) {
|
||||
return '参数错误';
|
||||
}
|
||||
$key = User::where('pid', $req_data['pid'])->where('state', 1)->value('secret_key');
|
||||
if (!$key) {
|
||||
return '用户禁用或不存在';
|
||||
}
|
||||
$sign_str = self::getSign($req_data, $key);
|
||||
if ($req_data['sign'] === $sign_str) {
|
||||
// 检查商户订单
|
||||
$out_trade_no = Order::where('out_trade_no', $req_data['out_trade_no'])->value('out_trade_no');
|
||||
if (!$out_trade_no) {
|
||||
// 创建新订单
|
||||
$order_id = Order::createOrder($req_data);
|
||||
if ($order_id) {
|
||||
return redirect("/Pay/console/{$order_id}");
|
||||
} else {
|
||||
return '创建订单失败';
|
||||
}
|
||||
} else {
|
||||
return '订单提交重复';
|
||||
}
|
||||
} else {
|
||||
return '签名错误';
|
||||
}
|
||||
}
|
||||
// api提交订单
|
||||
public function mapi(Request $request)
|
||||
{
|
||||
if ($request->isPost()) {
|
||||
$req_data = $request->post();
|
||||
if (!$req_data) {
|
||||
$req_data = $request->get();
|
||||
if (!$req_data) {
|
||||
return '参数错误';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return '请使用POST方式提交';
|
||||
}
|
||||
$key = User::where('pid', $req_data['pid'])->where('state', 1)->value('key');
|
||||
if (!$key) {
|
||||
return '用户禁用或不存在';
|
||||
}
|
||||
$sign_str = self::getSign($req_data, $key);
|
||||
if ($req_data['sign'] === $sign_str) {
|
||||
// 检查商户订单
|
||||
$out_trade_no = Order::where('out_trade_no', $req_data['out_trade_no'])->value('out_trade_no');
|
||||
if (!$out_trade_no) {
|
||||
// 创建新订单
|
||||
$order_id = Order::createOrder($req_data);
|
||||
if ($order_id) {
|
||||
$payurl = $request->domain() . "/Pay/console/{$order_id}";
|
||||
$info = ['code' => 1, 'msg' => '订单创建成功', 'trade_no' => $order_id, 'qrcode' => $payurl];
|
||||
return json($info);
|
||||
} else {
|
||||
return '创建订单失败';
|
||||
}
|
||||
} else {
|
||||
return '订单提交重复';
|
||||
}
|
||||
} else {
|
||||
return '签名错误';
|
||||
}
|
||||
}
|
||||
// 收银台
|
||||
public function console($order_id = '')
|
||||
{
|
||||
if ($order_id) {
|
||||
$act_order = Order::where('order_id', $order_id)->field(['out_trade_no', 'name', 'really_price', 'close_time', 'type', 'order_id', 'cid'])->find();
|
||||
if ($act_order) {
|
||||
$qrcode = PayChannel::where('id', $act_order->cid)->value('qrcode');
|
||||
View::assign($act_order->toArray());
|
||||
View::assign('payUrl', $qrcode);
|
||||
return View::fetch();
|
||||
} else {
|
||||
return '订单不存在';
|
||||
}
|
||||
} else {
|
||||
return '订单号参数错误';
|
||||
}
|
||||
}
|
||||
// 查询订单状态
|
||||
public function getOrderState($order_id = '')
|
||||
{
|
||||
if ($order_id) {
|
||||
$act_order = Order::where('order_id', $order_id)->find();
|
||||
if ($act_order) {
|
||||
$data = [];
|
||||
if ($act_order->state === 0) {
|
||||
$data['order_id'] = $act_order->order_id;
|
||||
$data['state'] = $act_order->state;
|
||||
return json($data);
|
||||
} elseif ($act_order->state === 1) {
|
||||
// 通知参数
|
||||
$notify = self::crateNotify($act_order);
|
||||
// 字符串签名
|
||||
$user_key = User::where('pid', $act_order->pid)->value('secret_key');
|
||||
$sign = self::getSign($notify, $user_key);
|
||||
$notify['sign'] = $sign;
|
||||
// 跳转通知URL
|
||||
$res_return_url = $act_order->return_url . '?' . http_build_query($notify);
|
||||
// 响应消息
|
||||
$data['order_id'] = $act_order->order_id;
|
||||
$data['state'] = $act_order->state;
|
||||
$data['return_url'] = $res_return_url;
|
||||
return json($data);
|
||||
}
|
||||
} else {
|
||||
return '订单不存在';
|
||||
}
|
||||
} else {
|
||||
return '订单号参数错误';
|
||||
}
|
||||
}
|
||||
// 处理收款通知
|
||||
public function payHeart($pid = '', $aid = '', $sign = '')
|
||||
{
|
||||
// 检测请求参数
|
||||
if (!($pid && $aid && $sign)) {
|
||||
return '参数错误';
|
||||
}
|
||||
// 检测收款通知
|
||||
$payList = request()->post();
|
||||
if (!$payList) {
|
||||
return json(['code' => 0, 'msg' => '空收款通知']);
|
||||
}
|
||||
// 签名验证
|
||||
$is_user = User::checkUser($pid, $sign);
|
||||
if (!$is_user) {
|
||||
return json(['code' => 0, 'msg' => '签名错误']);
|
||||
}
|
||||
// 当前用户账号
|
||||
$query = ['pid' => $pid, 'aid' => $aid];
|
||||
// 排除有效期内的已支付订单
|
||||
$doneOrders = Order::scope('dealOrder')->where($query)->column('platform_order');
|
||||
if ($doneOrders) {
|
||||
$num = count($payList['order_no']);
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
if (in_array($payList['order_no'][$i], $doneOrders)) {
|
||||
$payList['price'][$i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (array_sum($payList['price']) === 0) {
|
||||
return json(['code' => 0, 'msg' => '查询无新订单']);
|
||||
}
|
||||
// 有效订单列表
|
||||
$activeOrders = Order::scope('activeOrder')->where($query)->select();
|
||||
if (!\count($activeOrders)) {
|
||||
return json(['code' => 0, 'msg' => '无有效期订单']);
|
||||
}
|
||||
// $msg = []; 订单高并发预留
|
||||
foreach ($activeOrders as $order) {
|
||||
$index = array_search($order->really_price, $payList['price']);
|
||||
// 付款金额检查
|
||||
if ($index !== false) {
|
||||
// 已支付订单容错查询
|
||||
$is_order_no = Order::where('platform_order', $payList['order_no'][$index])->where($query)->find();
|
||||
// 支付方式核对
|
||||
$is_payway = $order->type === $payList['payway'][$index];
|
||||
// 支付渠道核对
|
||||
$is_channel = PayChannel::where('id', $order->cid)->value('channel') === $payList['channel'][$index];
|
||||
// 全部核对通过,修改订单状态
|
||||
if (!$is_order_no && $is_payway && $is_channel) {
|
||||
// 支付成功
|
||||
$set_order_state = $order->save(['state' => 1, 'pay_time' => date('Y-m-d H:i:s', time()), 'platform_order' => $payList['order_no'][$index]]);
|
||||
// 订单成交通知
|
||||
if (!$set_order_state) {
|
||||
return json(['code' => 0, 'msg' => '修改订单状态失败']);
|
||||
}
|
||||
$notify = self::crateNotify($order);
|
||||
// 字符串签名
|
||||
$user_key = User::where('pid', $order->pid)->value('secret_key');
|
||||
$sign = self::getSign($notify, $user_key);
|
||||
$notify['sign'] = $sign;
|
||||
// 异步通知
|
||||
$res_notify = self::getHttpResponse($order->notify_url . '?' . http_build_query($notify));
|
||||
if ($res_notify === 'success') {
|
||||
return json(['code' => 0, 'msg' => 'success']);
|
||||
} else {
|
||||
return json(['code' => 1, 'msg' => '异步通知失败']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// [定时任务]监听新订单
|
||||
public function checkOrder($pid = '', $sign = '')
|
||||
{
|
||||
if (!($pid && $sign)) {
|
||||
return '参数错误';
|
||||
}
|
||||
$is_user = User::checkUser($pid, $sign);
|
||||
if ($is_user) {
|
||||
$orders = Order::scope('activeOrder')->field('id,pid,aid,cid')->select();
|
||||
$old_info = file_get_contents('order.json');
|
||||
$num = count($orders);
|
||||
if ($num > 0) {
|
||||
$info = ['code' => 1, 'msg' => "有{$num}个新订单"];
|
||||
$order_list = ['code' => 1, 'msg' => "有{$num}个新订单", 'orders' => $orders];
|
||||
if ($old_info !== json_encode($order_list)) {
|
||||
file_put_contents('order.json', json_encode($order_list));
|
||||
}
|
||||
return json($info);
|
||||
} else {
|
||||
$info = ['code' => 0, 'msg' => '没有新订单'];
|
||||
if ($old_info !== json_encode($info, 320)) {
|
||||
file_put_contents('order.json', json_encode($info, 320));
|
||||
}
|
||||
return json($info);
|
||||
}
|
||||
} else {
|
||||
$info = ['code' => 2, 'msg' => '签名错误'];
|
||||
file_put_contents('order.json', json_encode($info, 320));
|
||||
return json($info);
|
||||
}
|
||||
}
|
||||
// [定时任务]监听收款通知
|
||||
public function checkPayResult(Request $request)
|
||||
{
|
||||
$req_info = $request->get();
|
||||
$req_pid = $req_info['pid'];
|
||||
$req_aid = $req_info['aid'];
|
||||
// 加载配置文件
|
||||
$config = \think\facade\Config::load("payconfig/{$req_pid}_{$req_aid}", 'payconfig');
|
||||
// 用户账号配置
|
||||
$user_config = isset($config['user']) ? $config['user'] : [];
|
||||
// 收款平台账号配置
|
||||
$pay_config = isset($config['pay']) ? $config['pay'] : [];
|
||||
// 配置检查
|
||||
if ($user_config && $pay_config) {
|
||||
// 账号配置信息
|
||||
$pid = $user_config['pid'];
|
||||
$aid = $pay_config['aid'];
|
||||
if (!($req_pid == $pid && $req_aid == $aid)) {
|
||||
return '监听收款配置不一致';
|
||||
}
|
||||
} else {
|
||||
return '监听收款配置文件名错误';
|
||||
}
|
||||
// 实例化支付类
|
||||
$Mpay = new \MpayClass($user_config);
|
||||
// 获取订单
|
||||
$res_new_order = $Mpay->orderHeart();
|
||||
$new_order = json_decode($res_new_order, true);
|
||||
// 检测新订单
|
||||
if ($new_order['code'] !== 1) {
|
||||
return $res_new_order;
|
||||
}
|
||||
// 订单列表
|
||||
$order_list = $new_order['orders'];
|
||||
// 检测本账号订单
|
||||
$orders = [];
|
||||
foreach ($order_list as $key => $val) {
|
||||
if ($pid == $val['pid'] && $aid == $val['aid']) {
|
||||
$orders[] = $order_list[$key];
|
||||
}
|
||||
}
|
||||
if (!$orders) {
|
||||
return \json(['code' => 0, 'msg' => '非本账号订单']);
|
||||
}
|
||||
// 收款平台
|
||||
$platform = ['sqbpay' => 'ShouQianBa', 'storepay' => 'ZhiHuiJingYing', 'mqpay' => 'MaQian', 'ysepay' => 'Ysepay'];
|
||||
// 登陆账号
|
||||
$config = ['username' => $pay_config['account'], 'password' => $pay_config['password']];
|
||||
// 收款查询
|
||||
$query = $pay_config['query'];
|
||||
// 实例监听客户端
|
||||
$payclient_name = $platform[$pay_config['platform']];
|
||||
$payclient_path = "\\payclient\\{$payclient_name}";
|
||||
$Payclient = new $payclient_path($config);
|
||||
// 获取支付明细
|
||||
$records = $Payclient->payQuery($query);
|
||||
if ($records) {
|
||||
// 提交收款记录
|
||||
$upres = $Mpay->upRecords($records, $aid);
|
||||
return $upres;
|
||||
} else {
|
||||
return \json(['code' => 0, 'msg' => '查询空订单'], 320);
|
||||
}
|
||||
}
|
||||
// 签名
|
||||
private static function getSign(array $param = [], string $key = ''): string
|
||||
{
|
||||
ksort($param);
|
||||
reset($param);
|
||||
$signstr = '';
|
||||
foreach ($param as $k => $v) {
|
||||
if ($k != "sign" && $k != "sign_type" && $v != '') {
|
||||
$signstr .= $k . '=' . $v . '&';
|
||||
}
|
||||
}
|
||||
$signstr = substr($signstr, 0, -1);
|
||||
$signstr .= $key;
|
||||
$sign = md5($signstr);
|
||||
return $sign;
|
||||
}
|
||||
// 构建通知
|
||||
private static function crateNotify($param): array
|
||||
{
|
||||
$notify = [
|
||||
'pid' => $param->pid,
|
||||
'trade_no' => $param->order_id,
|
||||
'out_trade_no' => $param->out_trade_no,
|
||||
'type' => $param->type,
|
||||
'name' => $param->name,
|
||||
'money' => $param->money,
|
||||
'trade_status' => 'TRADE_SUCCESS',
|
||||
'sign_type' => 'MD5',
|
||||
];
|
||||
// 添加扩展参数
|
||||
$notify = array_merge($notify, unserialize($param->param));
|
||||
return $notify;
|
||||
}
|
||||
// 请求外部资源
|
||||
private static function getHttpResponse($url, $header = [], $post = null, $timeout = 10)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
if ($header) {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
} else {
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
if ($post) {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
}
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
79
app/controller/PayManageController.php
Normal file
79
app/controller/PayManageController.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use app\model\Order;
|
||||
use app\model\PayAccount;
|
||||
use app\model\PayChannel;
|
||||
use think\facade\View;
|
||||
use app\model\Platform;
|
||||
|
||||
class PayManageController extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
// 加载配置文件
|
||||
$option = \think\facade\Config::load("extendconfig/platform", 'extendconfig');
|
||||
View::assign('options', $option);
|
||||
return View::fetch();
|
||||
}
|
||||
// 编辑账号
|
||||
public function editAccount()
|
||||
{
|
||||
$id = $this->request->get('id');
|
||||
$account = PayAccount::find($id);
|
||||
// 加载配置文件
|
||||
$option = \think\facade\Config::load("extendconfig/platform", 'extendconfig');
|
||||
View::assign([
|
||||
'id' => $id,
|
||||
'options' => $option,
|
||||
'platform' => $account->getData('platform'),
|
||||
'account' => $account->account,
|
||||
'password' => $account->password,
|
||||
'state' => $account->state,
|
||||
'pattern' => $account->getData('pattern')
|
||||
]);
|
||||
return View::fetch();
|
||||
}
|
||||
// 添加账号
|
||||
public function addAccount()
|
||||
{
|
||||
// 加载配置文件
|
||||
$option = \think\facade\Config::load("extendconfig/platform", 'extendconfig');
|
||||
View::assign(['options' => $option]);
|
||||
return View::fetch();
|
||||
}
|
||||
// 添加收款终端
|
||||
public function addChannel()
|
||||
{
|
||||
$aid = $this->request->get('aid');
|
||||
View::assign(['aid' => $aid]);
|
||||
return View::fetch();
|
||||
}
|
||||
// 编辑收款终端
|
||||
public function editChannel()
|
||||
{
|
||||
$cid = $this->request->get('cid');
|
||||
$channel = PayChannel::with('payAccount')->where('id', $cid)->find();
|
||||
View::assign([
|
||||
'cid' => $channel->id,
|
||||
'platform' => $channel->payAccount->platform,
|
||||
'account' => $channel->payAccount->account,
|
||||
'channel' => $channel->channel,
|
||||
'qrcode' => $channel->qrcode,
|
||||
'last_time' => $channel->last_time,
|
||||
'state' => $channel->state,
|
||||
]);
|
||||
return View::fetch();
|
||||
}
|
||||
// 收款终端列表
|
||||
public function channelList()
|
||||
{
|
||||
$id = $this->request->get('id');
|
||||
View::assign(['id' => $id]);
|
||||
return View::fetch();
|
||||
}
|
||||
}
|
||||
85
app/controller/SystemController.php
Normal file
85
app/controller/SystemController.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use think\Request;
|
||||
|
||||
class SystemController
|
||||
{
|
||||
/**
|
||||
* 显示资源列表
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return '系统设置';
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示创建资源表单页.
|
||||
*
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存新建的资源
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function save(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示指定的资源
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function read($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示编辑资源表单页.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存更新的资源
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定资源
|
||||
*
|
||||
* @param int $id
|
||||
* @return \think\Response
|
||||
*/
|
||||
public function delete($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
26
app/controller/UserController.php
Normal file
26
app/controller/UserController.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\View;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
protected $middleware = ['Auth' => ['except' => ['login']]];
|
||||
// 用户中心
|
||||
public function index()
|
||||
{
|
||||
return View::fetch();
|
||||
}
|
||||
// 登陆视图
|
||||
public function login()
|
||||
{
|
||||
if (session('?islogin')) {
|
||||
return redirect('/Console/index');
|
||||
}
|
||||
return View::fetch();
|
||||
}
|
||||
}
|
||||
186
app/controller/api/OrderController.php
Normal file
186
app/controller/api/OrderController.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api;
|
||||
|
||||
use app\BaseController;
|
||||
use app\model\Order;
|
||||
use app\model\User;
|
||||
|
||||
class OrderController extends BaseController
|
||||
{
|
||||
public function getOrders()
|
||||
{
|
||||
$query = $this->request->get();
|
||||
$orders = Order::serchOrders($query)->order('id', 'desc')->paginate(['list_rows' => $query['limit'], 'page' => $query['page']]);
|
||||
if ($orders) {
|
||||
return json(['code' => 0, 'msg' => 'OK', 'count' => $orders->total(), 'data' => $orders->items()]);
|
||||
} else {
|
||||
return json(['code' => 1, 'msg' => '无数据记录', 'count' => 0, 'data' => []]);
|
||||
}
|
||||
}
|
||||
// 修改订单支付状态
|
||||
public function changeOrderState()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
$uporder_res = Order::update(['state' => $info['state'], 'id' => $info['id']]);
|
||||
if ($uporder_res) {
|
||||
return json(\backMsg(0, '修改成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '修改失败'));
|
||||
}
|
||||
}
|
||||
// 手动补单
|
||||
public function doPayOrder()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
// 修改支付状态
|
||||
$order = Order::find($info['id']);
|
||||
$order->state = $info['state'];
|
||||
$res = $order->save();
|
||||
if ($res) {
|
||||
// 创建通知
|
||||
$notify = self::crateNotify($order);
|
||||
// 字符串签名
|
||||
$user_key = User::where('pid', $order->pid)->value('secret_key');
|
||||
$sign = self::getSign($notify, $user_key);
|
||||
$notify['sign'] = $sign;
|
||||
// 异步通知
|
||||
$res_notify = self::getHttpResponse($order->notify_url . '?' . http_build_query($notify));
|
||||
if ($res_notify === 'success') {
|
||||
return json(\backMsg(0, '订单通知成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '异步通知失败'));
|
||||
}
|
||||
} else {
|
||||
return json(\backMsg(1, '支付状态修改失败'));
|
||||
}
|
||||
}
|
||||
// 重新通知
|
||||
public function redoPayOrder()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
// 修改支付状态
|
||||
$order = Order::find($id);
|
||||
if ($order) {
|
||||
// 创建通知
|
||||
$notify = self::crateNotify($order);
|
||||
// 字符串签名
|
||||
$user_key = User::where('pid', $order->pid)->value('secret_key');
|
||||
$sign = self::getSign($notify, $user_key);
|
||||
$notify['sign'] = $sign;
|
||||
// 异步通知
|
||||
$res_notify = self::getHttpResponse($order->notify_url . '?' . http_build_query($notify));
|
||||
if ($res_notify === 'success') {
|
||||
return json(\backMsg(0, '订单通知成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '异步通知失败'));
|
||||
}
|
||||
} else {
|
||||
return json(\backMsg(1, '订单不存在'));
|
||||
}
|
||||
}
|
||||
// 删除订单
|
||||
public function deleteOrder()
|
||||
{
|
||||
$id = $this->request->post('id');
|
||||
$del_res = Order::destroy($id);
|
||||
if ($del_res) {
|
||||
return json(\backMsg(0, '删除成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '删除失败'));
|
||||
}
|
||||
}
|
||||
// 批量删除订单
|
||||
public function batchRemove()
|
||||
{
|
||||
$ids = $this->request->post('ids');
|
||||
if (!$ids) {
|
||||
return json(\backMsg(1, '参数错误'));
|
||||
}
|
||||
$del_res = Order::destroy($ids);
|
||||
if ($del_res) {
|
||||
return json(\backMsg(0, '删除成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '删除失败'));
|
||||
}
|
||||
}
|
||||
// 清空超时订单
|
||||
public function batchTimeout()
|
||||
{
|
||||
$ids = Order::scope('timeoutOrder')->column('id');
|
||||
if (!$ids) {
|
||||
return json(\backMsg(1, '无过期订单'));
|
||||
}
|
||||
$batch_del_res = Order::destroy($ids);
|
||||
if ($batch_del_res) {
|
||||
return json(\backMsg(0, '清理成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '清理失败'));
|
||||
}
|
||||
}
|
||||
|
||||
// 签名方法
|
||||
private static function getSign(array $param = [], string $key = ''): string
|
||||
{
|
||||
if (!$param)
|
||||
return '参数错误';
|
||||
if (!$key)
|
||||
return '密钥错误';
|
||||
ksort($param);
|
||||
reset($param);
|
||||
$signstr = '';
|
||||
foreach ($param as $k => $v) {
|
||||
if ($k != "sign" && $k != "sign_type" && $v != '') {
|
||||
$signstr .= $k . '=' . $v . '&';
|
||||
}
|
||||
}
|
||||
$signstr = substr($signstr, 0, -1);
|
||||
$signstr .= $key;
|
||||
$sign = md5($signstr);
|
||||
return $sign;
|
||||
}
|
||||
// 构建通知参数
|
||||
private static function crateNotify($param): array
|
||||
{
|
||||
$notify = [
|
||||
'pid' => $param->pid,
|
||||
'trade_no' => $param->order_id,
|
||||
'out_trade_no' => $param->out_trade_no,
|
||||
'type' => $param->type,
|
||||
'name' => $param->name,
|
||||
'money' => $param->money,
|
||||
'trade_status' => 'TRADE_SUCCESS',
|
||||
'sign_type' => 'MD5',
|
||||
];
|
||||
// 添加扩展参数
|
||||
$notify = array_merge($notify, unserialize($param->param));
|
||||
return $notify;
|
||||
}
|
||||
// 请求外部资源
|
||||
private static function getHttpResponse($url, $header = [], $post = null, $timeout = 10)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
if ($header) {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
} else {
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
if ($post) {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
}
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
153
app/controller/api/PayManageController.php
Normal file
153
app/controller/api/PayManageController.php
Normal file
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api;
|
||||
|
||||
use app\BaseController;
|
||||
use app\model\PayAccount;
|
||||
use app\model\PayChannel;
|
||||
use app\model\Platform;
|
||||
use think\facade\View;
|
||||
|
||||
class PayManageController extends BaseController
|
||||
{
|
||||
// 获取账号列表
|
||||
public function getPayAccount()
|
||||
{
|
||||
$query = $this->request->get();
|
||||
$accounts = PayAccount::serchAccount($query)->order('id', 'desc')->paginate(['list_rows' => $query['limit'], 'page' => $query['page']]);
|
||||
if ($accounts) {
|
||||
return json(['code' => 0, 'msg' => 'OK', 'count' => $accounts->total(), 'data' => $accounts->items()]);
|
||||
} else {
|
||||
return json(['code' => 1, 'msg' => '无数据记录', 'count' => 0, 'data' => []]);
|
||||
}
|
||||
}
|
||||
// 编辑账号
|
||||
public function editAccount()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
$up_res = PayAccount::update($info);
|
||||
if ($up_res) {
|
||||
return json(\backMsg(0, '修改成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '修改失败'));
|
||||
}
|
||||
}
|
||||
// 账号状态
|
||||
public function accountEnable()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
$up_res = PayAccount::update($info);
|
||||
if ($up_res) {
|
||||
return json(\backMsg(0, '成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '失败'));
|
||||
}
|
||||
}
|
||||
// 删除账号
|
||||
public function delAccount()
|
||||
{
|
||||
$ids = $this->request->post('ids');
|
||||
$res = PayAccount::destroy($ids);
|
||||
if ($res) {
|
||||
return \json(\backMsg(0, '已删除'));
|
||||
} else {
|
||||
return \json(\backMsg(1, '失败'));
|
||||
}
|
||||
}
|
||||
// 添加账号
|
||||
public function addAccount()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
$res = PayAccount::create($info);
|
||||
if ($res) {
|
||||
return \json(\backMsg(0, '添加成功'));
|
||||
} else {
|
||||
return \json(\backMsg(1, '添加失败'));
|
||||
}
|
||||
}
|
||||
// 添加收款终端
|
||||
public function addChannel()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
$res = PayChannel::create($info);
|
||||
if ($res) {
|
||||
return \json(\backMsg(0, '添加成功'));
|
||||
} else {
|
||||
return \json(\backMsg(1, '添加失败'));
|
||||
}
|
||||
}
|
||||
// 编辑收款终端
|
||||
public function editChannel()
|
||||
{
|
||||
$info = $this->request->post();
|
||||
$up_res = PayChannel::update($info);
|
||||
if ($up_res) {
|
||||
return json(\backMsg(0, '修改成功'));
|
||||
} else {
|
||||
return json(\backMsg(1, '修改失败'));
|
||||
}
|
||||
}
|
||||
// 收款终端列表
|
||||
public function getChannelList()
|
||||
{
|
||||
$aid = $this->request->post('aid');
|
||||
$res = PayChannel::where(['account_id' => $aid])->order('last_time', 'desc')->select();
|
||||
if ($res) {
|
||||
return \json(\backMsg(0, '获取成功', $res));
|
||||
} else {
|
||||
return \json(\backMsg(1, '失败'));
|
||||
}
|
||||
}
|
||||
// 生成账号配置
|
||||
public function createAccountConfig()
|
||||
{
|
||||
$query = [
|
||||
"date_end" => null,
|
||||
"date_start" => null,
|
||||
"page" => 1,
|
||||
"page_size" => 10,
|
||||
"upayQueryType" => 0,
|
||||
"status" => "2000",
|
||||
"store_sn" => "",
|
||||
"type" => "30"
|
||||
];
|
||||
|
||||
$data = [
|
||||
'pid' => 1001,
|
||||
'key' => '154556b80a3f02ab6b57d4199cd6ebdf',
|
||||
'aid' => 1,
|
||||
'platform' => 'sqbpay',
|
||||
'account' => '18872410423',
|
||||
'password' => '7698177hcnSQB',
|
||||
'query' => \var_export($query, \true)
|
||||
];
|
||||
$config = View::fetch('tpl/account_config', $data);
|
||||
$name = "{$data['pid']}_{$data['aid']}";
|
||||
$path = "../config/payconfig/{$name}.php";
|
||||
$res = \file_put_contents($path, $config);
|
||||
if ($res) {
|
||||
return \json(\backMsg(msg: '创建成功'));
|
||||
} else {
|
||||
return \json(\backMsg(1, '创建成功'));
|
||||
}
|
||||
}
|
||||
// 生成平台列表配置
|
||||
public function crtPlfConfig()
|
||||
{
|
||||
$info = Platform::where('state', 1)->field('platform, name')->select()->toArray();
|
||||
$data = [];
|
||||
foreach ($info as $value) {
|
||||
$data[$value['platform']] = $value['name'];
|
||||
}
|
||||
$config = View::fetch('tpl/platform_config', $data);
|
||||
$path = "../config/extendconfig/platform.php";
|
||||
$res = \file_put_contents($path, $config);
|
||||
if ($res) {
|
||||
return \json(\backMsg(msg: '创建成功'));
|
||||
} else {
|
||||
return \json(\backMsg(1, '创建成功'));
|
||||
}
|
||||
}
|
||||
}
|
||||
50
app/controller/api/UserController.php
Normal file
50
app/controller/api/UserController.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\controller\api;
|
||||
|
||||
use app\BaseController;
|
||||
use think\Request;
|
||||
use think\facade\Session;
|
||||
use app\model\User;
|
||||
|
||||
class UserController extends BaseController
|
||||
{
|
||||
protected $middleware = ['Auth' => ['except' => ['login']]];
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
$login_info = $request->post();
|
||||
$userinfo = self::checkUser($login_info);
|
||||
if ($userinfo['code'] === 0) {
|
||||
Session::set('userid', $userinfo['data']->id);
|
||||
Session::set('nickname', $userinfo['data']->nickname);
|
||||
Session::set('userrole', $userinfo['data']->role);
|
||||
Session::set('islogin', true);
|
||||
return json(\backMsg(0, 'ok'));
|
||||
} else {
|
||||
return json($userinfo);
|
||||
}
|
||||
}
|
||||
public function logout()
|
||||
{
|
||||
Session::clear();
|
||||
return json(\backMsg(0, '注销成功'));
|
||||
}
|
||||
private function checkUser(array $login_info): array
|
||||
{
|
||||
$username = $login_info['username'];
|
||||
$password = $login_info['password'];
|
||||
$userinfo = User::where('username', $username)->find();
|
||||
if ($userinfo) {
|
||||
if ($password === $userinfo->password) {
|
||||
return ['code' => 0, 'data' => $userinfo];
|
||||
} else {
|
||||
return \backMsg(1, '登陆密码错误');
|
||||
}
|
||||
} else {
|
||||
return \backMsg(2, '用户不存在');
|
||||
}
|
||||
}
|
||||
}
|
||||
17
app/event.php
Normal file
17
app/event.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
// 事件定义文件
|
||||
return [
|
||||
'bind' => [
|
||||
],
|
||||
|
||||
'listen' => [
|
||||
'AppInit' => [],
|
||||
'HttpRun' => [],
|
||||
'HttpEnd' => [],
|
||||
'LogLevel' => [],
|
||||
'LogWrite' => [],
|
||||
],
|
||||
|
||||
'subscribe' => [
|
||||
],
|
||||
];
|
||||
10
app/middleware.php
Normal file
10
app/middleware.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// 全局中间件定义文件
|
||||
return [
|
||||
// 全局请求缓存
|
||||
// \think\middleware\CheckRequestCache::class,
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
\think\middleware\SessionInit::class
|
||||
];
|
||||
30
app/middleware/Auth.php
Normal file
30
app/middleware/Auth.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
class Auth
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
// 登陆状态
|
||||
$islogin = session('?islogin');
|
||||
|
||||
if ($islogin) {
|
||||
return $next($request);
|
||||
} else {
|
||||
$method = $request->isJson();
|
||||
if ($method) {
|
||||
return \json(\backMsg(404, '身份过期,请重新登陆'));
|
||||
}
|
||||
return redirect('/User/login');
|
||||
}
|
||||
}
|
||||
}
|
||||
191
app/model/Order.php
Normal file
191
app/model/Order.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use app\BaseModel;
|
||||
use app\model\PayAccount;
|
||||
use app\model\PayChannel;
|
||||
|
||||
class Order extends BaseModel
|
||||
{
|
||||
// 订单有效期
|
||||
private static $activity_time = 180;
|
||||
// 新建订单
|
||||
public static function createOrder($data)
|
||||
{
|
||||
$my_time = time();
|
||||
$channel = self::setChannel($data['pid']);
|
||||
$new_order = [
|
||||
// 订单号
|
||||
'order_id' => self::createOrderID('H'),
|
||||
// 商户ID
|
||||
'pid' => $data['pid'],
|
||||
// 支付类型
|
||||
'type' => $data['type'],
|
||||
// 商户订单号
|
||||
'out_trade_no' => $data['out_trade_no'],
|
||||
// 异步通知
|
||||
'notify_url' => $data['notify_url'],
|
||||
// 跳转通知
|
||||
'return_url' => isset($data['return_url']) ? $data['return_url'] : '',
|
||||
// 商品名称
|
||||
'name' => $data['name'],
|
||||
// 商品金额
|
||||
'money' => $data['money'],
|
||||
// 实际成交金额
|
||||
'really_price' => self::checkMoney($data['money'], $data['type'], $channel['aid'], $channel['cid']),
|
||||
// 用户IP
|
||||
'clientip' => isset($data['clientip']) ? $data['clientip'] : '',
|
||||
// 设备类型
|
||||
'device' => isset($data['device']) ? $data['device'] : '',
|
||||
// 业务扩展参数
|
||||
'param' => serialize(self::getParams($data)),
|
||||
// 等待/过期:0, 支付成功:1
|
||||
'state' => 0,
|
||||
// 订单创建时间
|
||||
'create_time' => self::getFormatTime($my_time),
|
||||
// 订单关闭时间
|
||||
'close_time' => self::getFormatTime($my_time + self::$activity_time),
|
||||
// 支付时间
|
||||
'pay_time' => self::getFormatTime($my_time),
|
||||
// 收款账号id
|
||||
'aid' => $channel['aid'],
|
||||
// 交易终端id
|
||||
'cid' => $channel['cid'],
|
||||
];
|
||||
$res = self::create($new_order);
|
||||
if ($res->order_id) {
|
||||
return $res->order_id;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 查询订单列表
|
||||
public static function serchOrders($query)
|
||||
{
|
||||
$select = [];
|
||||
$_select = [];
|
||||
$allow_field = ['id', 'order_id', 'pid', 'type', 'out_trade_no', 'notify_url', 'return_url', 'name', 'really_price', 'money', 'clientip', 'device', 'state', 'create_time_start', 'create_time_end', 'close_time', 'pay_time', 'platform', 'platform_order', 'aid', 'cid',];
|
||||
foreach ($query as $key => $value) {
|
||||
if (in_array($key, $allow_field) && isset($value)) {
|
||||
if ($key === 'name') {
|
||||
$select[] = ['Order.' . $key, 'like', '%' . $value . '%'];
|
||||
continue;
|
||||
}
|
||||
if ($key === 'create_time_start') {
|
||||
$select[] = ['Order.' . 'create_time', '>', $value];
|
||||
continue;
|
||||
}
|
||||
if ($key === 'create_time_end') {
|
||||
$select[] = ['Order.' . 'create_time', '<', $value];
|
||||
continue;
|
||||
}
|
||||
if ($key === 'platform') {
|
||||
$_select['platform'] = $value;
|
||||
continue;
|
||||
}
|
||||
$select[] = ['Order.' . $key, '=', $value];
|
||||
}
|
||||
}
|
||||
return self::with('payAccount')
|
||||
->hasWhere('payAccount', function ($query) use ($_select) {
|
||||
$query->where($_select);
|
||||
})
|
||||
->where($select);
|
||||
}
|
||||
// 查询订单详细
|
||||
public static function showOrderDetail($id)
|
||||
{
|
||||
$order = self::find($id);
|
||||
$a_list = PayAccount::with('payChannel')->hasWhere('payChannel', ['id' => $order->cid])->where('PayAccount.id', $order->aid)->find();
|
||||
if (!$order) {
|
||||
return [];
|
||||
}
|
||||
$order->platform = $a_list->platform ?? '···';
|
||||
$order->account = $a_list->account ?? '···';
|
||||
$order->channel = $a_list->payChannel[0]->channel ?? '···';
|
||||
$order->qrcode = $a_list->payChannel[0]->qrcode ?? '···';
|
||||
return $order->toArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 选择收款通道
|
||||
private static function setChannel($pid): array
|
||||
{
|
||||
$aids = PayAccount::where('pid', $pid)->where('state', 1)->column('id');
|
||||
$channel_info = PayChannel::whereIn('account_id', $aids)->where('state', 1)->order('last_time', 'asc')->find();
|
||||
if (!$channel_info || !$aids) {
|
||||
return [];
|
||||
}
|
||||
$channel = ['aid' => $channel_info->account_id, 'cid' => $channel_info->id];
|
||||
PayChannel::update(['last_time' => self::getFormatTime(), 'id' => $channel['cid']]);
|
||||
return $channel;
|
||||
}
|
||||
// 获取扩展参数数组
|
||||
private static function getParams(array $data): array
|
||||
{
|
||||
$keys = ['pid', 'type', 'out_trade_no', 'notify_url', 'return_url', 'name', 'money', 'sign', 'sign_type'];
|
||||
$params = [];
|
||||
foreach ($data as $key => $value) {
|
||||
if (!in_array($key, $keys)) {
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
// 检查金额
|
||||
private static function checkMoney($money, $type, $aid, $cid): float
|
||||
{
|
||||
$money = (float) $money;
|
||||
// 查询有效订单
|
||||
$query = self::scope('activeOrder')->where(['type' => $type, 'aid' => $aid, 'cid' => $cid]);
|
||||
$activeOrders = $query->column('really_price');
|
||||
$num = count($activeOrders);
|
||||
if ($num > 0) {
|
||||
for ($i = 0; $i < $num; $i++) {
|
||||
if (in_array($money, $activeOrders)) {
|
||||
$money += 0.01;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $money;
|
||||
}
|
||||
// 获取格式时间
|
||||
private static function getFormatTime($time = 0)
|
||||
{
|
||||
if ($time) {
|
||||
return date('Y-m-d H:i:s', $time);
|
||||
}
|
||||
return date('Y-m-d H:i:s', time());
|
||||
}
|
||||
// 生成订单号
|
||||
private static function createOrderID(string $prefix = ''): string
|
||||
{
|
||||
return $prefix . date('Ymd') . substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
|
||||
}
|
||||
// 查询有效期内的未支付订单
|
||||
public function scopeActiveOrder($query)
|
||||
{
|
||||
$query->where('close_time', '>', self::getFormatTime())->where('state', 0);
|
||||
}
|
||||
// 查询有效期内的成交订单
|
||||
public function scopeDealOrder($query)
|
||||
{
|
||||
$query->where('close_time', '>', self::getFormatTime())->where('state', 1);
|
||||
}
|
||||
// 查询超时过期订单
|
||||
public function scopeTimeoutOrder($query)
|
||||
{
|
||||
$query->where('close_time', '<', self::getFormatTime())->where('state', 0);
|
||||
}
|
||||
// 模型多对一关联
|
||||
public function payAccount()
|
||||
{
|
||||
return $this->belongsTo(PayAccount::class, 'aid', 'id');
|
||||
}
|
||||
}
|
||||
45
app/model/PayAccount.php
Normal file
45
app/model/PayAccount.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use app\BaseModel;
|
||||
|
||||
class PayAccount extends BaseModel
|
||||
{
|
||||
// 查询账号列表
|
||||
public static function serchAccount($query)
|
||||
{
|
||||
$select = [];
|
||||
$allow_field = ['state', 'platform', 'account', 'pattern'];
|
||||
foreach ($query as $key => $value) {
|
||||
if (in_array($key, $allow_field) && isset($value)) {
|
||||
if ($key === 'account') {
|
||||
$select[] = [$key, 'like', '%' . $value . '%'];
|
||||
continue;
|
||||
}
|
||||
$select[] = [$key, '=', $value];
|
||||
}
|
||||
}
|
||||
return self::withCount(['payChannel' => 'channel'])->where($select);
|
||||
}
|
||||
// 获取器
|
||||
public function getPlatformAttr($value)
|
||||
{
|
||||
// 加载平台配置
|
||||
$platform = \think\facade\Config::load("extendconfig/platform", 'extendconfig');
|
||||
return $platform[$value];
|
||||
}
|
||||
public function getPatternAttr($value)
|
||||
{
|
||||
// 监听模式
|
||||
$pattern = ['0' => '单次监听·被动', '1' => '连续监听·主动'];
|
||||
return $pattern[$value];
|
||||
}
|
||||
// 一对多关联
|
||||
public function payChannel()
|
||||
{
|
||||
return $this->hasMany(PayChannel::class, 'account_id', 'id');
|
||||
}
|
||||
}
|
||||
16
app/model/PayChannel.php
Normal file
16
app/model/PayChannel.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use app\BaseModel;
|
||||
|
||||
class PayChannel extends BaseModel
|
||||
{
|
||||
// 模型多对一关联
|
||||
public function payAccount()
|
||||
{
|
||||
return $this->belongsTo(PayAccount::class, 'account_id', 'id');
|
||||
}
|
||||
}
|
||||
15
app/model/Platform.php
Normal file
15
app/model/Platform.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use app\BaseModel;
|
||||
|
||||
class Platform extends BaseModel
|
||||
{
|
||||
// use SoftDelete;
|
||||
// protected $deleteTime = 'delete_time';
|
||||
|
||||
|
||||
}
|
||||
46
app/model/User.php
Normal file
46
app/model/User.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\model;
|
||||
|
||||
use app\BaseModel;
|
||||
|
||||
class User extends BaseModel
|
||||
{
|
||||
// 验证用户
|
||||
public static function checkUser($pid, $sign)
|
||||
{
|
||||
$user = self::where('pid', $pid)->find();
|
||||
$sign2 = md5($user->pid . $user->secret_key);
|
||||
if ($sign === $sign2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 创建用户
|
||||
public static function createUser(array $userinfo)
|
||||
{
|
||||
$last_pid = self::withTrashed()->max('pid');
|
||||
$find_username = self::withTrashed()->where(['username' => $userinfo['username']])->find();
|
||||
if ($find_username) {
|
||||
return 1; // 账户已注册
|
||||
}
|
||||
$pid = $last_pid ? $last_pid + 1 : 1000;
|
||||
$secret = md5($pid . time() . mt_rand());
|
||||
$res = self::create(['pid' => $pid, 'secret_key' => $secret, 'username' => $userinfo['username'], 'password' => $userinfo['password'], 'nickname' => self::getNickname('小可爱', 5)]);
|
||||
return $res;
|
||||
}
|
||||
// 随机用户昵称
|
||||
private static function getNickname($pre = '', $length = 8)
|
||||
{
|
||||
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.';
|
||||
$charactersLength = strlen($characters);
|
||||
$randomString = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$randomString .= $characters[rand(0, $charactersLength - 1)];
|
||||
}
|
||||
return $pre . $randomString;
|
||||
}
|
||||
}
|
||||
9
app/provider.php
Normal file
9
app/provider.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
use app\ExceptionHandle;
|
||||
use app\Request;
|
||||
|
||||
// 容器Provider定义文件
|
||||
return [
|
||||
'think\Request' => Request::class,
|
||||
'think\exception\Handle' => ExceptionHandle::class,
|
||||
];
|
||||
9
app/service.php
Normal file
9
app/service.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
use app\AppService;
|
||||
|
||||
// 系统服务定义文件
|
||||
// 服务在完成全局初始化之后执行
|
||||
return [
|
||||
AppService::class,
|
||||
];
|
||||
Reference in New Issue
Block a user