xuw5
2026-05-07 94caa88a7ae0743369ade41c0ca83becde503606
feat: 完成支付分逻辑第一稿
3个文件已修改
363 ■■■■■ 已修改文件
src/actions/cashier.ts 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constants/api.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/cashier/index.tsx 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/actions/cashier.ts
@@ -2,6 +2,10 @@
  API_GET_ORDER_INFO,
  API_PAY,
  API_GET_PAY_RESULT,
  API_CREDIT_PAY_SIGN,
  API_CREDIT_PAY_SIGN_QUERY,
  API_CREDIT_ORDER_CREATE,
  API_CREDIT_ORDER_QUERY,
} from '../constants/api'
import { createAction } from '../utils/redux'
import { APPID } from '../constants/app'
@@ -51,3 +55,51 @@
    showToast: true,
  }, true)
}
// 微信支付分开通
export const dispatchCreditPaySign = (payload, autoLogin = true) => {
  return createAction({
    url: API_CREDIT_PAY_SIGN,
    type: '',
    method: 'POST',
    payload,
    autoLogin,
    showToast: true,
  }, true)
}
// 查询开通结果
export const dispatchCreditPaySignQuery = (payload, autoLogin = true) => {
  return createAction({
    url: API_CREDIT_PAY_SIGN_QUERY,
    type: '',
    method: 'POST',
    payload,
    autoLogin,
    showToast: true,
  }, true)
}
// 信用下单
export const dispatchCreditOrderCreate = (payload, autoLogin = true) => {
  return createAction({
    url: API_CREDIT_ORDER_CREATE,
    type: '',
    method: 'POST',
    payload,
    autoLogin,
    showToast: true,
  }, true)
}
// 查询信用订单
export const dispatchCreditOrderQuery = (payload, autoLogin = true) => {
  return createAction({
    url: API_CREDIT_ORDER_QUERY,
    type: '',
    method: 'POST',
    payload,
    autoLogin,
    showToast: true,
  }, true)
}
src/constants/api.ts
@@ -138,6 +138,11 @@
export const API_PAY = `${_PAY_HOST}/api/v1/mini/pay`
export const API_GET_PAY_RESULT = `${_PAY_HOST}/api/v1/mini/query`
export const API_GET_ORDER_INFO = `${_PAY_HOST}/api/v1/mini/cashier`
export const API_CREDIT_PAY_SIGN = `${_PAY_HOST}/v1/mini/pay/creditPay/sign`
export const API_CREDIT_PAY_SIGN_QUERY = `${_PAY_HOST}/v1/mini/pay/creditPay/sign/query`
export const API_CREDIT_ORDER_CREATE = `${_PAY_HOST}/v1/mini/pay/creditPay/creditOrder/create`
export const API_CREDIT_ORDER_QUERY = `${_PAY_HOST}/v1/mini/pay/creditPay/creditOrder/query`
// subscribe
export const API_SUBSCRIBECREATE_FREE = `${_MINI_HOST}/api/subscribeFree/create`
src/pages/cashier/index.tsx
@@ -2,7 +2,7 @@
import { Component } from 'react';
import { connect } from 'react-redux';
import { View, Text, Image, Button } from '@tarojs/components';
import { dispatchGetOrderInfo, dispatchMakePay, dispatchGetResult } from '../../actions/cashier';
import { dispatchGetOrderInfo, dispatchMakePay, dispatchGetResult, dispatchCreditPaySign, dispatchCreditPaySignQuery, dispatchCreditOrderCreate, dispatchCreditOrderQuery } from '../../actions/cashier';
import { getStorage } from '../../utils/tools';
import { jumpTo } from '../../utils/jump';
import { dispatchSubscribeCreateFree } from '../../actions/im';
@@ -17,6 +17,10 @@
  dispatchMakePay: any
  dispatchGetResult: any
  dispatchSubscribeCreateFree: any
  dispatchCreditPaySign: any
  dispatchCreditPaySignQuery: any
  dispatchCreditOrderCreate: any
  dispatchCreditOrderQuery: any
}
type State = {
@@ -28,7 +32,7 @@
const ENV = process.env.TARO_ENV;
// @ts-ignore
@connect(() => ({}), { dispatchGetOrderInfo, dispatchMakePay, dispatchGetResult, dispatchSubscribeCreateFree })
@connect(() => ({}), { dispatchGetOrderInfo, dispatchMakePay, dispatchGetResult, dispatchSubscribeCreateFree, dispatchCreditPaySign, dispatchCreditPaySignQuery, dispatchCreditOrderCreate, dispatchCreditOrderQuery })
/**
 * 收银台页面
 *
@@ -124,7 +128,7 @@
            return;
          }
          if (ENV === 'weapp') {
            if (item.payType === 1 || item.payType === 11 || item.payType === 17 || item.payType === 19) {
            if (item.payType === 1 || item.payType === 11 || item.payType === 17 || item.payType === 19 || item.payType === 13) {
              payType = item.payType;
            }
          } else if (ENV === 'alipay') {
@@ -159,6 +163,13 @@
    }
    const { payType } = this.state;
    // 微信支付分走单独流程
    if (payType === 13) {
      this.creditPay();
      return;
    }
    const { openId } = await this.$app.getIdData() || {};
    getStorage(_UID)
      .then(res => {
@@ -187,6 +198,282 @@
        console.log(err)
      })
      .then(() => this.loading = false);
  }
  // 微信支付分支付流程
  creditPay = async () => {
    try {
      // 第一步:查询微信支付分开通状态
      const status = await this.queryCreditPaySignStatus();
      console.log('creditPay sign status:', status);
      if (status === 'VALID') {
        // 已开通,进入信用下单流程
        await this.creditOrderCreate();
      } else if (status === 'INVALID' || status === 'INIT') {
        // 未签约,走签约开通流程
        await this.creditPaySign();
      } else {
        Taro.showToast({ title: `当前状态: ${status || '未知'},暂不支持`, icon: 'none' });
        this.resetLoading();
      }
    } catch (err) {
      console.error('creditPay error:', err);
      Taro.showToast({ title: '查询支付分状态失败', icon: 'none' });
      this.resetLoading();
    }
  }
  // 微信支付分签约开通
  creditPaySign = async () => {
    try {
      // 调用签约接口获取 signStr(预授权token)
      const signRes = await this.props.dispatchCreditPaySign({
        token: this.token,
        payType: 13,
        returnUrl: null,
        cancelUrl: null,
      });
      console.log('creditPaySign result:', signRes);
      const signStr = signRes?.signStr;
      if (!signStr) {
        Taro.showToast({ title: '获取授权信息失败', icon: 'none' });
        this.resetLoading();
        return;
      }
      // 拉起微信支付分授权窗口
      // @ts-ignore
      if (wx.openBusinessView) {
        // 即将跳转到微信侧,解锁 loading(用户在外部小程序中无法操作当前页面)
        this.resetLoading();
        // @ts-ignore
        wx.openBusinessView({
          businessType: 'wxpayScoreEnable',
          extraData: {
            apply_permissions_token: signStr,
          },
          success: () => {
            console.log('openBusinessView success');
          },
          fail: (err) => {
            console.error('openBusinessView fail:', err);
            Taro.showToast({ title: '拉起授权失败', icon: 'none' });
          },
          complete: () => {
            console.log('openBusinessView complete');
          },
        });
        // 监听从微信支付分小程序返回
        const handleAppShow = async (res) => {
          if (res && res.scene === 1038) {
            const { appId } = res.referrerInfo || {};
            if (appId === 'wxd8f3793ea3b935b8') {
              Taro.offAppShow(handleAppShow);
              this.appShowListener = null;
              // 用户返回,重新加锁
              this.loading = true;
              try {
                const newStatus = await this.queryCreditPaySignStatus();
                console.log('sign callback status:', newStatus);
                if (newStatus === 'VALID') {
                  Taro.showToast({ title: '开通成功', icon: 'success' });
                  await this.creditOrderCreate();
                } else {
                  Taro.showToast({ title: '开通未完成', icon: 'none' });
                  this.resetLoading();
                }
              } catch (e) {
                console.error('query sign status after auth error:', e);
                Taro.showToast({ title: '查询签约结果失败', icon: 'none' });
                this.resetLoading();
              }
            }
          }
        };
        this.appShowListener = handleAppShow;
        Taro.onAppShow(handleAppShow);
      } else {
        Taro.showToast({ title: '请升级微信版本后重试', icon: 'none' });
        this.resetLoading();
      }
    } catch (err) {
      console.error('creditPaySign error:', err);
      Taro.showToast({ title: '签约请求失败', icon: 'none' });
      this.resetLoading();
    }
  }
  // 信用下单
  creditOrderCreate = async () => {
    try {
      Taro.showLoading({ title: '下单中...' });
      const { openId } = await this.$app.getIdData() || {};
      const orderRes = await this.props.dispatchCreditOrderCreate({
        token: this.token,
        payType: 13,
        openId,
      });
      Taro.hideLoading();
      console.log('creditOrderCreate result:', orderRes);
      if (!orderRes) {
        Taro.showToast({ title: '信用下单失败', icon: 'none' });
        this.resetLoading();
        return;
      }
      const { businessOrderId, authOrderId, channelOrderId } = orderRes;
      const packageStr = orderRes.package;
      // 拉起微信支付分订单确认页
      // @ts-ignore
      if (wx.openBusinessView) {
        // 即将跳转到微信侧,解锁 loading
        this.resetLoading();
        // @ts-ignore
        wx.openBusinessView({
          businessType: 'wxpayScoreUse',
          extraData: {
            package: packageStr,
          },
          success: () => {
            console.log('openBusinessView wxpayScoreUse success');
          },
          fail: (err) => {
            console.error('openBusinessView wxpayScoreUse fail:', err);
            Taro.showToast({ title: '拉起支付分订单失败', icon: 'none' });
          },
          complete: () => {
            console.log('openBusinessView wxpayScoreUse complete');
          },
        });
        // 监听从微信支付分小程序返回
        const handleAppShow = async (res) => {
          if (res && res.scene === 1038) {
            const { appId } = res.referrerInfo || {};
            if (appId === 'wxd8f3793ea3b935b8') {
              Taro.offAppShow(handleAppShow);
              this.appShowListener = null;
              this.loading = true;
              // 轮询查询信用订单状态
              await this.pollCreditOrderStatus({ businessOrderId, authOrderId, channelOrderId });
            }
          }
        };
        this.appShowListener = handleAppShow;
        Taro.onAppShow(handleAppShow);
      } else {/*  */
        Taro.showToast({ title: '请升级微信版本后重试', icon: 'none' });
        this.resetLoading();
      }
    } catch (err) {
      Taro.hideLoading();
      console.error('creditOrderCreate error:', err);
      Taro.showToast({ title: '信用下单失败', icon: 'none' });
      this.resetLoading();
    }
  }
  // 轮询查询信用订单状态
  pollCreditOrderStatus = async ({ businessOrderId, authOrderId, channelOrderId }) => {
    const maxRetries = 10;
    const interval = 2000;
    let retries = 0;
    Taro.showLoading({ title: '查询订单状态...' });
    const poll = () => {
      this.timer = setInterval(async () => {
        retries++;
        try {
          const queryRes = await this.props.dispatchCreditOrderQuery({
            token: this.token,
            businessOrderId,
            authOrderId,
            channelOrderId,
            payType: 13,
          });
          console.log('creditOrderQuery result:', queryRes);
          const status = queryRes?.creditOrderStatus;
          if (status === 'DOING' || status === 'DONE') {
            clearInterval(this.timer);
            Taro.hideLoading();
            this.resetLoading();
            this.creditOrderSuccess(queryRes);
            return;
          }
          if (status === 'REVOKED' || status === 'EXPIRED') {
            clearInterval(this.timer);
            Taro.hideLoading();
            this.resetLoading();
            Taro.showToast({ title: '订单已取消或失效', icon: 'none' });
            return;
          }
          if (retries >= maxRetries) {
            clearInterval(this.timer);
            Taro.hideLoading();
            this.resetLoading();
            Taro.showToast({ title: '查询超时,请稍后再试', icon: 'none' });
          }
        } catch (err) {
          console.error('pollCreditOrderStatus error:', err);
          if (retries >= maxRetries) {
            clearInterval(this.timer);
            Taro.hideLoading();
            this.resetLoading();
            Taro.showToast({ title: '查询订单状态失败', icon: 'none' });
          }
        }
      }, interval);
    };
    poll();
  }
  // 统一重置 loading 状态
  resetLoading = () => {
    this.loading = false;
  }
  // 信用订单成功回调
  creditOrderSuccess = (orderRes) => {
    console.log('creditOrderSuccess:', orderRes);
    if (this.from === 'app') {
      this.setState({ showModal: true });
      return;
    }
    if (this.from === 'miniapp') {
      Taro.eventCenter.trigger('cashier:paySuccess', {
        businessOrderId: orderRes.businessOrderId,
        channelOrderId: orderRes.channelOrderId,
        authOrderId: orderRes.authOrderId,
        creditOrderStatus: orderRes.creditOrderStatus,
      });
      jumpTo({ type: 'back' });
      return;
    }
  }
  // 查询微信支付分签约状态
  queryCreditPaySignStatus = async (): Promise<string> => {
    const signRes = await this.props.dispatchCreditPaySignQuery({
      token: this.token,
      payType: 13,
    });
    console.log('creditPaySignQuery result:', signRes);
    const signList = signRes?.signList || [];
    const signItem = signList.find((item: any) => String(item.payType) === '13');
    return signItem?.status || '';
  }
  // 银联云闪付支付
@@ -444,6 +731,19 @@
                  </View>
                );
              }
              if (item.payType === 13) {
                return (
                  <View key={item.payType} className='pay-item' onClick={() => this.selectPayType(item.payType)}>
                    <Image className='icon' src={require('./assets/ic_wx.png')}></Image>
                    <View className='name'>微信支付分 | 先乘后付</View>
                    {payType === item.payType ? (
                      <Image className='ic-right' src={require('./assets/ic_select.png')}></Image>
                    ) : (
                      <Image className='ic-right' src={require('./assets/ic_se_default.png')}></Image>
                    )}
                  </View>
                );
              }
            })}
          </View>
        )}