16 Commits

Author SHA1 Message Date
技术老胡
4eef7f0797 更新二维码通道添加指引 2024-12-23 15:24:57 +08:00
技术老胡
dfb8edff22 修复通道测试服务器报500错误 2024-12-21 20:16:06 +08:00
技术老胡
05c1b08e95 修复图片上传文件漏洞 2024-12-20 11:16:57 +08:00
技术老胡
de848ab32b 更新一些细节 2024-12-18 17:56:40 +08:00
技术老胡
3f5866ea16 更新文档 2024-12-18 09:21:21 +08:00
技术老胡
fb2f8f2f2c 优化代码结构 2024-12-17 14:43:59 +08:00
技术老胡
62989e4100 更新支持云闪付通道 2024-12-17 11:53:03 +08:00
技术老胡
eeb877bd87 修改没有收款码,程序报BUG问题 2024-12-16 15:36:55 +08:00
技术老胡
e9f64988a9 更新文件 2024-12-16 14:15:27 +08:00
技术老胡
f62d4cd103 更新结构 2024-12-16 14:14:02 +08:00
技术老胡
331b0b2d56 更新逻辑 2024-12-16 12:52:52 +08:00
技术老胡
e5871d91c5 加添微信支付商业版通道 2024-12-16 11:00:27 +08:00
技术老胡
898daee64c 文件调整 2024-12-14 09:22:00 +08:00
技术老胡
b266e1ad7c 更新文件结构 2024-12-12 17:14:01 +08:00
技术老胡
e85e71f8d9 更新后台管理接口 2024-12-12 16:45:57 +08:00
技术老胡
6a8ec71b8d 收款通知逻辑更新,完全改为本地接口,避免网络提交带来的延迟 2024-12-12 16:34:39 +08:00
26 changed files with 199 additions and 344 deletions

12
!!.env
View File

@@ -1,12 +0,0 @@
APP_DEBUG = true
DB_TYPE = mysql
DB_HOST = 127.0.0.1
DB_NAME = test
DB_USER = test
DB_PASS = 123456
DB_PORT = 3306
DB_CHARSET = utf8
DB_PREFIX = mpay_
DEFAULT_LANG = zh-cn

View File

@@ -369,7 +369,7 @@ V免签是一款开源免费适用于个人收款使用的收款程序原理
##### **转发规则** ##### **转发规则**
添加应用转发规则,**微信**和**支付宝**需要分别设置 添加应用转发规则,**微信**和**支付宝**需要分别设置,请注意选择**应用**规则
![](assets/20241204_172656_image.png) ![](assets/20241204_172656_image.png)

View File

@@ -13,14 +13,14 @@ class ConsoleController extends BaseController
// 后台主页 // 后台主页
public function index() public function index()
{ {
View::assign('version', 'v1.0.1'); View::assign('version', 'v1');
return View::fetch(); return View::fetch();
} }
// 管理菜单 // 管理菜单
public function menu() public function menu()
{ {
// 加载菜单配置 // 加载菜单配置
$menu = \think\facade\Config::load("extendconfig/menu", 'extendconfig'); $menu = \think\facade\Config::load("extend/menu", 'extend');
return json($menu); return json($menu);
} }
// 管理菜单 // 管理菜单

View File

@@ -22,7 +22,6 @@ class IndexController
} }
public function test() public function test()
{ {
return View::fetch();
return app()->getBasePath();
} }
} }

View File

@@ -6,6 +6,7 @@ use think\Request;
use think\facade\View; use think\facade\View;
use app\model\User; use app\model\User;
use app\model\Order; use app\model\Order;
use app\model\PayAccount;
use app\model\PayChannel; use app\model\PayChannel;
class PayController class PayController
@@ -19,70 +20,41 @@ class PayController
'POST' => $request->post(), 'POST' => $request->post(),
default => [] default => []
}; };
if (!$req_data) { if (!$req_data) return '参数错误';
return '参数错误'; // 验证签名
}
$key = User::where('pid', $req_data['pid'])->where('state', 1)->value('secret_key'); $key = User::where('pid', $req_data['pid'])->where('state', 1)->value('secret_key');
if (!$key) { if (!$key) return '用户禁用或不存在';
return '用户禁用或不存在';
}
$sign_str = self::getSign($req_data, $key); $sign_str = self::getSign($req_data, $key);
if ($req_data['sign'] === $sign_str) { if ($req_data['sign'] !== $sign_str) return '签名错误';
// 检查商户订单 // 检查商户订单
$out_trade_no = Order::where('out_trade_no', $req_data['out_trade_no'])->value('out_trade_no'); $out_trade_no = Order::where('out_trade_no', $req_data['out_trade_no'])->value('out_trade_no');
if (!$out_trade_no) { if ($out_trade_no) return '订单提交重复';
// 创建新订单 // 创建新订单
$order_id = Order::createOrder($req_data); $order_id = Order::createOrder($req_data);
if ($order_id) { if (!$order_id) return '创建订单失败';
return redirect("/Pay/console/{$order_id}"); return redirect("/Pay/console/{$order_id}");
} else {
return '创建订单失败';
}
} else {
return '订单提交重复';
}
} else {
return '签名错误';
}
} }
// api提交订单 // api提交订单
public function mapi(Request $request) public function mapi(Request $request)
{ {
if ($request->isPost()) { if (!$request->isPost()) return '请使用POST方式提交';
$req_data = $request->post(); $req_data = $request->post();
if (!$req_data) { if (!$req_data) $req_data = $request->get();
$req_data = $request->get(); if (!$req_data) return '参数错误';
if (!$req_data) { // 验证签名
return '参数错误';
}
}
} else {
return '请使用POST方式提交';
}
$key = User::where('pid', $req_data['pid'])->where('state', 1)->value('secret_key'); $key = User::where('pid', $req_data['pid'])->where('state', 1)->value('secret_key');
if (!$key) { if (!$key) return '用户禁用或不存在';
return '用户禁用或不存在';
}
$sign_str = self::getSign($req_data, $key); $sign_str = self::getSign($req_data, $key);
if ($req_data['sign'] === $sign_str) { if ($req_data['sign'] !== $sign_str) return '签名错误';
// 检查商户订单 // 检查商户订单
$out_trade_no = Order::where('out_trade_no', $req_data['out_trade_no'])->value('out_trade_no'); $out_trade_no = Order::where('out_trade_no', $req_data['out_trade_no'])->value('out_trade_no');
if (!$out_trade_no) { if ($out_trade_no) return '订单提交重复';
// 创建新订单 // 创建新订单
$order_id = Order::createOrder($req_data); $order_id = Order::createOrder($req_data);
if ($order_id) { if (!$order_id) return '创建订单失败';
$payurl = $request->domain() . "/Pay/console/{$order_id}"; $payurl = $request->domain() . "/Pay/console/{$order_id}";
$info = ['code' => 1, 'msg' => '订单创建成功', 'trade_no' => $order_id, 'qrcode' => $payurl]; $info = ['code' => 1, 'msg' => '订单创建成功', 'trade_no' => $order_id, 'qrcode' => $payurl];
return json($info); return json($info);
} else {
return '创建订单失败';
}
} else {
return '订单提交重复';
}
} else {
return '签名错误';
}
} }
// 收银台 // 收银台
public function console($order_id = '') public function console($order_id = '')
@@ -157,31 +129,20 @@ class PayController
} }
} }
// 处理收款通知 // 处理收款通知
public function payHeart(Request $request) private function payHeart(array $records, array $config)
{ {
$pid = $request->get('pid'); $pid = $config['pid'];
$aid = $request->get('aid'); $aid = $config['aid'];
$sign = $request->get('sign');
// 检测请求参数
if (!($pid && $aid && $sign)) {
return json(['code' => 0, 'msg' => '参数错误']);
}
// 检测收款通知 // 检测收款通知
$payList = $request->post(); if (!$records) {
if (!$payList) {
return json(['code' => 0, 'msg' => '空收款通知']); return json(['code' => 0, 'msg' => '空收款通知']);
} }
// 签名验证
$is_user = User::checkUser($pid, $sign);
if (!$is_user) {
return json(['code' => 0, 'msg' => '签名错误']);
}
// 当前用户账号 // 当前用户账号
$query = ['pid' => $pid, 'aid' => $aid]; $query = ['pid' => $pid, 'aid' => $aid];
// 排除已支付订单 // 排除已支付订单
$doneOrders = Order::scope('dealOrder')->where($query)->column('platform_order'); $doneOrders = Order::scope('dealOrder')->where($query)->column('platform_order');
$new_orders = []; $new_orders = [];
foreach ($payList as $order) { foreach ($records as $order) {
if (!in_array($order['order_no'], $doneOrders)) $new_orders[] = $order; if (!in_array($order['order_no'], $doneOrders)) $new_orders[] = $order;
} }
if (!count($new_orders)) return json(['code' => 0, 'msg' => '收款通知无新消息']); if (!count($new_orders)) return json(['code' => 0, 'msg' => '收款通知无新消息']);
@@ -233,66 +194,47 @@ class PayController
return ['order' => $order->order_id, 'code' => 0, 'msg' => 'notify fail']; return ['order' => $order->order_id, 'code' => 0, 'msg' => 'notify fail'];
} }
} }
// [定时任务]获取收款明细,提交收款通知[本地版] // [定时任务]获取收款明细,提交收款通知
public function checkPayResult(Request $request) public function checkPayResult(Request $request)
{ {
$req_info = $request->get(); $req_info = $request->get();
$req_pid = $req_info['pid']; $req_pid = $req_info['pid'];
$req_aid = $req_info['aid']; $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 '监听收款配置文件名错误';
}
// 当前站点
$user_config['host'] = \request()->domain();
// 实例化支付类
$Mpay = new \MpayClass($user_config);
// 获取订单 // 获取订单
$res_new_order = $Mpay->orderHeart(); $order_path = runtime_path() . '/order.json';
$new_order = json_decode($res_new_order, true); if (!file_exists($order_path)) return json(['code' => 3, 'msg' => '订单文件不存在']);
$new_order = json_decode(file_get_contents($order_path), true);
// 检测新订单 // 检测新订单
if ($new_order['code'] !== 1) return $res_new_order; if ($new_order['code'] !== 1) return json($new_order);
// 订单列表 // 订单列表
$order_list = $new_order['orders']; $order_list = $new_order['orders'];
// 检测本账号订单 // 检测本账号订单
$orders = []; $orders = [];
foreach ($order_list as $key => $val) { foreach ($order_list as $key => $val) {
if ($pid == $val['pid'] && $aid == $val['aid'] && $val['patt'] == 1) { if ($req_pid == $val['pid'] && $req_aid == $val['aid'] && $val['patt'] == 1) {
$orders[] = $order_list[$key]; $orders[] = $order_list[$key];
} }
} }
if (!$orders) { if (!$orders) return json(['code' => 0, 'msg' => '非本账号订单或监听模式不对']);
return \json(['code' => 0, 'msg' => '非本账号订单或监听模式不对']); // 加载配置文件
} $config = PayAccount::getAccountConfig($req_aid);
if ($config === false) return json(['code' => 4, 'msg' => '监听收款配置错误']);
// 登陆账号 // 登陆账号
$config = ['username' => $pay_config['account'], 'password' => $pay_config['password']]; $pay_config = ['username' => $config['account'], 'password' => $config['password']];
// 收款查询 // 收款查询
$query = $pay_config['query']; $query = $config['query'];
// 实例监听客户端 // 实例监听客户端
$payclient_name = $pay_config['payclass']; $payclient_name = $config['payclass'];
$payclient_path = "\\payclient\\{$payclient_name}"; $payclient_path = "\\payclient\\{$payclient_name}";
$Payclient = new $payclient_path($config); $Payclient = new $payclient_path($pay_config);
// 获取支付明细 // 获取支付明细
$records = $Payclient->getOrderInfo($query); $records = $Payclient->getOrderInfo($query);
if ($records) { if ($records) {
// 提交收款记录 // 提交收款记录
$upres = $Mpay->upRecords($records, $aid); $upres = $this->payHeart($records, $config);
return $upres; return $upres;
} else { } else {
return \json(['code' => 0, 'msg' => '查询空订单'], 320); return json(['code' => 0, 'msg' => '查询空订单'], 320);
} }
} }
// [定时任务]监听新订单,生成JSON文件信息 // [定时任务]监听新订单,生成JSON文件信息
@@ -337,10 +279,14 @@ class PayController
$action = isset($info['action']) ? $info['action'] : ''; $action = isset($info['action']) ? $info['action'] : '';
if ($action === 'mpay') { if ($action === 'mpay') {
$data = json_decode($info['data'], true); $data = json_decode($info['data'], true);
$config = \think\facade\Config::load("payconfig/{$data['pid']}_{$data['aid']}", 'payconfig'); if (!is_array($data)) return 200;
$payclient_path = "\\payclient\\{$config['pay']['payclass']}"; if(!isset($data['aid']) || !isset($data['pid'])) return 202;
$Payclient = new $payclient_path($info, $config, $request->domain()); $config = PayAccount::getAccountConfig($data['aid'], $data['pid']);
$Payclient->notify(); $payclient_path = "\\payclient\\{$config['payclass']}";
$Payclient = new $payclient_path($info, $config);
$res = $Payclient->notify();
if (is_int($res)) return $res;
$this->payHeart($res, $config);
return 200; return 200;
} else { } else {
return 202; return 202;

View File

@@ -7,7 +7,6 @@ namespace app\controller\api;
use app\BaseController; use app\BaseController;
use app\model\PayAccount; use app\model\PayAccount;
use app\model\PayChannel; use app\model\PayChannel;
use app\model\User;
class PayManageController extends BaseController class PayManageController extends BaseController
{ {
@@ -28,9 +27,9 @@ class PayManageController extends BaseController
$aid = $this->request->post('aid'); $aid = $this->request->post('aid');
$res = PayChannel::where(['account_id' => $aid])->order('last_time', 'desc')->select(); $res = PayChannel::where(['account_id' => $aid])->order('last_time', 'desc')->select();
if ($res) { if ($res) {
return \json(\backMsg(0, '获取成功', $res)); return json(backMsg(0, '获取成功', $res));
} else { } else {
return \json(\backMsg(1, '失败')); return json(backMsg(1, '失败'));
} }
} }
// 账号状态 // 账号状态
@@ -39,9 +38,9 @@ class PayManageController extends BaseController
$info = $this->request->post(); $info = $this->request->post();
$up_res = PayAccount::update($info); $up_res = PayAccount::update($info);
if ($up_res) { if ($up_res) {
return json(\backMsg(0, '成功')); return json(backMsg(0, '成功'));
} else { } else {
return json(\backMsg(1, '失败')); return json(backMsg(1, '失败'));
} }
} }
// 添加账号 // 添加账号
@@ -53,17 +52,13 @@ class PayManageController extends BaseController
$info['params'] = '{}'; $info['params'] = '{}';
$check_acc = PayAccount::where(['account' => $info['account'], 'platform' => $info['platform'], 'pid' => $pid])->find(); $check_acc = PayAccount::where(['account' => $info['account'], 'platform' => $info['platform'], 'pid' => $pid])->find();
if ($check_acc) { if ($check_acc) {
return \json(\backMsg(1, '账号已存在')); return json(backMsg(1, '账号已存在'));
} }
$acc = PayAccount::create($info); $acc = PayAccount::create($info);
if ($acc) { if ($acc) {
$state = $this->createAccountConfig($acc); return json(backMsg(0, '添加成功'));
if (!$state) {
return json(\backMsg(1, '自字义参数错误'));
}
return \json(\backMsg(0, '添加成功'));
} else { } else {
return \json(\backMsg(1, '添加失败')); return json(backMsg(1, '添加失败'));
} }
} }
// 编辑账号 // 编辑账号
@@ -72,14 +67,9 @@ class PayManageController extends BaseController
$info = $this->request->post(); $info = $this->request->post();
$up_res = PayAccount::update($info); $up_res = PayAccount::update($info);
if ($up_res) { if ($up_res) {
$acc = PayAccount::find($info['id']); return json(backMsg(0, '修改成功'));
$state = $this->createAccountConfig($acc);
if (!$state) {
return json(\backMsg(1, '自字义参数错误'));
}
return json(\backMsg(0, '修改成功'));
} else { } else {
return json(\backMsg(1, '修改失败')); return json(backMsg(1, '修改失败'));
} }
} }
// 删除账号 // 删除账号
@@ -89,13 +79,9 @@ class PayManageController extends BaseController
$res = PayAccount::destroy($ids); $res = PayAccount::destroy($ids);
$res2 = PayChannel::whereIn('account_id', $ids)->select()->delete(); $res2 = PayChannel::whereIn('account_id', $ids)->select()->delete();
if ($res && $res2) { if ($res && $res2) {
$accs = PayAccount::whereIn('id', $ids)->withTrashed()->select(); return json(backMsg(0, '已删除'));
foreach ($accs as $acc) {
$this->delAccountConfig($acc);
}
return \json(\backMsg(0, '已删除'));
} else { } else {
return \json(\backMsg(1, '失败')); return json(backMsg(1, '失败'));
} }
} }
// 添加收款终端 // 添加收款终端
@@ -104,13 +90,13 @@ class PayManageController extends BaseController
$info = $this->request->post(); $info = $this->request->post();
$check = PayChannel::where(['account_id' => $info['account_id'], 'channel' => $info['channel']])->count(); $check = PayChannel::where(['account_id' => $info['account_id'], 'channel' => $info['channel']])->count();
if ($check) { if ($check) {
return \json(\backMsg(1, '编号已存在')); return json(backMsg(1, '编号已存在'));
} }
$res = PayChannel::create($info); $res = PayChannel::create($info);
if ($res) { if ($res) {
return \json(\backMsg(0, '添加成功')); return json(backMsg(0, '添加成功'));
} else { } else {
return \json(\backMsg(1, '添加失败')); return json(backMsg(1, '添加失败'));
} }
} }
// 编辑收款终端 // 编辑收款终端
@@ -119,9 +105,9 @@ class PayManageController extends BaseController
$info = $this->request->post(); $info = $this->request->post();
$up_res = PayChannel::update($info); $up_res = PayChannel::update($info);
if ($up_res) { if ($up_res) {
return json(\backMsg(0, '修改成功')); return json(backMsg(0, '修改成功'));
} else { } else {
return json(\backMsg(1, '修改失败')); return json(backMsg(1, '修改失败'));
} }
} }
// 删除收款终端 // 删除收款终端
@@ -130,31 +116,36 @@ class PayManageController extends BaseController
$cid = $this->request->post('id'); $cid = $this->request->post('id');
$res = PayChannel::destroy($cid); $res = PayChannel::destroy($cid);
if ($res) { if ($res) {
return \json(\backMsg(0, '已删除')); return json(backMsg(0, '已删除'));
} else { } else {
return \json(\backMsg(1, '失败')); return json(backMsg(1, '失败'));
}
}
// 删除账号配置
public function delAccountConfig($acc)
{
$path = config_path() . "/payconfig/{$acc->pid}_{$acc->id}.php";
if (file_exists($path)) {
unlink($path);
} }
} }
// 上传二维码图片 // 上传二维码图片
public function uploadQrcode() public function uploadQrcode()
{ {
$img = $this->request->file('codeimg'); $img = $this->request->file('codeimg');
if (!$img) {
return json(backMsg(1, '请选择要上传的文件'));
}
// 验证文件类型
$allowedTypes = ['image/png', 'image/jpeg', 'image/gif'];
$fileMimeType = $img->getMime();
if (!in_array($fileMimeType, $allowedTypes)) {
return json(backMsg(1, '只允许上传PNG、JPEG或GIF格式的图片'));
}
// 生成唯一文件名
$filename = 'img_' . time() . '_' . uniqid() . '.' . $img->getOriginalExtension();
// 设置文件保存路径
$path = public_path() . '/files/qrcode/'; $path = public_path() . '/files/qrcode/';
if (!is_dir($path)) { if (!is_dir($path)) {
mkdir($path, 0777, true); mkdir($path, 0755, true);
} }
$info = $img->move($path, 'img' . time() . '.' . $img->getOriginalExtension()); // 移动文件到指定目录
$info = $img->move($path, $filename);
if ($info) { if ($info) {
$imgpath = '/files/qrcode/'; $imgpath = '/files/qrcode/' . $filename;
return json(backMsg(0, '上传成功', ['imgpath' => $imgpath . $info->getFilename()])); return json(backMsg(0, '上传成功', ['imgpath' => $imgpath]));
} else { } else {
return json(backMsg(1, '上传失败')); return json(backMsg(1, '上传失败'));
} }
@@ -166,25 +157,17 @@ class PayManageController extends BaseController
$req_pid = $req_info['pid']; $req_pid = $req_info['pid'];
$req_aid = $req_info['aid']; $req_aid = $req_info['aid'];
// 加载配置文件 // 加载配置文件
$config = \think\facade\Config::load("payconfig/{$req_pid}_{$req_aid}", 'payconfig'); $config = PayAccount::getAccountConfig($req_aid);
// 收款平台账号配置 if ($config === false) return json(backMsg(1, '账号配置文件错误'));
$pay_config = isset($config['pay']) ? $config['pay'] : []; if ($req_aid != $config['aid'] || $req_pid != session('pid')) return json(backMsg(1, '监听收款配置不一致'));
// 配置检查
if ($pay_config) {
// 账号配置信息
$aid = $pay_config['aid'];
if ($req_aid != $aid) return '监听收款配置不一致';
} else {
return '监听收款配置文件名错误';
}
// 登陆账号 // 登陆账号
$config = ['username' => $pay_config['account'], 'password' => $pay_config['password']]; $pay_config = ['username' => $config['account'], 'password' => $config['password']];
// 收款查询 // 收款查询
$query = $pay_config['query']; $query = $config['query'];
// 实例监听客户端 // 实例监听客户端
$payclient_name = $pay_config['payclass']; $payclient_name = $config['payclass'];
$payclient_path = "\\payclient\\{$payclient_name}"; $payclient_path = "\\payclient\\{$payclient_name}";
$Payclient = new $payclient_path($config); $Payclient = new $payclient_path($pay_config);
// 获取支付明细 // 获取支付明细
$records = $Payclient->getOrderInfo($query); $records = $Payclient->getOrderInfo($query);
if ($records) { if ($records) {
@@ -194,51 +177,4 @@ class PayManageController extends BaseController
return json(backMsg(1, '查询空订单')); return json(backMsg(1, '查询空订单'));
} }
} }
// 生成账号配置
private function createAccountConfig($acc)
{
$params = \json_decode($acc->params, \true);
if ($params === null) {
return false; // 自定义参数错误
}
$platform = \app\controller\api\PluginController::getPluginInfo($acc->getData('platform'));
$user = User::where('pid', $acc->pid)->find();
$query_tpl = $platform['query'];
$query = var_export(\array_merge($query_tpl, $params), \true);
$config = <<<EOF
<?php
// +----------------------------------------------------------------------
// | 支付监听配置,一个文件,一个账号
// +----------------------------------------------------------------------
return [
// 用户账号配置
'user' => [
'pid' => {$user->pid},
'key' => '{$user->secret_key}'
],
// 收款平台账号配置
'pay' => [
// 账号id
'aid' => $acc->id,
// 收款平台
'platform' => '{$acc->getData('platform')}',
// 插件类名
'payclass' => '{$platform['class_name']}',
// 账号
'account' => '{$acc->account}',
// 密码
'password' => '{$acc->password}',
// 订单查询参数配置
'query' => {$query},
]
];
EOF;
$name = "{$user->pid}_{$acc->id}";
$path = config_path() . "/payconfig/{$name}.php";
\file_put_contents($path, $config);
return true;
}
} }

View File

@@ -171,7 +171,7 @@ class PluginController extends BaseController
// 获取插件配置 // 获取插件配置
private static function getPluginConfig(): array private static function getPluginConfig(): array
{ {
$payplugin_path = config_path() . '/extendconfig/payplugin.php'; $payplugin_path = config_path() . '/extend/payplugin.php';
if (!file_exists($payplugin_path)) { if (!file_exists($payplugin_path)) {
return []; return [];
} }
@@ -182,7 +182,7 @@ class PluginController extends BaseController
// 保存插件配置 // 保存插件配置
private function savePluginConfig(array $config, string $note = '说明') private function savePluginConfig(array $config, string $note = '说明')
{ {
$payplugin_path = config_path() . '/extendconfig/payplugin.php'; $payplugin_path = config_path() . '/extend/payplugin.php';
$note_tpl = <<<EOF $note_tpl = <<<EOF
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | $note // | $note

View File

@@ -13,11 +13,11 @@ class Order extends BaseModel
// 订单有效期 // 订单有效期
private static $activity_time = 180; private static $activity_time = 180;
// 新建订单 // 新建订单
public static function createOrder($data) public static function createOrder($data): string|false
{ {
$my_time = time(); $my_time = time();
$channel = self::setChannel($data['pid'], $data['type']); $channel = self::setChannel($data['pid'], $data['type']);
if(!$channel) return false; if (!$channel) return false;
$new_order = [ $new_order = [
// 订单号 // 订单号
'order_id' => self::createOrderID('H'), 'order_id' => self::createOrderID('H'),
@@ -122,10 +122,10 @@ class Order extends BaseModel
$channel_infos = PayChannel::whereIn('account_id', $aids)->where('state', 1)->order('last_time', 'asc')->select(); $channel_infos = PayChannel::whereIn('account_id', $aids)->where('state', 1)->order('last_time', 'asc')->select();
if (!$channel_infos || !$aids) return []; if (!$channel_infos || !$aids) return [];
// 微信/支付宝收款处理 // 微信/支付宝收款处理
$channel_info = null;
foreach ($channel_infos as $key => $value) { foreach ($channel_infos as $key => $value) {
$check_wx = preg_match('/^wxpay\d+#/i', $value->channel); $check_wx = preg_match('/^wxpay\d+#/i', $value->channel);
$check_ali = preg_match('/^alipay\d+#/i', $value->channel); $check_ali = preg_match('/^alipay\d+#/i', $value->channel);
$channel_info = null;
if ($check_wx && $type === 'wxpay') { if ($check_wx && $type === 'wxpay') {
$channel_info = $channel_infos[$key]; $channel_info = $channel_infos[$key];
break; break;
@@ -140,7 +140,7 @@ class Order extends BaseModel
break; break;
} }
} }
if(!$channel_info) return []; if (!$channel_info) return [];
// 选取收款通道 // 选取收款通道
$patt = PayAccount::find($channel_info->account_id); $patt = PayAccount::find($channel_info->account_id);
$channel = ['aid' => $channel_info->account_id, 'cid' => $channel_info->id, 'patt' => $patt->getData('pattern')]; $channel = ['aid' => $channel_info->account_id, 'cid' => $channel_info->id, 'patt' => $patt->getData('pattern')];

View File

@@ -5,6 +5,8 @@ declare(strict_types=1);
namespace app\model; namespace app\model;
use app\BaseModel; use app\BaseModel;
use app\model\User;
use app\controller\api\PluginController;
class PayAccount extends BaseModel class PayAccount extends BaseModel
{ {
@@ -24,10 +26,44 @@ class PayAccount extends BaseModel
} }
return self::withCount(['payChannel' => 'channel'])->where($select); return self::withCount(['payChannel' => 'channel'])->where($select);
} }
// 获取账号配置
public static function getAccountConfig($aid, $pid = null): array|bool
{
$aid_info = self::find($aid);
// 插件配置
$platform = PluginController::getPluginInfo($aid_info->getData('platform'));
// 查询参数
$params = json_decode($aid_info->params, true);
$query = array_merge($platform['query'], $params);
if ($aid_info && $platform) {
$config = [
'pid' => $aid_info->pid,
// 账号id
'aid' => $aid_info->id,
// 收款平台
'platform' => $aid_info->getData('platform'),
// 插件类名
'payclass' => $platform['class_name'],
// 账号
'account' => $aid_info->account,
// 密码
'password' => $aid_info->password,
// 订单查询参数配置
'query' => $query,
];
if ($pid !== null) {
$pid_info = User::where('pid', $pid)->find();
$config['key'] = $pid_info->secret_key;
}
return $config;
} else {
return false;
}
}
// 获取器 // 获取器
public function getPlatformAttr($value) public function getPlatformAttr($value)
{ {
$payplugin_path = config_path() . '/extendconfig/payplugin.php'; $payplugin_path = config_path() . '/extend/payplugin.php';
if (!file_exists($payplugin_path)) { if (!file_exists($payplugin_path)) {
return []; return [];
} }

View File

@@ -1,2 +0,0 @@
*
!.gitignore

2
extend/.gitignore vendored
View File

@@ -1 +1 @@
/payclient payclient

View File

@@ -1,66 +0,0 @@
<?php
declare(strict_types=1);
class MpayClass
{
private $pid;
private $key;
private $host;
private $check_neworder_url;
private $submit_records_url;
function __construct($config)
{
$this->pid = $config['pid'];
$this->key = $config['key'];
$this->host = $config['host'];
$this->check_neworder_url = $this->host . '/order.php';
$this->submit_records_url = $this->host . '/payHeart';
}
// 查询新订单
public function orderHeart()
{
$url = $this->check_neworder_url . "?pid={$this->pid}&sign={$this->getSign()}";
$res = $this->getHttpResponse($url);
return $res;
}
// 提交收款明细
public function upRecords($records, $aid)
{
$header = ['Content-Type: application/json;charset=UTF-8'];
$url = $this->submit_records_url . "?pid={$this->pid}&aid={$aid}&sign={$this->getSign()}";
$res = $this->getHttpResponse($url, $header, json_encode($records));
return $res;
}
// 签名方法
private function getSign()
{
return md5($this->pid . $this->key);
}
// 请求外部资源
private 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;
}
}

View File

@@ -1,9 +0,0 @@
<?php
header('content-type: application/json; charset=utf-8');
$path = '../runtime/order.json';
if (!file_exists($path)) {
exit('{"code":3,"msg":"文件不存在"}');
} else {
exit(file_get_contents($path));
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,14 +0,0 @@
<?php
function encrypt($string, $key) {
$method = "AES-256-CBC";
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method));
$encrypted = openssl_encrypt($string, $method, $key, 0, $iv);
// 将iv和加密字符串拼接起来
return base64_encode($iv . $encrypted);
}
$key = "your-encryption-key"; // 这里应该是一个安全的密钥
$string = "Hello, World!";
$encryptedString = encrypt($string, $key);
echo $encryptedString; // 输出加密字符串

View File

@@ -751,6 +751,10 @@
<td>wxpay</td> <td>wxpay</td>
<td>微信支付</td> <td>微信支付</td>
</tr> </tr>
<tr>
<td>unionpay</td>
<td>云闪付</td>
</tr>
</tbody> </tbody>
</table> </table>
<h3 id="pay5"><a name="设备类型列表" class="reference-link"></a><span <h3 id="pay5"><a name="设备类型列表" class="reference-link"></a><span

View File

@@ -5,6 +5,19 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>订单明细</title> <title>订单明细</title>
<link rel="stylesheet" href="/component/pear/css/pear.css" /> <link rel="stylesheet" href="/component/pear/css/pear.css" />
<style>
.paytype {
display: flex;
align-items: center;
justify-content: center;
height: 34px;
}
.paytype>span {
margin-left: 3px;
line-height: normal;
}
</style>
</head> </head>
<body class="pear-container"> <body class="pear-container">
@@ -56,6 +69,7 @@
<option value="">请选择</option> <option value="">请选择</option>
<option value="wxpay">微信支付</option> <option value="wxpay">微信支付</option>
<option value="alipay">支付宝</option> <option value="alipay">支付宝</option>
<option value="unionpay">云闪付</option>
</select> </select>
</div> </div>
</div> </div>
@@ -207,7 +221,7 @@
{ title: '成交金额', field: 'really_price', align: 'center', minWidth: 85 }, { title: '成交金额', field: 'really_price', align: 'center', minWidth: 85 },
{ title: '支付状态', field: 'state', align: 'center', minWidth: 85, templet: '<div>{{# if(d.state==1){return`<span class="layui-badge layui-bg-green">成功</span>`}else{if(new Date(d.close_time)>new Date("<?php echo $servertime ?>")){return`<span class="layui-badge layui-bg-orange">等待</span>`}else{return`<span class="layui-badge layui-bg-gray">过期</span>`} } }}</div>' }, { title: '支付状态', field: 'state', align: 'center', minWidth: 85, templet: '<div>{{# if(d.state==1){return`<span class="layui-badge layui-bg-green">成功</span>`}else{if(new Date(d.close_time)>new Date("<?php echo $servertime ?>")){return`<span class="layui-badge layui-bg-orange">等待</span>`}else{return`<span class="layui-badge layui-bg-gray">过期</span>`} } }}</div>' },
{ title: '支付时间', field: 'pay_time', align: 'center', minWidth: 160, templet: '<div>{{= d.pay_time == d.create_time ? "- -" : d.pay_time}}</div>' }, { title: '支付时间', field: 'pay_time', align: 'center', minWidth: 160, templet: '<div>{{= d.pay_time == d.create_time ? "- -" : d.pay_time}}</div>' },
{ title: '支付平台', field: 'type', align: 'center', width: 120, templet: '<div>{{# if(d.type=="wxpay"){return`<img src="/static/img/wxpay.ico"width="15"><span>微信支付</span>`}if(d.type=="alipay"){return`<img src="/static/img/alipay.ico"width="15"><span>支付宝</span>`} }}</div>' }, { title: '支付平台', field: 'type', align: 'center', width: 120, templet: '<div>{{# if(d.type=="wxpay"){return`<div class="paytype"><img src="/static/img/wxpay.ico"width="15"><span>微信支付</span></div>`}if(d.type=="alipay"){return`<div class="paytype"><img src="/static/img/alipay.ico"width="15"><span>支付宝</span></div>`}if(d.type=="unionpay"){return`<div class="paytype"><img src="/static/img/unionpay.ico"width="15"><span>云闪付</span></div>`} }}</div>' },
{ title: '收款平台[账号:终端]', field: 'platform', align: 'center', minWidth: 160, templet: '<div>{{# return`${d.payAccount.platform} [${d.aid}:${d.cid}]` }}</div>' }, { title: '收款平台[账号:终端]', field: 'platform', align: 'center', minWidth: 160, templet: '<div>{{# return`${d.payAccount.platform} [${d.aid}:${d.cid}]` }}</div>' },
{ title: '操作', align: 'center', width: 120, fixed: 'right', templet: '<div><strong><a href="javascript:;" data-id="{{= d.id }}" class="layui-font-green {{= d.state==1 ? "orderSet-paid" : "orderSet-paying" }}">设置</a></strong></div>' } { title: '操作', align: 'center', width: 120, fixed: 'right', templet: '<div><strong><a href="javascript:;" data-id="{{= d.id }}" class="layui-font-green {{= d.state==1 ? "orderSet-paid" : "orderSet-paying" }}">设置</a></strong></div>' }
]] ]]

View File

@@ -23,6 +23,15 @@
margin-left: 20px; margin-left: 20px;
} }
.paytype {
display: flex;
align-items: center;
}
.paytype>strong {
margin-left: 3px;
}
.alipay { .alipay {
color: #1677ff; color: #1677ff;
} }
@@ -30,6 +39,10 @@
.wxpay { .wxpay {
color: #1AAD19; color: #1AAD19;
} }
.unionpay {
color: #d81e06;
}
</style> </style>
</head> </head>
@@ -54,8 +67,8 @@
<div class="layui-row"> <div class="layui-row">
<div class="layui-col-xs3"><label class="layui-form-label"><strong>收款方式</strong></label></div> <div class="layui-col-xs3"><label class="layui-form-label"><strong>收款方式</strong></label></div>
<div class="layui-col-xs9"> <div class="layui-col-xs9">
<div class="list"> <div class="list paytype">
<?php $payway=['alipay'=>'支付宝','wxpay'=>'微信支付'];$payway_img=['alipay'=>'/static/img/alipay.ico','wxpay'=>'/static/img/wxpay.ico'];echo "<img src='{$payway_img[$type]}'width='16'><strong class='{$type}'>{$payway[$type]}</strong>" ?> <?php $payway=['alipay'=>'支付宝','wxpay'=>'微信支付','unionpay'=>'云闪付'];$payway_img=['alipay'=>'/static/img/alipay.ico','wxpay'=>'/static/img/wxpay.ico','unionpay'=>'/static/img/unionpay.ico'];echo "<img src='{$payway_img[$type]}'width='16'><strong class='{$type}'>{$payway[$type]}</strong>" ?>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>订单明细</title> <title>支付测试</title>
<link rel="stylesheet" href="/component/pear/css/pear.css" /> <link rel="stylesheet" href="/component/pear/css/pear.css" />
<style> <style>
.paybtn { .paybtn {
@@ -60,6 +60,10 @@
<img src="/static/img/alipay.ico" width="16"> <img src="/static/img/alipay.ico" width="16">
<span>支付宝</span> <span>支付宝</span>
</button> </button>
<button class="pear-btn unionpay">
<img src="/static/img/unionpay.ico" width="16">
<span>云闪付</span>
</button>
</div> </div>
</div> </div>
</div> </div>
@@ -91,6 +95,9 @@
document.querySelector('.alipay').addEventListener('click', function () { document.querySelector('.alipay').addEventListener('click', function () {
crateOrder('alipay'); crateOrder('alipay');
}); });
document.querySelector('.unionpay').addEventListener('click', function () {
crateOrder('unionpay');
});
// 创建订单 // 创建订单
function crateOrder(paytype) { function crateOrder(paytype) {
form.submit('paytest', function (data) { form.submit('paytest', function (data) {

View File

@@ -166,6 +166,9 @@
} else if (payType === 'alipay') { } else if (payType === 'alipay') {
payTpeyImg.src = '/static/img/alipay.jpg'; payTpeyImg.src = '/static/img/alipay.jpg';
payTypeText.innerText = '请使用支付宝扫码支付' payTypeText.innerText = '请使用支付宝扫码支付'
} else if (payType === 'unionpay') {
payTpeyImg.src = '/static/img/unionpay.jpg';
payTypeText.innerText = '请使用云闪付扫码支付'
} }
// 生成二维码 // 生成二维码
if (codeType == 0) { if (codeType == 0) {

View File

@@ -28,14 +28,14 @@
<select class="type" lay-filter="select-type"> <select class="type" lay-filter="select-type">
<option value="">请选择</option> <option value="">请选择</option>
<!-- <?php if ($platform == 'wxpay') { ?> --> <!-- <?php if ($platform == 'wxpay') { ?> -->
<option value="wxpay1">个人码</option> <option value="wxpay1">个人码/经营码</option>
<option value="wxpay2">赞赏码</option> <option value="wxpay2">赞赏码</option>
<!-- <option value="wxpay3">经营码</option> <option value="wxpay3" disabled >经营码</option>
<option value="wxpay4">商家码</option> --> <option value="wxpay4">商家码</option>
<!-- <?php } ?> --> <!-- <?php } ?> -->
<!-- <?php if ($platform == 'alipay') { ?> --> <!-- <?php if ($platform == 'alipay') { ?> -->
<option value="alipay1">收钱码</option> <option value="alipay1">收钱码/经营码</option>
<!-- <option value="alipay2">经营码</option> --> <option value="alipay2" disabled>经营码</option>
<!-- <?php } ?> --> <!-- <?php } ?> -->
</select> </select>
</div> </div>

View File

@@ -181,9 +181,9 @@
<div class="layui-input-block"> <div class="layui-input-block">
<div class="layui-form-mid layui-elip" <div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;"> style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo '并且 是 APP包名 相等 com.tencent.mm<br />并且 是 通知标题 相等 微信支付<br />[空格]或者 是 通知标题 相等 微信收款助手' ?> <?php echo '并且 是 APP包名 相等 com.tencent.mm<br />并且 是 通知标题 相等 微信支付<br />[空格]或者 是 通知标题 相等 微信收款助手<br />[空格]或者 是 通知标题 相等 微信收款商业版' ?>
<a href="javascript:;" lay-on="copyinfo" <a href="javascript:;" lay-on="copyinfo"
data-info='<?php echo "并且 是 APP包名 相等 com.tencent.mm\n并且 是 通知标题 相等 微信支付\n[空格]或者 是 通知标题 相等 微信收款助手" ?>' data-info='<?php echo "并且 是 APP包名 相等 com.tencent.mm\n并且 是 通知标题 相等 微信支付\n[空格]或者 是 通知标题 相等 微信收款助手\n[空格]或者 是 通知标题 相等 微信收款商业版" ?>'
style="float: right;" title="复制"><span style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a> class="icon pear-icon pear-icon-survey"></span></a>
</div> </div>