更新
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\order;
|
||||
|
||||
use app\common\model\Order;
|
||||
use think\response\Json;
|
||||
|
||||
/**
|
||||
* 支付宝支付回调控制器
|
||||
* Class AlipayNotifyController
|
||||
* @package app\adminapi\controller\order
|
||||
*/
|
||||
class AlipayNotifyController
|
||||
{
|
||||
/**
|
||||
* @notes 支付宝异步通知
|
||||
* @return string
|
||||
*/
|
||||
public function notify()
|
||||
{
|
||||
try {
|
||||
// 获取支付宝配置
|
||||
$alipayConfig = config('pay.alipay');
|
||||
|
||||
// 获取POST数据
|
||||
$data = request()->post();
|
||||
|
||||
// 验证签名
|
||||
if (!$this->verifyAlipaySign($data, $alipayConfig['alipay_public_key'])) {
|
||||
return 'fail';
|
||||
}
|
||||
|
||||
// 验证金额
|
||||
$order = Order::where('order_no', $data['out_trade_no'])->find();
|
||||
if (!$order) {
|
||||
return 'fail';
|
||||
}
|
||||
|
||||
if ((float)$data['total_amount'] != (float)$order->amount) {
|
||||
return 'fail';
|
||||
}
|
||||
|
||||
// 验证交易状态
|
||||
if ($data['trade_status'] == 'TRADE_SUCCESS' || $data['trade_status'] == 'TRADE_FINISHED') {
|
||||
// 更新订单状态
|
||||
if ($order->status == 1) { // 只有待支付的订单才能更新
|
||||
$order->status = 2; // 已支付
|
||||
$order->payment_method = 'alipay';
|
||||
$order->payment_time = date('Y-m-d H:i:s');
|
||||
$order->trade_no = $data['trade_no'];
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
|
||||
return 'success';
|
||||
} catch (\Exception $e) {
|
||||
return 'fail';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 验证支付宝签名
|
||||
* @param array $data
|
||||
* @param string $publicKey
|
||||
* @return bool
|
||||
*/
|
||||
private function verifyAlipaySign(array $data, string $publicKey): bool
|
||||
{
|
||||
try {
|
||||
// 获取签名
|
||||
$sign = $data['sign'] ?? '';
|
||||
unset($data['sign']);
|
||||
unset($data['sign_type']);
|
||||
|
||||
// 按键排序
|
||||
ksort($data);
|
||||
|
||||
// 构建签名字符串
|
||||
$signStr = '';
|
||||
foreach ($data as $key => $value) {
|
||||
if ($value !== '' && $value !== null) {
|
||||
$signStr .= $key . '=' . $value . '&';
|
||||
}
|
||||
}
|
||||
$signStr = rtrim($signStr, '&');
|
||||
|
||||
// 验证签名
|
||||
$publicKeyResource = openssl_pkey_get_public($publicKey);
|
||||
$result = openssl_verify($signStr, base64_decode($sign), $publicKeyResource, OPENSSL_ALGO_SHA256);
|
||||
openssl_free_key($publicKeyResource);
|
||||
|
||||
return $result === 1;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ class OrderController extends BaseAdminController
|
||||
public function detail()
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('detail');
|
||||
$detail = OrderLogic::detail($params['id']);
|
||||
$detail = OrderLogic::detail((int)$params['id']);
|
||||
|
||||
if (!$detail) {
|
||||
return $this->fail('订单不存在');
|
||||
@@ -66,7 +66,7 @@ class OrderController extends BaseAdminController
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('edit');
|
||||
|
||||
$result = OrderLogic::edit($params['id'], $params);
|
||||
$result = OrderLogic::edit((int)$params['id'], $params);
|
||||
if (!$result) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
@@ -82,7 +82,26 @@ class OrderController extends BaseAdminController
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('pay');
|
||||
|
||||
$result = OrderLogic::pay($params['id'], $params['payment_method']);
|
||||
// 判断是否是补单支付
|
||||
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
|
||||
// 补单支付:通过订单号查找订单
|
||||
if (empty($params['order_no'])) {
|
||||
return $this->fail('补单支付需要提供订单号');
|
||||
}
|
||||
$order = \app\common\model\Order::where('order_no', $params['order_no'])->find();
|
||||
if (!$order) {
|
||||
return $this->fail('订单不存在');
|
||||
}
|
||||
$orderId = $order->id;
|
||||
} else {
|
||||
// 正常支付:通过订单ID
|
||||
if (empty($params['id'])) {
|
||||
return $this->fail('订单ID不能为空');
|
||||
}
|
||||
$orderId = (int)$params['id'];
|
||||
}
|
||||
|
||||
$result = OrderLogic::pay($orderId, $params['payment_method']);
|
||||
if (!$result) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
@@ -98,7 +117,7 @@ class OrderController extends BaseAdminController
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('cancel');
|
||||
|
||||
$result = OrderLogic::cancel($params['id']);
|
||||
$result = OrderLogic::cancel((int)$params['id']);
|
||||
if (!$result) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
@@ -114,7 +133,7 @@ class OrderController extends BaseAdminController
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('refund');
|
||||
|
||||
$result = OrderLogic::refund($params['id']);
|
||||
$result = OrderLogic::refund((int)$params['id']);
|
||||
if (!$result) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
@@ -130,7 +149,7 @@ class OrderController extends BaseAdminController
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('delete');
|
||||
|
||||
$result = OrderLogic::delete($params['id']);
|
||||
$result = OrderLogic::delete((int)$params['id']);
|
||||
if (!$result) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
@@ -146,4 +165,92 @@ class OrderController extends BaseAdminController
|
||||
{
|
||||
return $this->dataLists(new OrderLists());
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 支付宝支付
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function alipay()
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('pay');
|
||||
|
||||
// 补单支付不需要校验订单是否存在
|
||||
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
|
||||
// 补单支付:直接返回支付URL,不校验订单
|
||||
$payUrl = OrderLogic::alipayPay(['order_no' => $params['order_no']]);
|
||||
if (!$payUrl) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
return $this->data(['pay_url' => $payUrl]);
|
||||
}
|
||||
|
||||
// 正常支付需要校验订单
|
||||
$order = $this->getOrderByParams($params);
|
||||
if (!$order) {
|
||||
return $this->fail('订单不存在');
|
||||
}
|
||||
|
||||
// 调用支付宝支付接口
|
||||
$payUrl = OrderLogic::alipayPay($order);
|
||||
if (!$payUrl) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
|
||||
return $this->data(['pay_url' => $payUrl]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 微信支付
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function wechat()
|
||||
{
|
||||
$params = (new OrderValidate())->post()->goCheck('pay');
|
||||
|
||||
// 补单支付不需要校验订单是否存在
|
||||
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
|
||||
// 补单支付:直接返回支付数据,不校验订单
|
||||
$payData = OrderLogic::wechatPay(['order_no' => $params['order_no']]);
|
||||
if (!$payData) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
return $this->data($payData);
|
||||
}
|
||||
|
||||
// 正常支付需要校验订单
|
||||
$order = $this->getOrderByParams($params);
|
||||
if (!$order) {
|
||||
return $this->fail('订单不存在');
|
||||
}
|
||||
|
||||
// 调用微信支付接口
|
||||
$payData = OrderLogic::wechatPay($order);
|
||||
if (!$payData) {
|
||||
return $this->fail(OrderLogic::getError());
|
||||
}
|
||||
|
||||
return $this->data($payData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 根据参数获取订单
|
||||
* @param array $params
|
||||
* @return mixed
|
||||
*/
|
||||
private function getOrderByParams(array $params)
|
||||
{
|
||||
if (!empty($params['is_supplement']) && $params['is_supplement'] == 1) {
|
||||
// 补单支付:通过订单号查找
|
||||
if (empty($params['order_no'])) {
|
||||
return null;
|
||||
}
|
||||
return \app\common\model\Order::where('order_no', $params['order_no'])->find();
|
||||
} else {
|
||||
// 正常支付:通过订单ID
|
||||
if (empty($params['id'])) {
|
||||
return null;
|
||||
}
|
||||
return \app\common\model\Order::find((int)$params['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\adminapi\controller\order;
|
||||
|
||||
use app\common\model\Order;
|
||||
use think\response\Xml;
|
||||
|
||||
/**
|
||||
* 微信支付回调控制器
|
||||
* Class WechatNotifyController
|
||||
* @package app\adminapi\controller\order
|
||||
*/
|
||||
class WechatNotifyController
|
||||
{
|
||||
/**
|
||||
* @notes 微信异步通知
|
||||
* @return Xml
|
||||
*/
|
||||
public function notify()
|
||||
{
|
||||
try {
|
||||
// 获取微信配置
|
||||
$wechatConfig = config('pay.wechat');
|
||||
|
||||
// 获取XML数据
|
||||
$xmlData = file_get_contents('php://input');
|
||||
$data = $this->xmlToArray($xmlData);
|
||||
|
||||
// 验证签名
|
||||
if (!$this->verifyWechatSign($data, $wechatConfig['api_key'])) {
|
||||
return $this->xmlResponse('FAIL', '签名验证失败');
|
||||
}
|
||||
|
||||
// 验证金额
|
||||
$order = Order::where('order_no', $data['out_trade_no'])->find();
|
||||
if (!$order) {
|
||||
return $this->xmlResponse('FAIL', '订单不存在');
|
||||
}
|
||||
|
||||
if ((int)$data['total_fee'] != (int)($order->amount * 100)) {
|
||||
return $this->xmlResponse('FAIL', '金额不匹配');
|
||||
}
|
||||
|
||||
// 验证交易状态
|
||||
if ($data['result_code'] == 'SUCCESS') {
|
||||
// 更新订单状态
|
||||
if ($order->status == 1) { // 只有待支付的订单才能更新
|
||||
$order->status = 2; // 已支付
|
||||
$order->payment_method = 'wechat';
|
||||
$order->payment_time = date('Y-m-d H:i:s');
|
||||
$order->trade_no = $data['transaction_id'];
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->xmlResponse('SUCCESS', '支付成功');
|
||||
} catch (\Exception $e) {
|
||||
return $this->xmlResponse('FAIL', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 验证微信签名
|
||||
* @param array $data
|
||||
* @param string $apiKey
|
||||
* @return bool
|
||||
*/
|
||||
private function verifyWechatSign(array $data, string $apiKey): bool
|
||||
{
|
||||
try {
|
||||
// 获取签名
|
||||
$sign = $data['sign'] ?? '';
|
||||
unset($data['sign']);
|
||||
|
||||
// 按键排序
|
||||
ksort($data);
|
||||
|
||||
// 构建签名字符串
|
||||
$signStr = '';
|
||||
foreach ($data as $key => $value) {
|
||||
if ($value !== '' && $value !== null) {
|
||||
$signStr .= $key . '=' . $value . '&';
|
||||
}
|
||||
}
|
||||
$signStr .= 'key=' . $apiKey;
|
||||
|
||||
// MD5签名
|
||||
$computedSign = strtoupper(md5($signStr));
|
||||
|
||||
return $computedSign === $sign;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes XML转数组
|
||||
* @param string $xml
|
||||
* @return array
|
||||
*/
|
||||
private function xmlToArray(string $xml): array
|
||||
{
|
||||
try {
|
||||
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
||||
return is_array($data) ? $data : [];
|
||||
} catch (\Exception $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 返回XML响应
|
||||
* @param string $returnCode
|
||||
* @param string $returnMsg
|
||||
* @return Xml
|
||||
*/
|
||||
private function xmlResponse(string $returnCode, string $returnMsg): Xml
|
||||
{
|
||||
$xml = '<xml>';
|
||||
$xml .= '<return_code><![CDATA[' . $returnCode . ']]></return_code>';
|
||||
$xml .= '<return_msg><![CDATA[' . $returnMsg . ']]></return_msg>';
|
||||
$xml .= '</xml>';
|
||||
|
||||
return response($xml, 200, ['Content-Type' => 'application/xml']);
|
||||
}
|
||||
}
|
||||
@@ -233,7 +233,24 @@ class DiagnosisController extends BaseAdminController
|
||||
$result = DiagnosisLogic::getCallRecords($params);
|
||||
return $this->data($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取患者通话签名(用于测试)
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function getDoctorSignature()
|
||||
{
|
||||
$params = $this->request->get();
|
||||
|
||||
if (empty($params['patient_id'])) {
|
||||
return $this->fail('医助理ID不能为空');
|
||||
}
|
||||
|
||||
$result = DiagnosisLogic::getDoctorSignature((int)$params['patient_id']);
|
||||
if ($result) {
|
||||
return $this->data($result);
|
||||
}
|
||||
return $this->fail(DiagnosisLogic::getError());
|
||||
}
|
||||
/**
|
||||
* @notes 获取患者通话签名(用于测试)
|
||||
* @return \think\response\Json
|
||||
@@ -300,14 +317,14 @@ class DiagnosisController extends BaseAdminController
|
||||
|
||||
$offset = ($page_no - 1) * $page_size;
|
||||
|
||||
$lists = \app\common\model\tcm\Diagnosis::where('patient_name|patient_phone|patient_id_card', 'like', '%' . $keyword . '%')
|
||||
->field(['id', 'patient_name', 'patient_phone', 'patient_id_card', 'gender', 'age'])
|
||||
$lists = \app\common\model\tcm\Diagnosis::where('patient_name|phone|id_card', 'like', '%' . $keyword . '%')
|
||||
->field(['id', 'patient_name', 'phone', 'id_card', 'gender', 'age'])
|
||||
->limit($offset, $page_size)
|
||||
->order('id desc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
$count = \app\common\model\tcm\Diagnosis::where('patient_name|patient_phone|patient_id_card', 'like', '%' . $keyword . '%')
|
||||
$count = \app\common\model\tcm\Diagnosis::where('patient_name|phone|id_card', 'like', '%' . $keyword . '%')
|
||||
->count();
|
||||
|
||||
return $this->success('', [
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace app\adminapi\lists\order;
|
||||
use app\adminapi\lists\BaseAdminDataLists;
|
||||
use app\common\lists\ListsSearchInterface;
|
||||
use app\common\model\Order;
|
||||
use app\common\model\auth\AdminRole;
|
||||
|
||||
/**
|
||||
* 订单列表
|
||||
@@ -27,6 +28,33 @@ class OrderLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 权限过滤 - 普通员工只能看自己创建的订单
|
||||
* @param array $where
|
||||
* @return void
|
||||
*/
|
||||
private function filterByPermission(array &$where): void
|
||||
{
|
||||
// 检查是否是超管(root字段为1)
|
||||
if (!empty($this->adminInfo['root']) && $this->adminInfo['root'] == 1) {
|
||||
// 超管不过滤,可以看所有订单
|
||||
return;
|
||||
}
|
||||
|
||||
// 主管角色ID列表(可根据实际调整)
|
||||
$supervisorRoles = [0, 3];
|
||||
|
||||
// 检查当前用户是否是主管
|
||||
$roleIds = \app\common\model\auth\AdminRole::where('admin_id', $this->adminId)->column('role_id');
|
||||
|
||||
// 如果不是主管,只能看自己创建的订单
|
||||
$isSupervisor = count(array_intersect($roleIds, $supervisorRoles)) > 0;
|
||||
|
||||
if (!$isSupervisor) {
|
||||
$where[] = ['creator_id', '=', $this->adminId];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取列表
|
||||
* @return array
|
||||
@@ -38,11 +66,14 @@ class OrderLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||
{
|
||||
$where = $this->searchWhere;
|
||||
|
||||
// 处理患者关键词搜索
|
||||
// 权限控制:普通员工只能看自己创建的订单
|
||||
$this->filterByPermission($where);
|
||||
|
||||
// 处理患者关键词搜索(从诊单表搜索)
|
||||
if (!empty($this->params['patient_keyword'])) {
|
||||
$where[] = ['patient_id', 'in', function ($query) {
|
||||
$query->table('user')
|
||||
->where('nickname|mobile', 'like', '%' . $this->params['patient_keyword'] . '%')
|
||||
$query->table('zyt_tcm_diagnosis')
|
||||
->where('patient_name|patient_phone', 'like', '%' . $this->params['patient_keyword'] . '%')
|
||||
->field('id');
|
||||
}];
|
||||
}
|
||||
@@ -57,7 +88,7 @@ class OrderLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||
}
|
||||
|
||||
return Order::where($where)
|
||||
->with(['patient', 'creator', 'details'])
|
||||
->with(['patient', 'creator'])
|
||||
->order(['create_time' => 'desc'])
|
||||
->limit($this->limitOffset, $this->pageSize)
|
||||
->select()
|
||||
@@ -72,11 +103,14 @@ class OrderLists extends BaseAdminDataLists implements ListsSearchInterface
|
||||
{
|
||||
$where = $this->searchWhere;
|
||||
|
||||
// 处理患者关键词搜索
|
||||
// 权限控制:普通员工只能看自己创建的订单
|
||||
$this->filterByPermission($where);
|
||||
|
||||
// 处理患者关键词搜索(从诊单表搜索)
|
||||
if (!empty($this->params['patient_keyword'])) {
|
||||
$where[] = ['patient_id', 'in', function ($query) {
|
||||
$query->table('user')
|
||||
->where('nickname|mobile', 'like', '%' . $this->params['patient_keyword'] . '%')
|
||||
$query->table('zyt_tcm_diagnosis')
|
||||
->where('patient_name|patient_phone', 'like', '%' . $this->params['patient_keyword'] . '%')
|
||||
->field('id');
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ class OrderLogic
|
||||
public static function create(array $params)
|
||||
{
|
||||
try {
|
||||
Db::startTrans();
|
||||
|
||||
$order = new Order();
|
||||
$order->order_no = self::generateOrderNo();
|
||||
$order->patient_id = $params['patient_id'];
|
||||
@@ -44,24 +42,8 @@ class OrderLogic
|
||||
$order->remark = $params['remark'] ?? '';
|
||||
$order->save();
|
||||
|
||||
// 创建订单详情
|
||||
if (!empty($params['details'])) {
|
||||
foreach ($params['details'] as $detail) {
|
||||
$orderDetail = new OrderDetail();
|
||||
$orderDetail->order_id = $order->id;
|
||||
$orderDetail->related_type = $detail['related_type'];
|
||||
$orderDetail->related_id = $detail['related_id'];
|
||||
$orderDetail->quantity = $detail['quantity'] ?? 1;
|
||||
$orderDetail->unit_price = $detail['unit_price'];
|
||||
$orderDetail->total_price = $detail['total_price'];
|
||||
$orderDetail->save();
|
||||
}
|
||||
}
|
||||
|
||||
Db::commit();
|
||||
return $order;
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
self::setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
@@ -198,9 +180,6 @@ class OrderLogic
|
||||
return false;
|
||||
}
|
||||
|
||||
// 删除订单详情
|
||||
OrderDetail::where('order_id', $id)->delete();
|
||||
|
||||
// 删除订单
|
||||
$order->delete();
|
||||
|
||||
@@ -218,7 +197,7 @@ class OrderLogic
|
||||
*/
|
||||
public static function detail(int $id): ?array
|
||||
{
|
||||
$order = Order::with(['patient', 'creator', 'details'])
|
||||
$order = Order::with(['patient', 'creator'])
|
||||
->find($id);
|
||||
|
||||
if (!$order) {
|
||||
@@ -239,4 +218,213 @@ class OrderLogic
|
||||
{
|
||||
return self::$error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 生成支付宝签名
|
||||
* @param array $params
|
||||
* @param string $privateKey
|
||||
* @return string
|
||||
*/
|
||||
private static function generateAlipaySign(array $params, string $privateKey): string
|
||||
{
|
||||
// 移除sign字段
|
||||
unset($params['sign']);
|
||||
|
||||
// 按键排序
|
||||
ksort($params);
|
||||
|
||||
// 构建签名字符串
|
||||
$signStr = '';
|
||||
foreach ($params as $key => $value) {
|
||||
if ($value !== '' && $value !== null) {
|
||||
$signStr .= $key . '=' . $value . '&';
|
||||
}
|
||||
}
|
||||
$signStr = rtrim($signStr, '&');
|
||||
|
||||
// 使用私钥签名
|
||||
$privateKeyResource = openssl_pkey_get_private($privateKey);
|
||||
openssl_sign($signStr, $sign, $privateKeyResource, OPENSSL_ALGO_SHA256);
|
||||
openssl_free_key($privateKeyResource);
|
||||
|
||||
return base64_encode($sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 生成微信签名
|
||||
* @param array $params
|
||||
* @param string $apiKey
|
||||
* @return string
|
||||
*/
|
||||
private static function generateWechatSign(array $params, string $apiKey): string
|
||||
{
|
||||
// 移除sign字段
|
||||
unset($params['sign']);
|
||||
|
||||
// 按键排序
|
||||
ksort($params);
|
||||
|
||||
// 构建签名字符串
|
||||
$signStr = '';
|
||||
foreach ($params as $key => $value) {
|
||||
if ($value !== '' && $value !== null) {
|
||||
$signStr .= $key . '=' . $value . '&';
|
||||
}
|
||||
}
|
||||
$signStr .= 'key=' . $apiKey;
|
||||
|
||||
// MD5签名
|
||||
return strtoupper(md5($signStr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 生成随机字符串
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
private static function generateNonceStr(int $length = 32): string
|
||||
{
|
||||
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$str = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$str .= $chars[mt_rand(0, strlen($chars) - 1)];
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 支付宝支付
|
||||
* @param $order
|
||||
* @return string|false
|
||||
*/
|
||||
public static function alipayPay($order)
|
||||
{
|
||||
try {
|
||||
// 这里调用支付宝SDK生成支付链接
|
||||
// 示例:生成支付宝支付URL
|
||||
$payUrl = self::generateAlipayUrl($order);
|
||||
return $payUrl;
|
||||
} catch (\Exception $e) {
|
||||
self::setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 微信支付
|
||||
* @param $order
|
||||
* @return array|false
|
||||
*/
|
||||
public static function wechatPay($order)
|
||||
{
|
||||
try {
|
||||
// 这里调用微信SDK生成支付二维码或链接
|
||||
// 示例:生成微信支付数据
|
||||
$payData = self::generateWechatPayData($order);
|
||||
return $payData;
|
||||
} catch (\Exception $e) {
|
||||
self::setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 生成支付宝支付URL
|
||||
* @param $order
|
||||
* @return string
|
||||
*/
|
||||
private static function generateAlipayUrl($order): string
|
||||
{
|
||||
try {
|
||||
// 获取订单号
|
||||
$orderNo = is_array($order) ? $order['order_no'] : $order->order_no;
|
||||
$amount = is_array($order) ? ($order['amount'] ?? 0) : $order->amount;
|
||||
|
||||
// 获取支付宝配置
|
||||
$alipayConfig = config('pay.alipay');
|
||||
|
||||
if (empty($alipayConfig['app_id']) || empty($alipayConfig['merchant_private_key'])) {
|
||||
throw new \Exception('支付宝配置不完整');
|
||||
}
|
||||
|
||||
// 使用支付宝SDK生成支付URL
|
||||
$params = [
|
||||
'app_id' => $alipayConfig['app_id'],
|
||||
'method' => 'alipay.trade.page.pay',
|
||||
'charset' => 'UTF-8',
|
||||
'sign_type' => 'RSA2',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'version' => '1.0',
|
||||
'notify_url' => $alipayConfig['notify_url'] ?: config('app.url') . '/api/order/alipay-notify',
|
||||
'return_url' => $alipayConfig['return_url'] ?: config('app.url') . '/order',
|
||||
'biz_content' => json_encode([
|
||||
'out_trade_no' => $orderNo,
|
||||
'product_code' => 'FAST_INSTANT_TRADE_PAY',
|
||||
'total_amount' => $amount,
|
||||
'subject' => '订单支付',
|
||||
'body' => '订单号:' . $orderNo,
|
||||
], JSON_UNESCAPED_UNICODE),
|
||||
];
|
||||
|
||||
// 生成签名
|
||||
$sign = self::generateAlipaySign($params, $alipayConfig['merchant_private_key']);
|
||||
$params['sign'] = $sign;
|
||||
|
||||
// 生成支付URL
|
||||
$payUrl = $alipayConfig['gateway_url'] . '?' . http_build_query($params);
|
||||
|
||||
return $payUrl;
|
||||
} catch (\Exception $e) {
|
||||
self::setError($e->getMessage());
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 生成微信支付数据
|
||||
* @param $order
|
||||
* @return array
|
||||
*/
|
||||
private static function generateWechatPayData($order): array
|
||||
{
|
||||
try {
|
||||
// 获取订单号
|
||||
$orderNo = is_array($order) ? $order['order_no'] : $order->order_no;
|
||||
$amount = is_array($order) ? ($order['amount'] ?? 0) : $order->amount;
|
||||
|
||||
// 获取微信配置
|
||||
$wechatConfig = config('pay.wechat');
|
||||
|
||||
if (empty($wechatConfig['app_id']) || empty($wechatConfig['mch_id']) || empty($wechatConfig['api_key'])) {
|
||||
throw new \Exception('微信支付配置不完整');
|
||||
}
|
||||
|
||||
// 生成微信支付数据
|
||||
$payData = [
|
||||
'appid' => $wechatConfig['app_id'],
|
||||
'mch_id' => $wechatConfig['mch_id'],
|
||||
'nonce_str' => self::generateNonceStr(),
|
||||
'body' => '订单支付',
|
||||
'out_trade_no' => $orderNo,
|
||||
'total_fee' => (int)($amount * 100), // 转换为分
|
||||
'spbill_create_ip' => request()->ip() ?: '127.0.0.1',
|
||||
'notify_url' => $wechatConfig['notify_url'] ?: config('app.url') . '/api/order/wechat-notify',
|
||||
'trade_type' => 'NATIVE', // 二维码支付
|
||||
];
|
||||
|
||||
// 生成签名
|
||||
$sign = self::generateWechatSign($payData, $wechatConfig['api_key']);
|
||||
$payData['sign'] = $sign;
|
||||
|
||||
// 返回支付数据
|
||||
return [
|
||||
'pay_url' => $wechatConfig['gateway_url'] . '/pay/unifiedorder',
|
||||
'pay_data' => $payData,
|
||||
'order_no' => $orderNo,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
self::setError($e->getMessage());
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,6 +703,55 @@ class DiagnosisLogic extends BaseLogic
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @notes 获取医助签名(供小程序调用)
|
||||
* @param int $patientId
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function getDoctorSignature(int $patientId)
|
||||
{
|
||||
|
||||
try {
|
||||
// 获取配置
|
||||
$config = self::getTrtcConfig();
|
||||
|
||||
if (!$config) {
|
||||
self::setError('请先配置腾讯云TRTC参数');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 患者userId
|
||||
$patientUserId = 'doctor_' . $patientId;
|
||||
|
||||
// 生成患者的 UserSig
|
||||
$userSig = self::generateUserSig(
|
||||
$config['sdkAppId'],
|
||||
$config['secretKey'],
|
||||
$patientUserId
|
||||
);
|
||||
|
||||
if (!$userSig) {
|
||||
self::setError('生成签名失败');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 确保患者账号已导入IM
|
||||
self::ensurePatientImAccount($patientId, $patientUserId);
|
||||
|
||||
\think\facade\Log::info('小程序获取患者签名成功 - doctor_id: ' . $patientId . ', user_id: ' . $patientUserId);
|
||||
|
||||
return [
|
||||
'sdkAppId' => (int)$config['sdkAppId'],
|
||||
'userId' => $patientUserId,
|
||||
'userSig' => $userSig,
|
||||
'expireTime' => 86400
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
\think\facade\Log::error('获取患者签名失败 - patient_id: ' . $patientId . ', error: ' . $e->getMessage());
|
||||
self::setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取患者签名(供小程序调用)
|
||||
|
||||
@@ -16,17 +16,17 @@ class OrderValidate extends BaseValidate
|
||||
protected $rule = [
|
||||
'id' => 'require|integer',
|
||||
'patient_id' => 'require|integer',
|
||||
'creator_id' => 'require|integer',
|
||||
'order_type' => 'require|in:1,2,3',
|
||||
'amount' => 'require|float',
|
||||
'status' => 'require|in:1,2,3,4',
|
||||
'payment_method' => 'in:alipay,wechat,bank',
|
||||
'payment_method' => 'in:alipay,wechat',
|
||||
'remark' => 'string|max:500',
|
||||
'order_no' => 'string|max:50',
|
||||
'is_supplement' => 'in:0,1',
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
'patient_id.require' => '患者ID必填',
|
||||
'creator_id.require' => '创建人ID必填',
|
||||
'order_type.require' => '订单类型必填',
|
||||
'order_type.in' => '订单类型不正确',
|
||||
'amount.require' => '订单金额必填',
|
||||
@@ -36,10 +36,10 @@ class OrderValidate extends BaseValidate
|
||||
];
|
||||
|
||||
protected $scene = [
|
||||
'create' => ['patient_id', 'creator_id', 'order_type', 'amount'],
|
||||
'create' => ['patient_id', 'order_type', 'amount'],
|
||||
'edit' => ['id', 'remark'],
|
||||
'detail' => ['id'],
|
||||
'pay' => ['id', 'payment_method'],
|
||||
'pay' => ['payment_method'],
|
||||
'cancel' => ['id'],
|
||||
'refund' => ['id'],
|
||||
'delete' => ['id'],
|
||||
|
||||
Reference in New Issue
Block a user