This commit is contained in:
youda 2025-05-22 13:24:18 +08:00
parent 3b1d7d6566
commit 783a04dae6
11 changed files with 572 additions and 62 deletions

5
.env
View File

@ -1,4 +1,4 @@
APP_DEBUG = false
APP_DEBUG = true
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
@ -21,3 +21,6 @@ HOST = 127.0.0.1
PORT = 6379
PASSWORD =
DB = 3
[YOUDA]
YOUDA_ENV=test

View File

@ -15,6 +15,7 @@ use app\common\model\UserLoginLog;
use think\facade\Log;
use app\common\server\TencentCosUploader;
use app\common\model\ProfitMoney;
use app\common\helper\EnvHelper;
class Login extends Base
{
private $uploader;
@ -886,13 +887,15 @@ class Login extends Base
$redis = (new RedisHelper())->getRedis();
$redisKey = "VerificationCode:{$mobile}";
$redisCode = $redis->get($redisKey);
// if ($code != "9999") {
$is_test = EnvHelper::getIsTest();
if (!$is_test) {
if (empty($redisCode) || $redisCode != $code) {
$logMessages[] = '验证码错误: ' . $code . ',正确验证码: ' . $redisCode . '==>' . $mobile;
Log::error(end($logMessages));
return $this->renderError('验证码错误');
}
// }
}
// 验证通过后删除Redis中的验证码
$redis->del($redisKey);

View File

@ -949,6 +949,7 @@ class Mall extends Base
'user_id' => $user['id'],
'diamond_id' => $diamond_product['id'],
'product_id' => $product_id,
'product_name' => $diamond_product['name'],
'amount_paid' => $price,
'pay_method' => $pay_type == 1 || $pay_type == 3 ? DiamondOrder::PAY_METHOD_WECHAT : DiamondOrder::PAY_METHOD_ALIPAY,
'is_first_charge' => $diamond_order_count == 0 ? 1 : 0,

View File

@ -2880,14 +2880,14 @@ class Notify extends Base
if ($diamond_order_count == 0 && $diamondProduct['first_bonus_reward'] != '') {
$reward_res = RewardService::sendReward($user_id, $diamondProduct['first_bonus_reward'], '首充赠送');
foreach ($reward_res['data'] as $item) {
$reward_log .='首充赠送' . $item['msg'] . ',';
$reward_log .= '首充赠送' . $item['msg'] . ',';
}
// $reward_log = '首充赠送' . implode(',', $reward_res['data']);
}
}
//判断$reward_log结尾是否是,号,是的话,去除
if(substr($reward_log, -1) == ','){
if (substr($reward_log, -1) == ',') {
$reward_log = substr($reward_log, 0, -1);
}
// 更新订单状态为支付成功
@ -3086,4 +3086,5 @@ class Notify extends Base
}
}
}

View File

@ -4,8 +4,9 @@ namespace app\api\controller;
use app\common\model\Order as OrderModel;
use app\common\model\OrderList;
use app\common\model\OrderNotify;
use think\facade\Db;
use app\common\helper\EnvHelper;
/**
* 订单控制器
*/
@ -46,12 +47,12 @@ class Order extends Base
$order['addtime'] = date('Y-m-d H:i:s', $order['addtime']);
$order['pay_time'] = $order['pay_time'] ? date('Y-m-d H:i:s', $order['pay_time']) : '';
// 格式化价格数据
$order['goods_price'] = (float)$order['goods_price'];
$order['order_total'] = (float)$order['order_total'];
$order['order_zhe_total'] = (float)$order['order_zhe_total'];
$order['price'] = (float)$order['price'];
$order['use_money'] = (float)$order['use_money'];
$order['use_money2'] = (float)$order['use_money2'];
$order['goods_price'] = (float) $order['goods_price'];
$order['order_total'] = (float) $order['order_total'];
$order['order_zhe_total'] = (float) $order['order_zhe_total'];
$order['price'] = (float) $order['price'];
$order['use_money'] = (float) $order['use_money'];
$order['use_money2'] = (float) $order['use_money2'];
}
unset($order);
@ -59,8 +60,8 @@ class Order extends Base
$data = [
'list' => $orderList,
'total' => $total,
'page' => (int)$page,
'page_size' => (int)$pageSize,
'page' => (int) $page,
'page_size' => (int) $pageSize,
'total_pages' => ceil($total / $pageSize)
];
@ -103,12 +104,12 @@ class Order extends Base
$orderInfo['pay_time'] = $orderInfo['pay_time'] ? date('Y-m-d H:i:s', $orderInfo['pay_time']) : '';
// 格式化价格数据
$orderInfo['goods_price'] = (float)$orderInfo['goods_price'];
$orderInfo['order_total'] = (float)$orderInfo['order_total'];
$orderInfo['order_zhe_total'] = (float)$orderInfo['order_zhe_total'];
$orderInfo['price'] = (float)$orderInfo['price'];
$orderInfo['use_money'] = (float)$orderInfo['use_money'];
$orderInfo['use_money2'] = (float)$orderInfo['use_money2'];
$orderInfo['goods_price'] = (float) $orderInfo['goods_price'];
$orderInfo['order_total'] = (float) $orderInfo['order_total'];
$orderInfo['order_zhe_total'] = (float) $orderInfo['order_zhe_total'];
$orderInfo['price'] = (float) $orderInfo['price'];
$orderInfo['use_money'] = (float) $orderInfo['use_money'];
$orderInfo['use_money2'] = (float) $orderInfo['use_money2'];
// 获取订单商品列表
$orderGoods = Db::name('order_list')
@ -121,7 +122,7 @@ class Order extends Base
// 格式化订单商品数据
foreach ($orderGoods as &$goods) {
$goods['addtime'] = date('Y-m-d H:i:s', $goods['addtime']);
$goods['goodslist_price'] = (float)$goods['goodslist_price'];
$goods['goodslist_price'] = (float) $goods['goodslist_price'];
$goods['goodslist_imgurl'] = imageUrl($goods['goodslist_imgurl']);
}
unset($goods);
@ -131,4 +132,157 @@ class Order extends Base
return $this->renderSuccess('获取成功', $orderInfo);
}
/**
* 发送网页支付订单
*
* @return \think\Response
*/
public function sendWebPayOrder()
{
// sendCustomerServiceMessage
// 获取当前登录用户
$user = $this->getUser();
// 获取订单编号
$orderNum = $this->request->param('order_num', '');
if (empty($orderNum)) {
return $this->renderError('订单编号不能为空');
}
$platform = \app\common\server\platform\PlatformFactory::create();
$res = $platform->sendCustomerServiceMessage($user, $orderNum);
if ($res['status'] == 1) {
return $this->renderSuccess('发送成功');
} else {
return $this->renderError($res['msg']);
}
}
/**
* 获取订单状态
*
* @return \think\Response
*/
public function getOrderStatus()
{
// 获取当前登录用户
$user = $this->getUser();
// 获取订单编号
$orderNum = $this->request->param('order_num', '');
if (empty($orderNum)) {
return $this->renderError('订单编号不能为空');
}
$orderNotify = OrderNotify::where([
'order_no' => $orderNum,
])->find();
if (!$orderNotify) {
return $this->renderError('订单不存在');
}
if ($orderNotify['status'] == 1) {
return $this->renderSuccess('支付成功', $orderNotify['status']);
}
return $this->renderSuccess('支付未完成请10秒后重试', $orderNotify['status']);
}
/**
* 创建H5支付订单通知
*
* @return \think\Response
*/
public function createWebPayOrderNotify()
{
$orderNum = $this->request->param('order_num', '');
if (empty($orderNum)) {
return $this->renderError('订单编号不能为空');
}
$cache_key = "order:webpay:" . $orderNum;
$redis = (new \app\common\server\RedisHelper())->getRedis();
$redis_key_info = $redis->get($cache_key);
$orderNotify = OrderNotify::where([
'order_no' => $orderNum,
])->find();
if (!$orderNotify) {
if ($redis_key_info) {
$redis->del($cache_key);
}
return $this->renderError('订单不存在');
}
if ($orderNotify['status'] == 1) {
if ($redis_key_info) {
$redis->del($cache_key);
}
return $this->renderError('订单已支付');
}
if ($orderNotify['status'] == 2) {
if ($redis_key_info) {
$redis->del($cache_key);
}
return $this->renderError('订单已失效');
}
$res = [];
if ($redis_key_info) {
$res = json_decode($redis_key_info, true);
} else {
$platform = new \app\common\server\platform\H5Platform();
$res = $platform->createWebPayOrderNotify($orderNum);
if ($res['status'] == 1) {
$redis->set($cache_key, json_encode($res), 60 * 30);
}
}
if ($res['status'] == 1) {
return $this->renderSuccess('创建成功', $res['data']);
} else {
return $this->renderError($res['msg']);
}
}
public function getOrderUrlLink()
{
$order_num = $this->request->param('order_num', '');
if (!empty($orderNum)) {
return $this->renderError('订单编号不能为空');
}
$order_notify = OrderNotify::where('order_no', $order_num)->find();
$user_id = 0;
$extend = [];
if ($order_notify == null) {
return ['status' => 0, 'msg' => '未找到订单'];
}
if ($order_notify['status'] == 2) {
return ['status' => 0, 'msg' => '订单已失效'];
}
// $this->appid
$web_domain = EnvHelper::getWebDomain();
$returnUrl = '';
if ($order_notify) {
if ($order_notify['extend'] == '') {
return $this->renderError('订单号错误');
}
$extend = json_decode($order_notify['extend'], true);
$user_id = $extend['userId'];
$order_type = $extend['orderType'];
$returnUrl = $extend['returnUrl'];
// 1. 提取路径部分
$path = parse_url($returnUrl, PHP_URL_PATH);
$path = ltrim($path, '/');
// 2. 提取查询部分
$queryString = parse_url($returnUrl, PHP_URL_QUERY);
parse_str($queryString, $paramsArray);
$paramsArray['order_num'] = $order_num;
$query = http_build_query($paramsArray);
$platform = new \app\common\server\platform\MiniProgramPlatform();
$env_version = 'release';
if (EnvHelper::getIsTest()) {
$env_version = 'develop';
}
$res = $platform->getUrlLink($path, $query, $env_version);
if ($res['status'] == 1) {
return $this->renderSuccess('获取成功', $res['data']);
}
}
return $this->renderError('获取失败');
}
}

View File

@ -215,7 +215,10 @@ Route::any('getRankList', 'Index/getRankList');
#============================
Route::any('order_list', 'Order/getOrderList');
Route::any('order_detail', 'Order/getOrderDetail');
Route::any('send_web_pay_order', 'Order/sendWebPayOrder');
Route::any('get_order_status', 'Order/getOrderStatus');
Route::any('create_web_pay_order', 'Order/createWebPayOrderNotify');
Route::any('get_order_url_link', 'Order/getOrderUrlLink');
#============================
#FloatBall.php悬浮球
#============================

View File

@ -30,6 +30,28 @@ class ConfigHelper
private static $systemTest = null;
private static $youda_env = null;
/**
* 获取友达环境
*
* @return string 友达环境
*/
public static function getYoudaEnv()
{
if (self::$youda_env !== null) {
return self::$youda_env;
}
$youda_env = env('youda.youda_env', 'production ');
if ($youda_env) {
self::$youda_env = $youda_env;
}
return self::$youda_env;
}
public static function getIsTest(){
}
/**
* 获取应用设置
*

View File

@ -0,0 +1,58 @@
<?php
namespace app\common\helper;
use think\facade\Db;
use app\common\server\RedisHelper;
/**
* 环境帮助类
* 用于获取系统环境参数
*/
class EnvHelper
{
private static $youda_env = null;
/**
* 获取友达环境
*
* @return string 友达环境
*/
public static function getYoudaEnv()
{
if (self::$youda_env !== null) {
return self::$youda_env;
}
$youda_env = env('youda.youda_env', 'production ');
if ($youda_env) {
self::$youda_env = $youda_env;
}
return self::$youda_env;
}
/**
* 获取是否为测试环境
*
* @return bool 是否为测试环境
*/
public static function getIsTest()
{
return self::getYoudaEnv() == "test";
}
/**
* 获取友达web域名
*
* @return string 友达web域名
*/
public static function getWebDomain()
{
if (self::getIsTest()) {
return "https://testweb.zfunbox.cn";
}
return "https://zfunbox.cn";
}
}

View File

@ -139,5 +139,11 @@ abstract class BasePlatform
}
return $output;
}
/**
* 客服发送消息
* @param mixed $user_id
* @param mixed $order_num
* @return array{status: int, data: array, msg: string}
*/
abstract public function sendCustomerServiceMessage($user, $order_num): array;
}

View File

@ -3,9 +3,13 @@ namespace app\common\server\platform;
use Alipay\EasySDK\Kernel\Factory;
use Alipay\EasySDK\Kernel\Config;
use app\common\model\User;
use think\App;
use think\facade\Db;
use think\facade\Log;
use app\common\model\Order;
use app\common\model\OrderNotify;
use app\common\helper\EnvHelper;
/**
* 多端平台支付抽象基类
*/
@ -99,7 +103,8 @@ class H5Platform extends BasePlatform
'status' => 0,
'retry_count' => 0,
'create_time' => date('Y-m-d H:i:s'),
'update_time' => date('Y-m-d H:i:s')
'update_time' => date('Y-m-d H:i:s'),
'title' => $title,
]);
return [
'status' => 1,
@ -173,7 +178,17 @@ class H5Platform extends BasePlatform
return ['status' => 1, 'data' => ""];
}
/**
* 客服发送消息
* @param mixed $user_id
* @param mixed $order_num
* @return array{status: int, data: array, msg: string}
*/
public function sendCustomerServiceMessage($user, $order_num): array
{
$message = "用户ID{$user['id']},订单号:{$order_num}";
return ['status' => 1, 'data' => $message];
}
public function getOptions()
{
@ -202,4 +217,98 @@ class H5Platform extends BasePlatform
return $options;
}
/**
* 根据订单号创建订单
* @param string $order_num 订单号
* @return array{status: int, data: array, msg: string}
*/
public function createWebPayOrderNotify($order_num)
{
// echo "H5支付{$amount}分,订单号:{$orderId}\n";
// 实际项目中这里调用支付SDK
try {
$order_notify = OrderNotify::where('order_no', $order_num)->find();
$user_id = 0;
$extend = [];
$order_type = '';
if ($order_notify == null) {
return ['status' => 0, 'msg' => '未找到订单'];
}
if ($order_notify['status'] == 2) {
return ['status' => 0, 'msg' => '订单已失效'];
}
if ($order_notify['status'] == 1) {
return ['status' => 0, 'msg' => '订单已支付'];
}
// $this->appid
$web_domain = EnvHelper::getWebDomain();
$returnUrl = $web_domain . '/pages/other/web-pay-success';
$quitUrl = $web_domain . '/pages/other/web-pay-order';
if ($order_notify) {
$title = $order_notify['title'];
$price = $order_notify['pay_amount'];
if ($order_notify['extend'] == '') {
return ['status' => 0, 'msg' => '订单号错误'];
}
$extend = json_decode($order_notify['extend'], true);
$user_id = $extend['userId'];
$order_type = $extend['orderType'];
}
if ($price <= 0) {
return ['status' => 0, 'msg' => '金额错误'];
}
$user = User::where('id', $user_id)->find();
if ($user == null) {
//抛出异常
throw new \Exception('用户信息为空');
}
$title = mb_substr($title, 0, 30);
$order_no = $order_num;
$payment_type = 'zfbpay';
// 回调使用的随机数(与支付随机数分离)
$callback_nonce_str = $this->genRandomString();
// 生成新的支付通知URL
$notifyUrl = generatePayNotifyUrl($payment_type, $order_type, $user_id, $order_no, $callback_nonce_str);
$is_env_test = EnvHelper::getIsTest();
if ($is_env_test) {
$is_test = $user['istest'];
if ($is_test == 2) {
$price = 0.01;
}
}
//2. 发起API调用以支付能力下的统一收单交易创建接口为例
$result = Factory::payment()
->wap()
->asyncNotify($notifyUrl)
->pay(
$title, // 支付标题
$order_no, // 商户订单号(唯一)
$price, // 金额
$quitUrl,// 取消地址
$returnUrl// 支付后返回地址
);
//3. 处理响应或异常
if (!empty($result->body)) {
// 将通知URL和随机字符串保存到order_notify表中
if ($order_notify) {
$order_notify->notify_url = $notifyUrl;
$order_notify->nonce_str = $callback_nonce_str;
}
$order_notify->save();
return [
'status' => 1,
'data' => [
'order_no' => $order_no,
'res' => $result->body
]
];
} else {
return ['status' => 0, 'msg' => '支付失败:' . $result];
}
} catch (\Exception $e) {
}
return ['status' => 0, 'msg' => '支付失败:'];
}
}

View File

@ -1,9 +1,16 @@
<?php
namespace app\common\server\platform;
use app\common\model\OrderListSend;
use think\App;
use think\facade\Db;
use think\facade\Log;
use app\common\helper\WxPayHelper;
use think\facade\Request;
use app\common\model\User;
use app\common\model\Order;
use app\common\model\OrderNotify;
use app\common\model\DiamondOrder;
use app\common\helper\EnvHelper;
use Exception;
/**
@ -92,21 +99,52 @@ class MiniProgramPlatform extends BasePlatform
];
}
return [
'status' => 0,
'data' => [],
'msg' => '小程序支付通道维护中请联系客服下载app。'
];
if ($currentTime < 800 || $currentTime >= 2200) {
return [
'status' => 0,
'data' => [],
'msg' => '支付未开放请在08:00-22:00范围内购买'
];
}
// return [
// 'status' => 0,
// 'data' => [],
// 'msg' => '小程序支付通道维护中请联系客服下载app。'
// ];
// if ($currentTime < 800 || $currentTime >= 2200) {
// return [
// 'status' => 0,
// 'data' => [],
// 'msg' => '支付未开放请在08:00-22:00范围内购买'
// ];
// }
$title = mb_substr($title, 0, 30);
$prefix = $this->GetPrefix();
if (true) {
$domain = Request::domain();
// Request::param('return_url')
$host = parse_url($domain, PHP_URL_HOST);
$order_no = create_order_no_new($pre, "ZFA", 'MP', "ZFB");
$extend = [
'orderType' => $attach,
];
$extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE);
// 将通知URL和随机字符串保存到order_notify表中
Db::name('order_notify')->insert([
'order_no' => $order_no,
'notify_url' => '',
'nonce_str' => '',
'pay_time' => date('Y-m-d H:i:s'),
'pay_amount' => $price,
'status' => 0,
'retry_count' => 0,
'create_time' => date('Y-m-d H:i:s'),
'update_time' => date('Y-m-d H:i:s'),
'extend' => $extend_str,
'title' => $title,
]);
return [
'status' => 1,
'data' => [
'order_no' => $order_no,
'res' => ['data' => ['order_num' => $order_no], 'requestPay' => $domain . '/api/send_web_pay_order', 'tips' => '您即将进入客服聊天界面完成支付也可前往「我的」页面下载官方APP享受更便捷的购物及充值服务。']
]
];
}
//生成订单号订单号为ML_DRAYDMP02025018.... ML_ 前缀固定3位DRA 商户号固定3位YD 项目固定2位MP0 表示微信小程序支付
$order_no = create_order_no_new($pre, $prefix, $project_prefix, "MP0");
$openid = $user['openid'];
@ -155,7 +193,8 @@ class MiniProgramPlatform extends BasePlatform
'status' => 0,
'retry_count' => 0,
'create_time' => date('Y-m-d H:i:s'),
'update_time' => date('Y-m-d H:i:s')
'update_time' => date('Y-m-d H:i:s'),
'title' => $title,
]);
$time = time();
$res['appId'] = $this->wx_appid;
@ -252,6 +291,89 @@ class MiniProgramPlatform extends BasePlatform
return ['status' => 0, 'msg' => '支付失败:' . $error_message];
}
/**
* 客服发送消息
* @param mixed $user_id
* @param mixed $order_num
* @return array{status: int, data: array, msg: string}
*/
public function sendCustomerServiceMessage($user, $order_num): array
{
// 获取订单编号
$return_url = Request::param('return_url', '');
$message = "用户ID{$user['id']},订单号:{$order_num}";
$order_title = '';
$order_price = 0;
if ($user['openid'] == null) {
return ['status' => 0, 'msg' => '用户openid为空'];
}
$orderNotify = OrderNotify::where([
'order_no' => $order_num,
])->find();
$extend = [];
if ($orderNotify) {
if ($orderNotify['extend'] != '') {
$extend = json_decode($orderNotify['extend'], true);
}
$order_title = $orderNotify['title'];
$order_price = $orderNotify['pay_amount'];
}
if ($order_title == "") {
return ['status' => 0, 'msg' => '订单号错误'];
}
// $this->appid
$web_domain = EnvHelper::getWebDomain();
$extend['returnUrl'] = $return_url;
$extend['openId'] = $user['openid'];
$extend['userId'] = $user['id'];
$extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE);
$access_token = $this->get_access_token();
$request_url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" . $access_token;
$param = [
'touser' => $user['openid'],
'msgtype' => 'link',
'link' => [
'title' => $order_title,
'description' => "{$order_price}【点击去支付】",
'thumb_url' => 'https://image.zfunbox.cn/icon_80.png',
'url' => $web_domain . '/pages/other/web-pay-order?order_num=' . $order_num
]
];
$postData = json_encode($param, JSON_UNESCAPED_UNICODE);
$result = [];
for ($i = 0; $i < 5; $i++) {
$result = curlPost($request_url, $postData);
$result = json_decode($result, true);
if (isset($result['errcode']) && $result['errcode'] == 0) {
//发送成功,退出循环
$extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE);
OrderNotify::where('order_no', $order_num)->update(['extend' => $extend_str]);
return ['status' => 1, 'data' => $result];
}
// 记录响应结果日志
writelog('post_order_log', json_encode([
'method' => 'sendCustomerServiceMessage',
'order_num' => $order_num,
'response' => $result,
'time' => date('Y-m-d H:i:s')
]));
//延迟一秒
sleep(1);
// usleep(500000);
}
//发送成功,退出循环
$extend_str = json_encode($extend, JSON_UNESCAPED_UNICODE);
OrderNotify::where('order_no', $order_num)->update(['extend' => $extend_str]);
return ['status' => 1, 'msg' => $result['errmsg'] ?? '发送失败'];
}
/**
* 发货
* @param mixed $openid
@ -377,11 +499,39 @@ class MiniProgramPlatform extends BasePlatform
$result = curlPost($url, json_encode($param));
$result = json_decode($result, true);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return ['status' => 0, 'msg' => $result['errmsg'] ?? '生成链接失败'];
}
return ['status' => 1, 'data' => $result];
}
/**
* 生成URL链接
* @param string $path 路径
* @param string $query 查询参数
* @return array
*/
public function getUrlLink($path, $query, $env_version = "release"): array
{
// 获取access_token
$access_token = $this->get_access_token();
$url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=" . $access_token;
$param = [
'path' => $path,
'query' => $query,
'env_version' => $env_version
];
$result = curlPost($url, json_encode($param));
$result = json_decode($result, true);
if (isset($result['errcode']) && $result['errcode'] != 0) {
return ['status' => 0, 'msg' => $result['errmsg'] ?? '生成链接失败'];
}
return ['status' => 1, 'data' => $result['url_link']];
}
/**
* 获取手机号