Browse Source

修改 bug

develop
王泽彦 5 months ago
parent
commit
fdca37a8b5
  1. 1
      niucloud/app/api/route/pay.php
  2. 53
      niucloud/app/listener/pay/PayCreateListener.php
  3. 66
      niucloud/app/listener/pay/PaySuccessListener.php
  4. 57
      niucloud/app/service/api/apiService/CoachStudentService.php
  5. 15
      uniapp/api/apiRoute.js
  6. 206
      uniapp/components/order-list-card/index.vue
  7. 32
      uniapp/pages-market/clue/clue_info.vue

1
niucloud/app/api/route/pay.php

@ -45,5 +45,4 @@ Route::group('pay',function () {
Route::post('close', 'pay.Pay/close'); Route::post('close', 'pay.Pay/close');
})->middleware(ApiChannel::class) })->middleware(ApiChannel::class)
->middleware(ApiCheckToken::class, true)//表示验证登录
->middleware(ApiLog::class); ->middleware(ApiLog::class);

53
niucloud/app/listener/pay/PayCreateListener.php

@ -11,14 +11,67 @@
namespace app\listener\pay; namespace app\listener\pay;
use app\model\order_table\OrderTable;
/** /**
* 支付单据创建事件 * 支付单据创建事件
*/ */
class PayCreateListener class PayCreateListener
{ {
/**
* 处理支付创建事件
* @param array $params
* @return array|null
*/
public function handle(array $params) public function handle(array $params)
{ {
$trade_type = $params['trade_type'] ?? '';
$trade_id = $params['trade_id'] ?? 0;
// 根据不同的业务类型处理支付创建
switch ($trade_type) {
case 'school_order_table':
return $this->handleOrderPayment($trade_id);
// TODO: 添加其他业务类型的支付创建处理
// case 'recharge':
// return $this->handleRechargePayment($trade_id);
default:
return null;
}
}
/**
* 处理订单支付创建
* @param int $trade_id 订单ID
* @return array|null
*/
private function handleOrderPayment(int $trade_id)
{
// 查询订单信息
$order = OrderTable::where('id', $trade_id)->find();
if (!$order) {
return null;
}
// TODO: 根据订单信息构建支付数据
// 返回格式必须包含以下字段:
// - main_type: 支付主体类型(如 'member')
// - main_id: 支付主体ID(如会员ID)
// - money: 支付金额
// - trade_type: 业务类型
// - trade_id: 业务ID
// - body: 支付描述
return [
'main_type' => 'member', // TODO: 从订单获取会员类型
'main_id' => $order->student_id ?? 0, // TODO: 从订单获取会员ID
'money' => $order->order_amount ?? 0,
'trade_type' => 'school_order_table',
'trade_id' => $trade_id,
'body' => '订单支付 - ' . ($order->course_id_name ?? '课程')
];
} }
} }

66
niucloud/app/listener/pay/PaySuccessListener.php

@ -12,6 +12,9 @@
namespace app\listener\pay; namespace app\listener\pay;
use app\service\core\pay\CoreAccountService; use app\service\core\pay\CoreAccountService;
use app\model\order_table\OrderTable;
use app\service\api\apiService\OrderTableService;
use think\facade\Log;
/** /**
* 支付异步回调事件 * 支付异步回调事件
@ -23,6 +26,69 @@ class PaySuccessListener
if (isset($pay_info['out_trade_no']) && !empty($pay_info['out_trade_no'])) { if (isset($pay_info['out_trade_no']) && !empty($pay_info['out_trade_no'])) {
//账单记录添加 //账单记录添加
(new CoreAccountService())->addPayLog($pay_info); (new CoreAccountService())->addPayLog($pay_info);
// 处理业务逻辑
$this->handleBusinessLogic($pay_info);
}
}
/**
* 处理业务逻辑
* @param array $pay_info 支付信息
*/
private function handleBusinessLogic(array $pay_info)
{
$trade_type = $pay_info['trade_type'] ?? '';
$trade_id = $pay_info['trade_id'] ?? 0;
// 根据不同的业务类型处理支付成功逻辑
switch ($trade_type) {
case 'school_order_table':
$this->handleOrderPaymentSuccess($trade_id, $pay_info);
break;
// TODO: 添加其他业务类型的支付成功处理
// case 'recharge':
// $this->handleRechargeSuccess($trade_id, $pay_info);
// break;
default:
Log::info('PaySuccessListener: 未处理的业务类型 - ' . $trade_type);
break;
}
}
/**
* 处理订单支付成功
* @param int $trade_id 订单ID
* @param array $pay_info 支付信息
*/
private function handleOrderPaymentSuccess(int $trade_id, array $pay_info)
{
try {
// 更新订单状态为已支付
$order = OrderTable::where('id', $trade_id)->find();
if (!$order) {
Log::error('PaySuccessListener: 订单不存在 - ID:' . $trade_id);
return;
}
// TODO: 更新订单状态
// 确认订单表的字段名和状态值
$order->order_status = 'paid';
$order->payment_time = date('Y-m-d H:i:s');
$order->payment_id = $pay_info['out_trade_no'] ?? '';
$order->save();
// TODO: 调用订单服务处理支付成功后的业务逻辑
// 例如:分配课程、创建合同签署记录等
$orderArray = $order->toArray();
(new OrderTableService())->handlePaymentSuccess($orderArray);
Log::info('PaySuccessListener: 订单支付成功处理完成 - 订单ID:' . $trade_id);
} catch (\Exception $e) {
Log::error('PaySuccessListener: 订单支付成功处理异常 - ' . $e->getMessage());
} }
} }
} }

57
niucloud/app/service/api/apiService/CoachStudentService.php

@ -187,18 +187,32 @@ class CoachStudentService extends BaseApiService
} }
/** /**
* 获取教练负责的学员ID集合 * 获取教练负责的学员ID集合(带缓存)
* @param int $coachId 教练ID * @param int $coachId 教练ID
* @param array $data 查询条件 * @param array $data 查询条件
* @return array * @return array
*/ */
private function getCoachStudentIds($coachId, $data = []) private function getCoachStudentIds($coachId, $data = [])
{ {
// 1. 从 school_student_courses 表中查询 main_coach_id 或 education_id 是当前教练的学员 // 检查缓存
$cacheKey = "coach_student_ids:{$coachId}";
$cachedIds = cache($cacheKey);
if ($cachedIds !== null && is_array($cachedIds)) {
return $cachedIds;
}
// 1. 从 school_student_courses 表中查询相关学员
$courseStudentIds = Db::table('school_student_courses') $courseStudentIds = Db::table('school_student_courses')
->where(function($query) use ($coachId) { ->where(function($query) use ($coachId) {
$query->where('main_coach_id', $coachId) $query->where('main_coach_id', $coachId)
->whereOr('education_id', $coachId); ->whereOr('education_id', $coachId)
->whereOr(function($q) use ($coachId) {
// 查询 assistant_ids 字段中包含当前教练ID的记录
$q->whereNotNull('assistant_ids')
->where('assistant_ids', '<>', '')
->whereRaw("FIND_IN_SET(?, assistant_ids)", [$coachId]);
});
}) })
->column('student_id'); ->column('student_id');
@ -207,7 +221,13 @@ class CoachStudentService extends BaseApiService
->leftJoin('school_course_schedule cs', 'pcs.schedule_id = cs.id') ->leftJoin('school_course_schedule cs', 'pcs.schedule_id = cs.id')
->where(function($query) use ($coachId) { ->where(function($query) use ($coachId) {
$query->where('cs.education_id', $coachId) $query->where('cs.education_id', $coachId)
->whereOr('cs.coach_id', $coachId); ->whereOr('cs.coach_id', $coachId)
->whereOr(function($q) use ($coachId) {
// 查询 assistant_ids 字段中包含当前教练ID的记录
$q->whereNotNull('cs.assistant_ids')
->where('cs.assistant_ids', '<>', '')
->whereRaw("FIND_IN_SET(?, cs.assistant_ids)", [$coachId]);
});
}) })
->where('pcs.person_type', 'student') ->where('pcs.person_type', 'student')
->where('pcs.deleted_at', 0) ->where('pcs.deleted_at', 0)
@ -217,8 +237,12 @@ class CoachStudentService extends BaseApiService
// 3. 合并并去重学生ID // 3. 合并并去重学生ID
$allStudentIds = array_merge($courseStudentIds, $scheduleStudentIds); $allStudentIds = array_merge($courseStudentIds, $scheduleStudentIds);
$uniqueStudentIds = array_unique($allStudentIds); $uniqueStudentIds = array_unique($allStudentIds);
$result = array_values($uniqueStudentIds);
return array_values($uniqueStudentIds); // 4. 缓存结果(1小时 = 3600秒)
cache($cacheKey, $result, 3600);
return $result;
} }
/** /**
@ -410,4 +434,27 @@ class CoachStudentService extends BaseApiService
return 0; return 0;
} }
} }
/**
* 清除教练学员关系缓存
* @param int|array $coachId 教练ID或教练ID数组
* @return bool
*/
public static function clearCoachStudentCache($coachId)
{
try {
if (is_array($coachId)) {
// 批量清除缓存
foreach ($coachId as $id) {
cache("coach_student_ids:{$id}", null);
}
} else {
// 清除单个教练缓存
cache("coach_student_ids:{$coachId}", null);
}
return true;
} catch (\Exception $e) {
return false;
}
}
} }

15
uniapp/api/apiRoute.js

@ -106,10 +106,6 @@ export default {
}, },
//↓↓↓↓↓↓↓↓↓↓↓↓-----微信绑定相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ //↓↓↓↓↓↓↓↓↓↓↓↓-----微信绑定相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓
// 获取微信openid(支持小程序和公众号)
async getWechatOpenid(data = {}) {
return await http.post('/personnel/getWechatOpenid', data)
},
// 绑定微信openid到人员 // 绑定微信openid到人员
async bindWechatOpenid(data = {}) { async bindWechatOpenid(data = {}) {
return await http.post('/personnel/bindWechatOpenid', data) return await http.post('/personnel/bindWechatOpenid', data)
@ -528,6 +524,17 @@ export default {
async updateOrderPaymentVoucher(data = {}) { async updateOrderPaymentVoucher(data = {}) {
return await http.post('/updateOrderPaymentVoucher', data) return await http.post('/updateOrderPaymentVoucher', data)
}, },
// 微信在线支付 - 创建支付订单
async createWechatPayment(data = {}) {
return await http.post('/pay', data)
},
// 获取微信openid(使用code换取)
async getWechatOpenid(data = {}) {
return await http.post('/personnel/getWechatOpenid', data)
},
//↓↓↓↓↓↓↓↓↓↓↓↓-----课程预约相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓ //↓↓↓↓↓↓↓↓↓↓↓↓-----课程预约相关接口-----↓↓↓↓↓↓↓↓↓↓↓↓
// 获取可预约课程列表 // 获取可预约课程列表
async getAvailableCourses(data = {}) { async getAvailableCourses(data = {}) {

206
uniapp/components/order-list-card/index.vue

@ -553,13 +553,207 @@ export default {
}, },
/** /**
* 微信在线代付处理(本阶段只定义函数) * 微信在线代付处理
*/ */
processWechatOnlinePayment(order) { async processWechatOnlinePayment(order) {
// TODO: 线 try {
uni.showToast({ uni.showLoading({ title: '正在发起支付...' })
title: '微信在线代付功能开发中',
icon: 'none' // openid
const openid = await this.getWechatOpenid()
if (!openid) {
uni.hideLoading()
uni.showModal({
title: '提示',
content: '未获取到微信授权信息,请重新登录或授权',
showCancel: false,
success: () => {
//
// uni.navigateTo({ url: '/pages/student/login/login' })
}
})
return
}
console.log('发起微信支付 - 订单ID:', order._raw?.id || order.id)
console.log('发起微信支付 - OpenID:', openid.substring(0, 10) + '***')
//
const res = await apiRoute.createWechatPayment({
type: 'wechatpay',
trade_type: 'school_order_table',
trade_id: order._raw?.id || order.id,
openid: openid,
return_url: '',
quit_url: '',
buyer_id: '',
voucher: ''
})
uni.hideLoading()
if (res.code !== 1 || !res.data) {
console.error('创建支付订单失败:', res)
uni.showToast({ title: res.msg || '发起支付失败', icon: 'none' })
return
}
console.log('支付参数:', res.data)
//
await this.callWechatPay(res.data)
//
uni.showToast({ title: '支付成功', icon: 'success' })
await this.refresh()
this.$emit('payment-success', order)
} catch (error) {
uni.hideLoading()
console.error('微信支付异常:', error)
if (error.message?.includes('cancel') || error.message?.includes('取消')) {
uni.showToast({ title: '已取消支付', icon: 'none' })
} else {
uni.showToast({ title: error.message || '支付失败', icon: 'none' })
}
}
},
/**
* 获取微信openid
* @returns {Promise<string>} 微信openid
*/
async getWechatOpenid() {
try {
//
const userInfo = uni.getStorageSync('userInfo')
let openid = ''
// #ifdef MP-WEIXIN
openid = userInfo?.weapp_openid || userInfo?.openid || ''
if (openid) {
console.log('本地获取小程序openid成功')
return openid
}
console.log('本地无openid,使用 uni.login 获取...')
// uni.login code
const loginRes = await new Promise((resolve, reject) => {
uni.login({
success: (res) => resolve(res),
fail: (err) => reject(err)
})
})
if (!loginRes.code) {
console.error('uni.login 获取 code 失败')
return ''
}
console.log('uni.login 获取 code 成功:', loginRes.code.substring(0, 10) + '***')
// 使 code openid
const res = await apiRoute.getWechatOpenid({
code: loginRes.code,
type: 'miniprogram'
})
if (res.code === 1 && res.data?.openid) {
openid = res.data.openid
//
if (userInfo) {
userInfo.weapp_openid = openid
uni.setStorageSync('userInfo', userInfo)
}
console.log('接口获取小程序openid成功')
return openid
} else {
console.error('接口换取openid失败:', res.msg || '未知错误')
return ''
}
// #endif
// #ifdef H5
openid = userInfo?.wx_openid || userInfo?.openid || ''
if (openid) {
console.log('本地获取公众号openid成功')
return openid
}
console.log('本地无openid,从URL获取code...')
// URLcodecode
const urlParams = new URLSearchParams(window.location.search)
const code = urlParams.get('code')
if (code) {
console.log('从URL获取code成功,调用接口换取openid...')
const res = await apiRoute.getWechatOpenid({
code: code,
type: 'official'
})
if (res.code === 1 && res.data?.openid) {
openid = res.data.openid
//
if (userInfo) {
userInfo.wx_openid = openid
uni.setStorageSync('userInfo', userInfo)
}
console.log('接口获取公众号openid成功')
return openid
} else {
console.error('接口换取openid失败:', res.msg || '未知错误')
return ''
}
} else {
console.error('URL中未找到code参数,需要进行微信授权')
// TODO:
return ''
}
// #endif
console.error('无法获取openid,可能需要重新微信授权')
return ''
} catch (error) {
console.error('获取openid异常:', error)
return ''
}
},
/**
* 调用微信支付
*/
callWechatPay(payParams) {
return new Promise((resolve, reject) => {
// #ifdef MP-WEIXIN
wx.requestPayment({
timeStamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType || 'MD5',
paySign: payParams.paySign,
success: (res) => {
console.log('微信支付成功:', res)
resolve({ code: 1, msg: '支付成功' })
},
fail: (err) => {
console.error('微信支付失败:', err)
if (err.errMsg?.includes('cancel')) {
reject(new Error('用户取消支付'))
} else {
reject(new Error('微信支付失败'))
}
}
})
// #endif
// #ifndef MP-WEIXIN
reject(new Error('当前环境不支持微信支付'))
// #endif
}) })
}, },

32
uniapp/pages-market/clue/clue_info.vue

@ -132,7 +132,11 @@
/> />
<!-- 服务列表弹窗 --> <!-- 服务列表弹窗 -->
<ServiceListCard v-if="currentPopup === 'service_list'" :service-list="serviceList" /> <ServiceListCard
v-if="currentPopup === 'service_list'"
:student-id="currentStudent && currentStudent.id"
:service-list="serviceList"
/>
<!-- 底部操作按钮 --> <!-- 底部操作按钮 -->
<template #footer> <template #footer>
@ -552,7 +556,6 @@
break break
case 'service_list': case 'service_list':
await this.getServiceList(student.id) await this.getServiceList(student.id)
this.currentPopup = 'service_list'
break break
} }
}, },
@ -1178,6 +1181,31 @@
// , // ,
}, },
/**
* 获取服务列表 - 激活ServiceListCard组件
* @param {Number|String} studentId - 学生ID可选
*/
async getServiceList(studentId = null) {
// ServiceListCardstudentId
this.currentPopup = 'service_list'
// ID使ID
const targetStudentId = studentId || this.currentStudent?.id
if (!targetStudentId) {
console.warn('服务列表:缺少学生ID')
uni.showToast({
title: '请先选择学生',
icon: 'none'
})
return
}
// ServiceListCardstudentId prop
// API
console.log('打开服务列表弹窗,学生ID:', targetStudentId)
},
// //
async getGiftRecords() { async getGiftRecords() {
if (!this.clientInfo?.resource_id) return if (!this.clientInfo?.resource_id) return

Loading…
Cancel
Save