123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- import {ref, onMounted, onUnmounted} from 'vue'
- import {createOrder as createOrderApi, getCardPrice, queryOrder} from "@/api/system/user";
- import {createEventHook, useIntervalFn, useLocalStorage, useTimeout} from "@vueuse/core";
- import mxConst from "@/common/mxConst";
- import _ from "lodash";
- import {func, number} from "@/uni_modules/uv-ui-tools/libs/function/test";
- import {useTransfer} from "@/hooks/useTransfer";
- import {toast} from "@/uni_modules/uv-ui-tools/libs/function";
- import config from "@/config";
- import {useEnvStore} from "@/hooks/useEnvStore";
- import {useUserStore} from "@/hooks/useUserStore";
- export const paymentState = {
- NOTPAY: 'NOTPAY',
- SUCCESS: 'SUCCESS',
- CLOSED: 'CLOSED'
- }
- export const defaultPaymentOptions = {
- onSucceed: () => {
- const {transferTo} = useTransfer()
- uni.hideLoading()
- uni.showModal({
- content: '支付成功, 请查收短信并绑定VIP卡',
- confirmText: '去绑卡',
- success: res => {
- if (res.confirm) {
- transferTo(mxConst.routes.activate)
- }
- }
- })
- },
- onTimeout: (msg) => {
- uni.hideLoading()
- uni.showModal({
- content: msg,
- showCancel: false
- })
- },
- onFailed: () => {
- uni.hideLoading()
- // only print error info on console.
- console.error(...arguments)
- }
- }
- export const usePayment = function (options = defaultPaymentOptions) {
- const orderSucceed = createEventHook()
- const orderFailed = createEventHook()
- const orderTimeout = createEventHook()
- const price = ref(798)
- const outTradeNo = useLocalStorage(mxConst.keyOutTradeNo, '')
- const interval = ref(1500)
- let queryTimes = 8;
- let iframe = null
- let lock = false
- onMounted(() => loadPrice())
- onUnmounted(() => {
- // clear resources
- outTradeNo.value = null
- clearResultFrame()
- })
- const payment = async function () {
- if (lock) return toast('支付中,请稍候...')
- uni.showLoading({title:"", mask: true})
- try {
- lock = true // will release while trigger func be called
- const {h5url, outTradeNo: no} = await createOrder()
- if (h5url && no) {
- outTradeNo.value = no
- clearResultFrame()
- queryTimes = 8;
- iframe = await createResultFrame(h5url)
- } else {
- triggerFailed('Payment: create order failed', h5url, no)
- }
- } catch (e) {
- triggerFailed('Payment: exception', e)
- }
- }
- const iosPayment = async function () {
- const {isWap2App} = useEnvStore();
- const {token} = useUserStore();
- if (isWap2App.value && window.webviewBridge) {
- uni.showLoading({
- title: "",
- });
- const { orderId } = await createOrder('ios');
- uni.hideLoading();
- if (orderId) {
- let eventArgs = []
- window.webviewBridge.applePay({
- orderId,
- token: token.value,
- baseUrl: config.serverBaseUrl + '/front/ecard/iosVerifyResult'
- }).then(res => {
- if (res === "支付成功") {
- eventArgs = ['交易成功', orderId]
- triggerSucceed(...eventArgs)
- } else {
- eventArgs = ['支付失败', orderId]
- triggerFailed(...eventArgs)
- }
- });
- }
- } else {
- toast("请在app中操作");
- }
- }
- const loadPrice = async function () {
- const res = await getCardPrice()
- const val = _.get(res, 'data[0].price')
- if (number(val)) price.value = val / 100
- }
- const createOrder = async function (type) {
- const {data: {h5url, outTradeNo, orderId}} = await createOrderApi({totalFee: price.value, type})
- return {h5url, outTradeNo, orderId}
- }
- const createResultFrame = async function (h5url) {
- const { isH5, isWap2App } = useEnvStore();
- if (isH5.value) {
- await useTimeout()
- const iframe = document.createElement('iframe');
- const style = `width:0px;height:0px;position: absolute;opacity: 0;z-index: -1;outline:none;border:none;`;
- iframe.setAttribute('style', style);
- iframe.setAttribute('sandbox', 'allow-scripts allow-top-navigation allow-same-origin');
- iframe.style.position = 'absolute';
- iframe.src = h5url;
- iframe.onload = () => checkOrderStatus()
- iframe.onerror = () => console.error('Payment: iframe加载失败')
- document.body.appendChild(iframe);
- return iframe
- } else if (isWap2App.value) {
- const style = {
- webviewBGTransparent: true,
- opacity: 0,
- render: 'always',
- zindex: -1,
- width: '1px',
- height: '1px',
- top:'0px',
- left:'0px',
- additionalHttpHeaders:{
- Referer: config.paySiteUrl,
- }
- };
- const wv = plus.webview.create(h5url, 'wechatPayWebview', style);
- wv.addEventListener('loaded', (e) => {
- checkOrderStatus();
- }, false);
- wv.show();
- return wv;
- }
- }
- const checkOrderStatus = async function () {
- if (!outTradeNo.value) return
- const {pause} = useIntervalFn(() => {
- const no = outTradeNo.value // double check
- if (!no) return pause()
- if (queryTimes-- <= 0) {
- triggerTimeout('支付超时')
- return pause();
- }
- // 由于这个请示不是规范返回,request配置为 custom: {toast: false}
- queryOrder({outTradeNo: no})
- .then()
- .catch(({tradeState}) => {
- console.log(no, tradeState)
- let eventArgs = []
- switch (tradeState) {
- case paymentState.NOTPAY:
- // user payment not complete, do nothing
- // waiting for next order check
- break;
- case paymentState.SUCCESS:
- // success
- outTradeNo.value = ''
- pause()
- eventArgs = ['交易成功', no]
- triggerSucceed(...eventArgs)
- break
- case paymentState.CLOSED:
- // timeout
- outTradeNo.value = ''
- pause()
- eventArgs = ['支付超时', no]
- triggerTimeout(...eventArgs)
- break
- default:
- // unexpected status
- outTradeNo.value = ''
- pause()
- eventArgs = [`未知交易状态:${tradeState}`, no]
- triggerFailed(...eventArgs)
- break
- }
- });
- }, interval)
- }
- const triggerSucceed = function () {
- lock = false
- if (func(options?.onSucceed)) options.onSucceed(...arguments)
- else orderSucceed.trigger(...arguments)
- }
- const triggerTimeout = function () {
- lock = false
- if (func(options?.onTimeout)) options.onTimeout(...arguments)
- orderTimeout.trigger(...arguments)
- }
- const triggerFailed = function () {
- lock = false
- if (func(options?.onFailed)) options.onFailed(...arguments)
- orderFailed.trigger(...arguments)
- }
- const clearResultFrame = function () {
- const { isH5, isWap2App } = useEnvStore();
- if (iframe) {
- if (isH5.value) {
- document.body.removeChild(iframe)
- } else if (isWap2App.value) {
- iframe.close();
- }
- iframe = null;
- }
- }
- return {
- price,
- payment,
- iosPayment,
- onOrderSucceed: orderSucceed.on,
- onOrderFailed: orderFailed.on,
- onOrderTimeout: orderTimeout.on
- }
- }
|