@@ -0,0 +1,100 @@
|
||||
<script setup lang="ts">
|
||||
import { NInput } from 'naive-ui'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { payInvoice } from '@/api/billing'
|
||||
import FormModal from '@/components/FormModal.vue'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { invoiceDate } from '@/components/tenant/invoiceStatus'
|
||||
import { fmtMoney } from '@/composables/useFormat'
|
||||
import type { Invoice, PaymentMethod } from '@/types/api'
|
||||
|
||||
/** 付款确认:经 OSP Gateway PayInvoice 按订阅默认付款方式即时扣款;
|
||||
* email 是 API 必填项(接收付款回执),在此向用户收集。 */
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
cfgId: number
|
||||
invoice: Invoice | null
|
||||
methods: PaymentMethod[] | null
|
||||
}>()
|
||||
const emit = defineEmits<{ 'update:show': [boolean]; paid: [] }>()
|
||||
const message = useToast()
|
||||
|
||||
const email = ref('')
|
||||
const paying = ref(false)
|
||||
const emailOk = computed(() => /.+@.+\..+/.test(email.value.trim()))
|
||||
|
||||
/** 扣款方式展示:优先第一张信用卡,其次任一登记方式 */
|
||||
const payVia = computed(() => {
|
||||
const ms = props.methods ?? []
|
||||
const m = ms.find((x) => x.method === 'CREDIT_CARD') ?? ms[0]
|
||||
if (!m) return '订阅默认付款方式'
|
||||
if (m.method === 'CREDIT_CARD') return `${m.cardType || '银行卡'} •••• ${m.lastDigits}`
|
||||
return `PayPal(${m.email})`
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(v) => {
|
||||
if (v) paying.value = false
|
||||
},
|
||||
)
|
||||
|
||||
async function doPay() {
|
||||
const inv = props.invoice
|
||||
if (!inv || !emailOk.value) return
|
||||
paying.value = true
|
||||
try {
|
||||
await payInvoice(props.cfgId, inv.internalId, email.value.trim())
|
||||
message.success('付款已提交,发票状态稍后更新')
|
||||
emit('update:show', false)
|
||||
emit('paid')
|
||||
} catch (e) {
|
||||
message.error(e instanceof Error ? e.message : '付款失败')
|
||||
} finally {
|
||||
paying.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FormModal
|
||||
:show="show"
|
||||
title="支付发票"
|
||||
:width="440"
|
||||
submit-text="确认支付"
|
||||
:submitting="paying"
|
||||
:submit-disabled="!emailOk"
|
||||
@update:show="emit('update:show', $event)"
|
||||
@submit="doPay"
|
||||
>
|
||||
<template v-if="invoice">
|
||||
<div class="rounded-md bg-wash px-4 py-3">
|
||||
<div class="text-xs text-ink-3">应付金额</div>
|
||||
<div class="mt-1 text-[24px] font-semibold tabular-nums">
|
||||
{{ fmtMoney(invoice.amountDue || invoice.amount, invoice.currency) }}
|
||||
</div>
|
||||
<div class="mt-1 text-xs text-ink-3">
|
||||
发票 {{ invoice.number }} · 到期 {{ invoiceDate(invoice.timeDue) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-3 flex items-center justify-between rounded-md border border-line-soft px-4 py-2.5 text-[13px]"
|
||||
>
|
||||
<span class="text-ink-3">扣款方式</span>
|
||||
<span class="font-medium">{{ payVia }}</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<div class="mb-1 text-xs text-ink-3">回执邮箱(必填)</div>
|
||||
<NInput v-model:value="email" placeholder="billing@example.com" />
|
||||
</div>
|
||||
|
||||
<div class="mt-3 text-xs leading-relaxed text-ink-3">
|
||||
确认后经 OCI 支付网关按上述方式即时扣款,回执发送至邮箱;提交后发票转入「处理中」,
|
||||
入账通常需要数分钟,期间请勿重复支付。
|
||||
</div>
|
||||
</template>
|
||||
</FormModal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user