feat(payment): Stripe multi-method support + card type + hide single-type selector

- Add TypeCard payment type for bank card payments
- Stripe provider now supports card/alipay/wxpay payment methods
- Map payment types to Stripe payment_method_types (card, alipay, wechat_pay)
- Hide supported types selector for single-type providers (alipay/wxpay official)
- Add card i18n labels and PaymentMethodSelector styles
This commit is contained in:
erio
2026-04-07 00:23:54 +08:00
parent ec88ca6c57
commit 55b526582b
10 changed files with 48 additions and 17 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.108.36
0.1.108.37
+34 -9
View File
@@ -59,7 +59,7 @@ func (s *Stripe) GetPublishableKey() string {
func (s *Stripe) Name() string { return "Stripe" }
func (s *Stripe) ProviderKey() string { return "stripe" }
func (s *Stripe) SupportedTypes() []payment.PaymentType {
return []payment.PaymentType{payment.TypeStripe}
return []payment.PaymentType{payment.TypeCard, payment.TypeAlipay, payment.TypeWxpay}
}
// centsToYuan converts an amount in cents (int64) to yuan (float64).
@@ -76,6 +76,13 @@ func yuanToCents(amountStr string) (int64, error) {
return int64(math.Round(amount * 100)), nil
}
// stripePaymentMethodTypes maps our PaymentType to Stripe payment_method_types.
var stripePaymentMethodTypes = map[string][]string{
payment.TypeCard: {"card"},
payment.TypeAlipay: {"alipay"},
payment.TypeWxpay: {"wechat_pay"},
}
// CreatePayment creates a Stripe PaymentIntent.
func (s *Stripe) CreatePayment(ctx context.Context, req payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
s.ensureInit()
@@ -85,15 +92,33 @@ func (s *Stripe) CreatePayment(ctx context.Context, req payment.CreatePaymentReq
return nil, fmt.Errorf("stripe create payment: %w", err)
}
params := &stripe.PaymentIntentCreateParams{
Amount: stripe.Int64(amountInCents),
Currency: stripe.String(stripeCurrency),
AutomaticPaymentMethods: &stripe.PaymentIntentCreateAutomaticPaymentMethodsParams{
Enabled: stripe.Bool(true),
},
Description: stripe.String(req.Subject),
Metadata: map[string]string{"orderId": req.OrderID},
methods, ok := stripePaymentMethodTypes[req.PaymentType]
if !ok {
methods = []string{"card"}
}
pmTypes := make([]*string, len(methods))
for i, m := range methods {
pmTypes[i] = stripe.String(m)
}
params := &stripe.PaymentIntentCreateParams{
Amount: stripe.Int64(amountInCents),
Currency: stripe.String(stripeCurrency),
PaymentMethodTypes: pmTypes,
Description: stripe.String(req.Subject),
Metadata: map[string]string{"orderId": req.OrderID},
}
// WeChat Pay requires payment_method_options with client type
if req.PaymentType == payment.TypeWxpay {
params.PaymentMethodOptions = &stripe.PaymentIntentCreatePaymentMethodOptionsParams{
WeChatPay: &stripe.PaymentIntentCreatePaymentMethodOptionsWeChatPayParams{
Client: stripe.String("web"),
},
}
}
params.SetIdempotencyKey(fmt.Sprintf("pi-%s", req.OrderID))
params.Context = ctx
+3
View File
@@ -14,6 +14,7 @@ const (
TypeAlipayDirect PaymentType = "alipay_direct"
TypeWxpayDirect PaymentType = "wxpay_direct"
TypeStripe PaymentType = "stripe"
TypeCard PaymentType = "card"
TypeEasyPay PaymentType = "easypay"
)
@@ -39,6 +40,8 @@ func GetBasePaymentType(t string) string {
switch {
case t == "easypay":
return "easypay"
case t == "card":
return "card"
case len(t) >= 6 && t[:6] == "alipay":
return "alipay"
case len(t) >= 5 && t[:5] == "wxpay":
@@ -63,14 +63,14 @@ const emit = defineEmits<{
const { t } = useI18n()
function isStripe(type: string) {
return type === 'stripe'
return type === 'stripe' || type === 'card'
}
function iconBgClass(type: string): string {
if (type === 'easypay') return 'bg-[#FF6B35]'
if (type.includes('alipay')) return 'bg-[#00AEEF]'
if (type.includes('wxpay')) return 'bg-[#07C160]'
if (type === 'stripe') return 'bg-[#635bff]'
if (type === 'stripe' || type === 'card') return 'bg-[#635bff]'
return 'bg-gray-500'
}
@@ -85,7 +85,7 @@ function methodSelectedClass(type: string): string {
if (type === 'easypay') return 'border-[#FF6B35] bg-orange-50 text-gray-900 shadow-sm dark:bg-orange-950 dark:text-gray-100'
if (type.includes('alipay')) return 'border-[#00AEEF] bg-blue-50 text-gray-900 shadow-sm dark:bg-blue-950 dark:text-gray-100'
if (type.includes('wxpay')) return 'border-[#07C160] bg-green-50 text-gray-900 shadow-sm dark:bg-green-950 dark:text-gray-100'
if (type === 'stripe') return 'border-[#635bff] bg-indigo-50 text-gray-900 shadow-sm dark:bg-indigo-950 dark:text-gray-100'
if (type === 'stripe' || type === 'card') return 'border-[#635bff] bg-indigo-50 text-gray-900 shadow-sm dark:bg-indigo-950 dark:text-gray-100'
return 'border-primary-500 bg-primary-50 text-gray-900 shadow-sm dark:bg-primary-950 dark:text-gray-100'
}
</script>
@@ -29,8 +29,8 @@
</div>
</div>
<!-- Supported types -->
<div>
<!-- Supported types (hide for single-type providers) -->
<div v-if="availableTypes.length > 1">
<label class="input-label">
{{ t('admin.settings.payment.supportedTypes') }}
<span class="text-red-500">*</span>
@@ -30,7 +30,7 @@ export const PROVIDER_SUPPORTED_TYPES: Record<string, string[]> = {
easypay: ['easypay', 'alipay', 'wxpay'],
alipay: ['alipay'],
wxpay: ['wxpay'],
stripe: ['stripe'],
stripe: ['card', 'alipay', 'wxpay'],
}
/** Webhook paths for each provider (relative to origin). */
+1
View File
@@ -5059,6 +5059,7 @@ export default {
alipay: 'Alipay',
wxpay: 'WeChat Pay',
stripe: 'Stripe',
card: 'Card',
alipay_direct: 'Alipay (Direct)',
wxpay_direct: 'WeChat Pay (Direct)',
},
+1
View File
@@ -5256,6 +5256,7 @@ export default {
alipay: '支付宝',
wxpay: '微信支付',
stripe: 'Stripe',
card: '银行卡',
alipay_direct: '支付宝(直连)',
wxpay_direct: '微信支付(直连)',
},
+1 -1
View File
@@ -18,7 +18,7 @@ export type OrderStatus =
| 'REFUNDED'
| 'REFUND_FAILED'
export type PaymentType = 'alipay' | 'wxpay' | 'alipay_direct' | 'wxpay_direct' | 'stripe'
export type PaymentType = 'alipay' | 'wxpay' | 'alipay_direct' | 'wxpay_direct' | 'stripe' | 'card'
export type OrderType = 'balance' | 'subscription'
@@ -2841,6 +2841,7 @@ const allPaymentTypes = computed(() => [
{ value: 'easypay', label: t('payment.methods.easypay') },
{ value: 'alipay', label: t('payment.methods.alipay') },
{ value: 'wxpay', label: t('payment.methods.wxpay') },
{ value: 'card', label: t('payment.methods.card') },
{ value: 'stripe', label: t('payment.methods.stripe') },
])