jcloud/dashboard/src2/components/BuyPrepaidCreditsStripe.vue
2025-04-12 17:39:38 +08:00

182 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<label
class="block"
:class="{
'pointer-events-none h-0.5 opacity-0': step != 'Add Card Details',
'mt-4': step == 'Add Card Details'
}"
>
<span class="text-sm leading-4 text-gray-700">
信用卡或借记卡
</span>
<div class="form-input mt-2 block w-full pl-3" ref="card-element"></div>
<ErrorMessage class="mt-1" :message="cardErrorMessage" />
</label>
<div v-if="step == 'Setting up Stripe'" class="mt-8 flex justify-center">
<Spinner class="h-4 w-4 text-gray-600" />
</div>
<ErrorMessage
class="mt-2"
:message="$resources.createPaymentIntent.error || errorMessage"
/>
<div class="mt-4 flex w-full justify-between">
<div></div>
<div v-if="step == 'Get Amount'">
<Button
variant="solid"
@click="$resources.createPaymentIntent.submit()"
:loading="$resources.createPaymentIntent.loading"
>
使用 Stripe 进行支付
</Button>
</div>
<div v-if="step == 'Add Card Details'">
<Button
class="ml-2"
variant="solid"
@click="onBuyClick"
:loading="paymentInProgress"
>
通过 Stripe 支付
</Button>
</div>
</div>
</div>
</template>
<script>
import StripeLogo from '@/components/StripeLogo.vue';
import { loadStripe } from '@stripe/stripe-js';
import { toast } from 'vue-sonner';
import { DashboardError } from '../utils/error';
export default {
name: 'BuyPrepaidCreditsStripe',
components: {
StripeLogo
},
props: {
amount: {
default: 0
},
minimumAmount: {
default: 0
}
},
data() {
return {
step: 'Get Amount', // Get Amount / Add Card Details
clientSecret: null,
cardErrorMessage: null,
errorMessage: null,
paymentInProgress: false
};
},
resources: {
createPaymentIntent() {
return {
url: 'jcloud.api.billing.create_payment_intent_for_buying_credits',
params: {
amount: this.amount
},
validate() {
if (
this.amount < this.minimumAmount &&
!this.$team.pg.jerp_partner
) {
throw new DashboardError(
`Amount must be greater than or equal to ${this.minimumAmount}`
);
}
},
async onSuccess(data) {
this.step = 'Setting up Stripe';
let { publishable_key, client_secret } = data;
this.clientSecret = client_secret;
this.stripe = await loadStripe(publishable_key);
this.elements = this.stripe.elements();
let theme = this.$theme;
let style = {
base: {
color: theme.colors.black,
fontFamily: theme.fontFamily.sans.join(', '),
fontSmoothing: 'antialiased',
fontSize: '13px',
'::placeholder': {
color: theme.colors.gray['400']
}
},
invalid: {
color: theme.colors.red['600'],
iconColor: theme.colors.red['600']
}
};
this.card = this.elements.create('card', {
hidePostalCode: true,
style: style,
classes: {
complete: '',
focus: 'bg-gray-100'
}
});
this.step = 'Add Card Details';
this.$nextTick(() => {
this.card.mount(this.$refs['card-element']);
});
this.card.addEventListener('change', event => {
this.cardErrorMessage = event.error?.message || null;
});
this.card.addEventListener('ready', () => {
this.ready = true;
});
}
};
}
},
methods: {
setupStripe() {
this.$resources.createPaymentIntent.submit();
},
async onBuyClick() {
this.paymentInProgress = true;
let payload = await this.stripe.confirmCardPayment(this.clientSecret, {
payment_method: {
card: this.card
}
});
if (payload.error) {
this.errorMessage = payload.error.message;
this.paymentInProgress = false;
} else {
toast.success(
'支付处理成功我们将在收到Stripe确认后尽快更新您的账户'
);
this.paymentInProgress = false;
this.$emit('success');
this.errorMessage = null;
}
}
},
computed: {
totalAmount() {
let { currency, billing_info } = this.$account
? this.$account.team
: this.$team.pg;
if (currency === 'CNY') {
return Number(
(
this.amount +
this.amount * (billing_info.gst_percentage || 0)
).toFixed(2)
);
} else {
return this.amount;
}
}
}
};
</script>