|
|
@@ -2,7 +2,7 @@ import { View, Text } from '@tarojs/components'
|
|
|
import Taro from '@tarojs/taro'
|
|
|
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
|
import { InferResponseType } from 'hono'
|
|
|
-import { orderClient } from '@/api'
|
|
|
+import { orderClient, paymentClient } from '@/api'
|
|
|
import { useState } from 'react'
|
|
|
import CancelReasonDialog from '@/components/common/CancelReasonDialog'
|
|
|
|
|
|
@@ -96,7 +96,7 @@ export default function OrderButtonBar({ order, onViewDetail, onCancelOrder, hid
|
|
|
setShowCancelDialog(false)
|
|
|
// 调用取消订单API
|
|
|
cancelOrderMutation.mutate({
|
|
|
- orderId: order.id,
|
|
|
+ orderId: order.id!,
|
|
|
reason
|
|
|
})
|
|
|
}
|
|
|
@@ -143,22 +143,391 @@ export default function OrderButtonBar({ order, onViewDetail, onCancelOrder, hid
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+ // 确认收货mutation
|
|
|
+ const confirmReceiptMutation = useMutation({
|
|
|
+ mutationFn: async ({ orderId }: { orderId: number }) => {
|
|
|
+ const response = await orderClient['confirm-receipt'].$post({
|
|
|
+ json: { orderId }
|
|
|
+ })
|
|
|
+ if (response.status !== 200) {
|
|
|
+ throw new Error('确认收货失败')
|
|
|
+ }
|
|
|
+ return response.json()
|
|
|
+ },
|
|
|
+ onSuccess: () => {
|
|
|
+ // 刷新订单列表数据
|
|
|
+ queryClient.invalidateQueries({ queryKey: ['orders'] })
|
|
|
+ queryClient.invalidateQueries({ queryKey: ['order', order.id] })
|
|
|
+
|
|
|
+ // 显示成功信息
|
|
|
+ Taro.showToast({
|
|
|
+ title: '确认收货成功',
|
|
|
+ icon: 'success',
|
|
|
+ duration: 2000
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onError: (error) => {
|
|
|
+ // 根据错误消息类型显示不同的用户友好提示
|
|
|
+ let errorMessage = '确认收货失败,请稍后重试'
|
|
|
+
|
|
|
+ if (error.message.includes('订单不存在')) {
|
|
|
+ errorMessage = '订单不存在或已被删除'
|
|
|
+ } else if (error.message.includes('只有已发货的订单才能确认收货')) {
|
|
|
+ errorMessage = '当前订单状态不允许确认收货'
|
|
|
+ } else if (error.message.includes('只有已支付的订单才能确认收货')) {
|
|
|
+ errorMessage = '订单未支付,无法确认收货'
|
|
|
+ } else if (error.message.includes('网络')) {
|
|
|
+ errorMessage = '网络连接失败,请检查网络后重试'
|
|
|
+ }
|
|
|
+
|
|
|
+ Taro.showToast({
|
|
|
+ title: errorMessage,
|
|
|
+ icon: 'error',
|
|
|
+ duration: 3000
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
// 确认收货
|
|
|
const handleConfirmReceipt = () => {
|
|
|
+ // 先显示确认对话框
|
|
|
Taro.showModal({
|
|
|
title: '确认收货',
|
|
|
content: '确认已收到商品吗?',
|
|
|
success: async (res) => {
|
|
|
if (res.confirm) {
|
|
|
try {
|
|
|
- // 这里调用确认收货的API
|
|
|
- Taro.showToast({
|
|
|
- title: '已确认收货',
|
|
|
- icon: 'success'
|
|
|
+ // 准备微信openBusinessView参数
|
|
|
+ const extraData: any = {
|
|
|
+ orderId: order.id!.toString(),
|
|
|
+ // 商户信息 - 需要根据实际微信商户配置填写
|
|
|
+ merchant_id: order.merchantId?.toString() || '1230000109'
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置商户订单号 - 优先使用订单号
|
|
|
+ extraData.merchant_trade_no = order.orderNo || `ORDER_${order.id}`
|
|
|
+ console.debug('使用商户订单号:', extraData.merchant_trade_no)
|
|
|
+
|
|
|
+ // 如果订单已支付,尝试获取支付记录信息(可选)
|
|
|
+ if (order.payState === 2) { // 已支付状态
|
|
|
+ console.debug('订单已支付,尝试查询支付记录...')
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 使用订单API查询支付记录(新端点)
|
|
|
+ console.debug('使用订单API查询支付记录,订单ID:', order.id)
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 调用新的订单支付记录查询端点:GET /api/v1/orders/{orderId}/payment-record
|
|
|
+ const paymentRecordResponse = await orderClient[order.id!.toString()]['payment-record'].$get()
|
|
|
+
|
|
|
+ console.debug('支付记录API响应状态:', paymentRecordResponse.status, 'ok:', paymentRecordResponse.ok)
|
|
|
+
|
|
|
+ if (paymentRecordResponse.ok) {
|
|
|
+ const result = await paymentRecordResponse.json()
|
|
|
+ console.debug('支付记录查询结果:', result)
|
|
|
+
|
|
|
+ if (result.success && result.data?.exists) {
|
|
|
+ const paymentInfo = result.data
|
|
|
+ console.debug('找到支付记录信息:', paymentInfo)
|
|
|
+
|
|
|
+ // 1. 优先使用支付记录中的商户订单号
|
|
|
+ if (paymentInfo.outTradeNo) {
|
|
|
+ extraData.merchant_trade_no = paymentInfo.outTradeNo
|
|
|
+ console.debug('使用支付记录中的商户订单号:', paymentInfo.outTradeNo)
|
|
|
+ } else {
|
|
|
+ console.debug('支付记录中没有商户订单号,使用订单号:', extraData.merchant_trade_no)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取微信交易ID
|
|
|
+ if (paymentInfo.wechatTransactionId) {
|
|
|
+ extraData.transaction_id = paymentInfo.wechatTransactionId
|
|
|
+ console.debug("获取到微信交易ID:", paymentInfo.wechatTransactionId);
|
|
|
+ } else {
|
|
|
+ console.debug('支付记录中没有微信交易ID,可能的原因:')
|
|
|
+ console.debug('1. 微信支付回调还未到达(异步回调可能有延迟)')
|
|
|
+ console.debug('2. 支付状态:', paymentInfo.paymentStatus)
|
|
|
+ console.debug('3. 微信交易ID在支付回调成功时才会生成')
|
|
|
+ console.debug('4. 当前时间:', new Date().toISOString())
|
|
|
+
|
|
|
+ // 添加调试信息,帮助诊断问题
|
|
|
+ console.debug('支付记录详情:', {
|
|
|
+ 订单ID: order.id,
|
|
|
+ 支付状态: paymentInfo.paymentStatus,
|
|
|
+ 是否存在微信交易ID: !!paymentInfo.wechatTransactionId,
|
|
|
+ 商户订单号: paymentInfo.outTradeNo,
|
|
|
+ 记录存在: paymentInfo.exists
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.debug('未找到支付记录或查询失败:', result.message)
|
|
|
+ console.debug('支付记录查询结果:', result)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.warn('支付记录API请求失败,状态:', paymentRecordResponse.status)
|
|
|
+ }
|
|
|
+ } catch (apiError) {
|
|
|
+ console.debug('支付记录API调用失败:', apiError.message)
|
|
|
+ // 如果新端点不可用,回退到旧方法
|
|
|
+ console.debug('尝试使用旧方法查询支付记录...')
|
|
|
+
|
|
|
+ // 方法1:尝试使用支付状态查询端点(如果可用)
|
|
|
+ try {
|
|
|
+ const paymentStatusResponse = await paymentClient['payment']['status'].$get({
|
|
|
+ query: { orderId: order.id!.toString() }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (paymentStatusResponse.ok) {
|
|
|
+ const statusData = await paymentStatusResponse.json()
|
|
|
+ console.debug('支付状态查询成功:', statusData)
|
|
|
+ // 这里可以记录支付状态,但无法获取商户订单号和微信交易ID
|
|
|
+ }
|
|
|
+ } catch (statusError) {
|
|
|
+ console.debug('支付状态查询端点不可用或失败:', statusError.message)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 方法2:尝试使用通用的GET查询(可能不存在)
|
|
|
+ // 注意:由于支付模块可能没有实现通用的CRUD路由,这里需要类型断言
|
|
|
+ try {
|
|
|
+ // 使用类型断言来访问可能的$get方法
|
|
|
+ const paymentClientAny = paymentClient as any
|
|
|
+ if (paymentClientAny.$get) {
|
|
|
+ const paymentResponse = await paymentClientAny.$get({
|
|
|
+ query: {
|
|
|
+ filters: JSON.stringify([{ field: 'externalOrderId', operator: '=', value: order.id }]),
|
|
|
+ pageSize: 1
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ console.debug('支付API响应状态:', paymentResponse.status, 'ok:', paymentResponse.ok)
|
|
|
+
|
|
|
+ if (paymentResponse.ok) {
|
|
|
+ let payments
|
|
|
+ try {
|
|
|
+ const responseText = await paymentResponse.text()
|
|
|
+ console.debug('支付API响应文本:', responseText.substring(0, 200)) // 只显示前200字符
|
|
|
+
|
|
|
+ if (responseText) {
|
|
|
+ // 检查响应是否是HTML(以<开头)
|
|
|
+ const trimmedText = responseText.trim()
|
|
|
+ if (trimmedText.startsWith('<')) {
|
|
|
+ console.warn('支付API返回HTML响应,可能是404错误页面')
|
|
|
+ console.debug('HTML响应开头:', trimmedText.substring(0, 100))
|
|
|
+ payments = { data: [] }
|
|
|
+ } else {
|
|
|
+ // 尝试解析JSON
|
|
|
+ payments = JSON.parse(responseText)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.warn('支付API返回空响应')
|
|
|
+ payments = { data: [] }
|
|
|
+ }
|
|
|
+ } catch (jsonError) {
|
|
|
+ console.error('支付API响应JSON解析失败:', jsonError)
|
|
|
+ console.warn('跳过支付记录查询,使用订单信息')
|
|
|
+ payments = { data: [] }
|
|
|
+ }
|
|
|
+
|
|
|
+ const payment = payments.data?.[0]
|
|
|
+
|
|
|
+ if (payment) {
|
|
|
+ console.debug('找到支付记录:', {
|
|
|
+ paymentId: payment.id,
|
|
|
+ outTradeNo: payment.outTradeNo,
|
|
|
+ wechatTransactionId: payment.wechatTransactionId,
|
|
|
+ paymentStatus: payment.paymentStatus,
|
|
|
+ })
|
|
|
+
|
|
|
+ // 1. 优先使用支付记录中的商户订单号
|
|
|
+ if (payment.outTradeNo) {
|
|
|
+ extraData.merchant_trade_no = payment.outTradeNo
|
|
|
+ console.debug('使用支付记录中的商户订单号:', payment.outTradeNo)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 获取微信交易ID
|
|
|
+ if (payment.wechatTransactionId) {
|
|
|
+ extraData.transaction_id = payment.wechatTransactionId
|
|
|
+ console.debug("获取到微信交易ID:", payment.wechatTransactionId);
|
|
|
+ } else {
|
|
|
+ console.debug('支付记录中没有微信交易ID')
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.debug('未找到支付记录')
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.warn('支付API请求失败,状态:', paymentResponse.status)
|
|
|
+ // 对于非200响应,不尝试解析内容
|
|
|
+ if (paymentResponse.status === 404) {
|
|
|
+ console.warn('支付API端点不存在(404)')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.debug('支付客户端没有$get方法,跳过通用查询')
|
|
|
+ }
|
|
|
+ } catch (getError) {
|
|
|
+ console.debug('通用GET查询失败(可能端点不存在):', getError.message)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('查询支付记录失败,但不影响主要功能:', error.message)
|
|
|
+ // 支付记录查询失败不影响确认收货功能
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.debug('订单未支付或支付状态不是已支付')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 参数验证和优化
|
|
|
+ const businessType = 'weappOrderConfirm' // 固定配置的业务类型
|
|
|
+
|
|
|
+ // 优化extraData,确保必要参数存在
|
|
|
+ const optimizedExtraData = {
|
|
|
+ // 必需参数
|
|
|
+ orderId: extraData.orderId,
|
|
|
+ merchant_id: extraData.merchant_id,
|
|
|
+ merchant_trade_no: extraData.merchant_trade_no,
|
|
|
+ // 可选参数 - 只在存在时添加
|
|
|
+ ...(extraData.transaction_id && { transaction_id: extraData.transaction_id }),
|
|
|
+ ...(extraData.order_no && { order_no: extraData.order_no }),
|
|
|
+ }
|
|
|
+
|
|
|
+ console.debug('微信openBusinessView参数:', {
|
|
|
+ businessType,
|
|
|
+ optimizedExtraData,
|
|
|
+ // 检查必要参数是否存在
|
|
|
+ hasOrderId: !!optimizedExtraData.orderId,
|
|
|
+ hasMerchantId: !!optimizedExtraData.merchant_id,
|
|
|
+ hasMerchantTradeNo: !!optimizedExtraData.merchant_trade_no,
|
|
|
+ hasTransactionId: !!optimizedExtraData.transaction_id,
|
|
|
+ orderState: order.state,
|
|
|
+ payState: order.payState,
|
|
|
+ // 原始extraData用于调试
|
|
|
+ originalExtraData: extraData
|
|
|
})
|
|
|
+
|
|
|
+ console.debug('开始调用微信openBusinessView...')
|
|
|
+
|
|
|
+ // 检查Taro.openBusinessView是否存在
|
|
|
+ if (typeof Taro.openBusinessView !== 'function') {
|
|
|
+ console.error('Taro.openBusinessView不存在!可能的原因:')
|
|
|
+ console.error('1. 微信基础库版本过低')
|
|
|
+ console.error('2. 该API需要特定的微信版本')
|
|
|
+ console.error('3. 开发工具需要更新')
|
|
|
+
|
|
|
+ Taro.showModal({
|
|
|
+ title: '功能不可用',
|
|
|
+ content: '当前微信版本过低,无法使用确认收货功能,请升级微信后重试。',
|
|
|
+ showCancel: false
|
|
|
+ })
|
|
|
+
|
|
|
+ // 降级到普通确认
|
|
|
+ Taro.showToast({
|
|
|
+ title: '正在确认收货...',
|
|
|
+ icon: 'none',
|
|
|
+ duration: 1500
|
|
|
+ })
|
|
|
+
|
|
|
+ // 直接调用后端API
|
|
|
+ confirmReceiptMutation.mutate({ orderId: order.id! })
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用固定的businessType: weappOrderConfirm
|
|
|
+ try {
|
|
|
+ console.debug(`调用微信openBusinessView,businessType: ${businessType}`)
|
|
|
+
|
|
|
+ await Taro.openBusinessView({
|
|
|
+ businessType,
|
|
|
+ extraData: optimizedExtraData,
|
|
|
+ })
|
|
|
+
|
|
|
+ console.log(`微信openBusinessView调用成功,businessType: ${businessType}`)
|
|
|
+
|
|
|
+ } catch (wxError) {
|
|
|
+ console.warn(`微信openBusinessView调用失败:`, wxError)
|
|
|
+
|
|
|
+ // 尝试分析失败原因
|
|
|
+ if (wxError.errMsg) {
|
|
|
+ console.warn('微信API错误信息:', wxError.errMsg)
|
|
|
+
|
|
|
+ // 检查是否是参数错误
|
|
|
+ if (wxError.errMsg.includes('parameter') || wxError.errMsg.includes('参数')) {
|
|
|
+ console.warn('可能是参数错误,尝试简化参数...')
|
|
|
+
|
|
|
+ // 尝试使用最简参数
|
|
|
+ const minimalExtraData = {
|
|
|
+ orderId: optimizedExtraData.orderId,
|
|
|
+ merchant_trade_no: optimizedExtraData.merchant_trade_no,
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ console.debug('尝试使用简化参数:', minimalExtraData)
|
|
|
+ await Taro.openBusinessView({
|
|
|
+ businessType,
|
|
|
+ extraData: minimalExtraData,
|
|
|
+ })
|
|
|
+ console.log('使用简化参数调用成功')
|
|
|
+ } catch (minimalError) {
|
|
|
+ console.warn('简化参数也失败:', minimalError)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 降级方案:使用微信showModal作为替代界面
|
|
|
+ try {
|
|
|
+ const modalRes = await Taro.showModal({
|
|
|
+ title: '确认收货',
|
|
|
+ content: '请确认您已收到商品。\n\n如商品有质量问题,请及时联系客服。',
|
|
|
+ confirmText: '确认收货',
|
|
|
+ cancelText: '取消',
|
|
|
+ showCancel: true
|
|
|
+ })
|
|
|
+
|
|
|
+ if (modalRes.confirm) {
|
|
|
+ console.log('用户通过微信Modal确认收货')
|
|
|
+ // 显示处理中的提示
|
|
|
+ Taro.showToast({
|
|
|
+ title: '正在确认收货...',
|
|
|
+ icon: 'none',
|
|
|
+ duration: 1500
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ console.log('用户取消确认收货')
|
|
|
+ Taro.showToast({
|
|
|
+ title: '已取消',
|
|
|
+ icon: 'none',
|
|
|
+ duration: 1500
|
|
|
+ })
|
|
|
+ return // 用户取消,不继续后续流程
|
|
|
+ }
|
|
|
+ } catch (modalError) {
|
|
|
+ console.warn('微信Modal也失败,直接继续:', modalError)
|
|
|
+ // 即使Modal失败,也继续后续流程
|
|
|
+ Taro.showToast({
|
|
|
+ title: '正在确认收货...',
|
|
|
+ icon: 'none',
|
|
|
+ duration: 1500
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录详细错误信息便于调试
|
|
|
+ console.error('微信openBusinessView详细错误:', {
|
|
|
+ error: wxError,
|
|
|
+ businessType,
|
|
|
+ optimizedExtraData,
|
|
|
+ originalExtraData: extraData,
|
|
|
+ orderId: order.id,
|
|
|
+ orderState: order.state,
|
|
|
+ payState: order.payState
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 微信界面操作成功后(或降级后),调用后端确认收货API
|
|
|
+ console.debug('开始调用后端确认收货API...')
|
|
|
+ confirmReceiptMutation.mutate({ orderId: order.id! })
|
|
|
+
|
|
|
} catch (error) {
|
|
|
+ console.error('确认收货失败:', error)
|
|
|
Taro.showToast({
|
|
|
- title: '确认失败',
|
|
|
+ title: '确认收货失败',
|
|
|
icon: 'error'
|
|
|
})
|
|
|
}
|
|
|
@@ -167,6 +536,7 @@ export default function OrderButtonBar({ order, onViewDetail, onCancelOrder, hid
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+
|
|
|
// 申请退款 - 调用取消订单逻辑
|
|
|
const handleApplyRefund = () => {
|
|
|
handleCancelOrder()
|
|
|
@@ -252,12 +622,30 @@ export default function OrderButtonBar({ order, onViewDetail, onCancelOrder, hid
|
|
|
button.type === 'primary'
|
|
|
? 'bg-primary text-white border-primary'
|
|
|
: 'bg-white text-gray-600 border-gray-300'
|
|
|
- } ${cancelOrderMutation.isPending && button.text === '取消订单' ? 'opacity-50' : ''}`}
|
|
|
- onClick={cancelOrderMutation.isPending && button.text === '取消订单' ? undefined : button.onClick}
|
|
|
- data-testid={button.text === '取消订单' ? 'cancel-order-button' : undefined}
|
|
|
+ } ${
|
|
|
+ (cancelOrderMutation.isPending && button.text === '取消订单') ||
|
|
|
+ (confirmReceiptMutation.isPending && button.text === '确认收货')
|
|
|
+ ? 'opacity-50'
|
|
|
+ : ''
|
|
|
+ }`}
|
|
|
+ onClick={
|
|
|
+ (cancelOrderMutation.isPending && button.text === '取消订单') ||
|
|
|
+ (confirmReceiptMutation.isPending && button.text === '确认收货')
|
|
|
+ ? undefined
|
|
|
+ : button.onClick
|
|
|
+ }
|
|
|
+ data-testid={
|
|
|
+ button.text === '取消订单' ? 'cancel-order-button' :
|
|
|
+ button.text === '确认收货' ? 'confirm-receipt-button' :
|
|
|
+ undefined
|
|
|
+ }
|
|
|
>
|
|
|
<Text>
|
|
|
- {cancelOrderMutation.isPending && button.text === '取消订单' ? '取消中...' : button.text}
|
|
|
+ {cancelOrderMutation.isPending && button.text === '取消订单'
|
|
|
+ ? '取消中...'
|
|
|
+ : confirmReceiptMutation.isPending && button.text === '确认收货'
|
|
|
+ ? '确认中...'
|
|
|
+ : button.text}
|
|
|
</Text>
|
|
|
</View>
|
|
|
))}
|