二维码付款
This commit is contained in:
parent
da4a2c509c
commit
3c862d7dc4
@ -69,7 +69,6 @@ export function setupHttp() {
|
||||
if (data.status === 401) {
|
||||
message.error(i18n.t('http.error.loginExpired'))
|
||||
token.value = '' // 清除 token
|
||||
router.replace('/login')
|
||||
}
|
||||
|
||||
return response
|
||||
|
@ -1,11 +1,8 @@
|
||||
<template>
|
||||
<main class="flex flex-col min-h-svh">
|
||||
<AppHeader class="h-[var(--van-nav-bar-height)]" />
|
||||
<div class="flex-1 flex flex-col">
|
||||
<slot />
|
||||
</div>
|
||||
<AppFooter />
|
||||
</main>
|
||||
</template>
|
||||
<script setup >
|
||||
</script>
|
||||
<script setup></script>
|
||||
|
@ -1,145 +1,140 @@
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import {orderQuery} from "~/api/goods/index.js";
|
||||
import { WebSocketClient } from '@/utils/websocket'
|
||||
const config = useRuntimeConfig()
|
||||
// stripe支付页面
|
||||
import { onMounted, ref } from "vue";
|
||||
import { authStore } from "~/stores/auth/index.js";
|
||||
import { orderQuery } from "~/api/goods/index.js";
|
||||
import { WebSocketClient } from "@/utils/websocket";
|
||||
const config = useRuntimeConfig();
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: 'Stripe支付'
|
||||
})
|
||||
layout: "default",
|
||||
title: "Stripe支付",
|
||||
});
|
||||
|
||||
const stripe = Stripe(config.public.NUXT_PUBLIC_PKEY)
|
||||
const route = useRoute()
|
||||
const baseURL = config.public.NUXT_PUBLIC_API_BASE
|
||||
const items = [{ id: "xl-tshirt", amount: 1000 }]
|
||||
const elements = ref(null)
|
||||
const paymentMessage = ref('')
|
||||
const isLoading = ref(false)
|
||||
const showSpinner = ref(false)
|
||||
let pollTimer = null
|
||||
let timeoutTimer = null
|
||||
const router = useRouter()
|
||||
const stripe = Stripe(config.public.NUXT_PUBLIC_PKEY);
|
||||
const route = useRoute();
|
||||
const baseURL = config.public.NUXT_PUBLIC_API_BASE;
|
||||
const items = [{ id: "xl-tshirt", amount: 1000 }];
|
||||
const elements = ref(null);
|
||||
const paymentMessage = ref("");
|
||||
const isLoading = ref(false);
|
||||
const showSpinner = ref(false);
|
||||
let pollTimer = null;
|
||||
let timeoutTimer = null;
|
||||
const router = useRouter();
|
||||
const startPolling = () => {
|
||||
pollTimer = setInterval(async () => {
|
||||
const res = await orderQuery({
|
||||
orderNo: route.query.payUid
|
||||
})
|
||||
orderNo: route.query.payUid,
|
||||
});
|
||||
if (res.status === 0) {
|
||||
if (res.data.status !== 3) {
|
||||
clearInterval(pollTimer)
|
||||
clearTimeout(timeoutTimer)
|
||||
clearInterval(pollTimer);
|
||||
clearTimeout(timeoutTimer);
|
||||
router.replace({
|
||||
path: route.query.returnUrl,
|
||||
query: {
|
||||
orderNo: route.query.payUid
|
||||
}
|
||||
})
|
||||
orderNo: route.query.payUid,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
}, 1000);
|
||||
|
||||
/* timeoutTimer = setTimeout(() => {
|
||||
/* timeoutTimer = setTimeout(() => {
|
||||
clearInterval(pollTimer)
|
||||
setLoading(false)
|
||||
}, 180000)*/
|
||||
}
|
||||
let wsClient=null
|
||||
};
|
||||
let wsClient = null;
|
||||
const watchWebSocket = () => {
|
||||
wsClient = new WebSocketClient(
|
||||
config.public.NUXT_PUBLIC_SOCKET_URL
|
||||
)
|
||||
const ws = wsClient.connect('/api/v1/order/ws/v2', {
|
||||
wsClient = new WebSocketClient(config.public.NUXT_PUBLIC_SOCKET_URL);
|
||||
const ws = wsClient.connect("/api/v1/order/ws/v2", {
|
||||
PayUid: route.query.payUid,
|
||||
})
|
||||
ws.onOpen(() => {
|
||||
})
|
||||
});
|
||||
ws.onOpen(() => {});
|
||||
ws.onMessage((event) => {
|
||||
router.replace({
|
||||
path: route.query.returnUrl,
|
||||
query: {
|
||||
orderNo: route.query.payUid
|
||||
}
|
||||
})
|
||||
})
|
||||
ws.onClose(() => {
|
||||
})
|
||||
}
|
||||
orderNo: route.query.payUid,
|
||||
},
|
||||
});
|
||||
});
|
||||
ws.onClose(() => {});
|
||||
};
|
||||
async function initialize() {
|
||||
const clientSecret = route.query.stripeKey
|
||||
const clientSecret = route.query.stripeKey;
|
||||
const appearance = {
|
||||
theme: 'stripe',
|
||||
}
|
||||
elements.value = stripe.elements({ appearance, clientSecret })
|
||||
theme: "stripe",
|
||||
};
|
||||
elements.value = stripe.elements({ appearance, clientSecret });
|
||||
|
||||
const paymentElementOptions = {
|
||||
layout: "accordion",
|
||||
}
|
||||
};
|
||||
|
||||
const paymentElement = elements.value.create("payment", paymentElementOptions)
|
||||
paymentElement.mount("#payment-element")
|
||||
const paymentElement = elements.value.create(
|
||||
"payment",
|
||||
paymentElementOptions
|
||||
);
|
||||
paymentElement.mount("#payment-element");
|
||||
}
|
||||
|
||||
async function handleSubmit(e) {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
|
||||
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
|
||||
const { error } = await stripe.confirmPayment({
|
||||
elements: elements.value,
|
||||
confirmParams: {
|
||||
return_url: `${baseURL}${route.query.returnUrl}?orderNo=${route.query.payUid}`,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
if (error) {
|
||||
/* clearInterval(pollTimer)
|
||||
clearTimeout(timeoutTimer)*/
|
||||
if (error.type === "card_error" || error.type === "validation_error") {
|
||||
showMessage(error.message)
|
||||
showMessage(error.message);
|
||||
} else {
|
||||
showMessage("An unexpected error occurred.")
|
||||
showMessage("An unexpected error occurred.");
|
||||
}
|
||||
setLoading(false)
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(messageText) {
|
||||
paymentMessage.value = messageText
|
||||
paymentMessage.value = messageText;
|
||||
setTimeout(() => {
|
||||
paymentMessage.value = ''
|
||||
}, 4000)
|
||||
paymentMessage.value = "";
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
function setLoading(loading) {
|
||||
isLoading.value = loading
|
||||
showSpinner.value = loading
|
||||
isLoading.value = loading;
|
||||
showSpinner.value = loading;
|
||||
}
|
||||
|
||||
|
||||
onUnmounted(()=>{
|
||||
wsClient.disconnect()
|
||||
clearTimeout(timeoutTimer)
|
||||
clearInterval(pollTimer)
|
||||
|
||||
})
|
||||
onUnmounted(() => {
|
||||
wsClient.disconnect();
|
||||
clearTimeout(timeoutTimer);
|
||||
clearInterval(pollTimer);
|
||||
});
|
||||
onMounted(() => {
|
||||
watchWebSocket()
|
||||
initialize()
|
||||
startPolling()
|
||||
})
|
||||
watchWebSocket();
|
||||
initialize();
|
||||
startPolling();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<form id="payment-form" @submit="handleSubmit">
|
||||
<div id="payment-element">
|
||||
</div>
|
||||
<div id="payment-element"></div>
|
||||
<button id="submit">
|
||||
<div class="spinner" :class="{ hidden: !showSpinner }" id="spinner"></div>
|
||||
<span id="button-text" :class="{ hidden: showSpinner }">Pay now</span>
|
||||
</button>
|
||||
<div id="payment-message" :class="{ hidden: !paymentMessage }">{{ paymentMessage }}</div>
|
||||
<div id="payment-message" :class="{ hidden: !paymentMessage }">
|
||||
{{ paymentMessage }}
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
@ -188,7 +183,7 @@ form {
|
||||
|
||||
/* Buttons and links */
|
||||
button {
|
||||
background: #0055DE;
|
||||
background: #0055de;
|
||||
font-family: Arial, sans-serif;
|
||||
color: #ffffff;
|
||||
border-radius: 4px;
|
||||
@ -237,7 +232,7 @@ button:disabled {
|
||||
.spinner:before {
|
||||
width: 10.4px;
|
||||
height: 20.4px;
|
||||
background: #0055DE;
|
||||
background: #0055de;
|
||||
border-radius: 20.4px 0 0 20.4px;
|
||||
top: -0.2px;
|
||||
left: -0.2px;
|
||||
@ -249,7 +244,7 @@ button:disabled {
|
||||
.spinner:after {
|
||||
width: 10.4px;
|
||||
height: 10.2px;
|
||||
background: #0055DE;
|
||||
background: #0055de;
|
||||
border-radius: 0 10.2px 10.2px 0;
|
||||
top: -0.1px;
|
||||
left: 10.2px;
|
||||
@ -289,7 +284,7 @@ button:disabled {
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
color: #30313D;
|
||||
color: #30313d;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@ -315,11 +310,11 @@ table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table tbody tr:first-child td {
|
||||
border-top: 1px solid #E6E6E6; /* Top border */
|
||||
border-top: 1px solid #e6e6e6; /* Top border */
|
||||
padding-top: 10px;
|
||||
}
|
||||
table tbody tr:last-child td {
|
||||
border-bottom: 1px solid #E6E6E6; /* Bottom border */
|
||||
border-bottom: 1px solid #e6e6e6; /* Bottom border */
|
||||
}
|
||||
td {
|
||||
padding-bottom: 10px;
|
||||
@ -327,21 +322,21 @@ td {
|
||||
|
||||
.TableContent {
|
||||
text-align: right;
|
||||
color: #6D6E78;
|
||||
color: #6d6e78;
|
||||
}
|
||||
|
||||
.TableLabel {
|
||||
font-weight: 600;
|
||||
color: #30313D;
|
||||
color: #30313d;
|
||||
}
|
||||
|
||||
#view-details {
|
||||
color: #0055DE;
|
||||
color: #0055de;
|
||||
}
|
||||
|
||||
#retry-button {
|
||||
text-align: center;
|
||||
background: #0055DE;
|
||||
background: #0055de;
|
||||
color: #ffffff;
|
||||
border-radius: 4px;
|
||||
border: 0;
|
||||
@ -378,7 +373,8 @@ td {
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
form, #payment-status{
|
||||
form,
|
||||
#payment-status {
|
||||
width: 80vw;
|
||||
min-width: initial;
|
||||
}
|
||||
@ -388,7 +384,7 @@ td {
|
||||
}
|
||||
|
||||
form {
|
||||
width:100vw;
|
||||
width: 100vw;
|
||||
align-self: center;
|
||||
box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1),
|
||||
0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07);
|
||||
|
@ -1,104 +1,110 @@
|
||||
<script setup>
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
import {createBuyOrder} from "~/api/goods/index.js";
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import {showLoadingToast, closeToast} from 'vant';
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import {message} from "~/components/x-message/useMessage.js";
|
||||
import {createOrder} from "~/api-collect-code/goods/index.js";
|
||||
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import { liveStore } from "~/stores/live/index.js";
|
||||
import { createBuyOrder } from "~/api/goods/index.js";
|
||||
import { goodStore } from "~/stores/goods/index.js";
|
||||
import { showLoadingToast, closeToast } from "vant";
|
||||
import { authStore } from "~/stores/auth/index.js";
|
||||
import { message } from "~/components/x-message/useMessage.js";
|
||||
import { createOrder } from "~/api-collect-code/goods/index.js";
|
||||
import { codeAuthStore } from "~/stores-collect-code/auth/index.js";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const {t} = useI18n();
|
||||
const {checkoutSessionUrl,qrUid,qrData,codePKey,codePayUid} = codeAuthStore()
|
||||
const payStatus = ref(0)
|
||||
const { t } = useI18n();
|
||||
const { checkoutSessionUrl, qrUid, qrData, codePKey, codePayUid } =
|
||||
codeAuthStore();
|
||||
const payStatus = ref(0);
|
||||
definePageMeta({
|
||||
i18n: 'payment.title'
|
||||
})
|
||||
i18n: "payment.title",
|
||||
});
|
||||
const changePayStatus = () => {
|
||||
payStatus.value = payStatus.value === 0 ? 1 : 0
|
||||
}
|
||||
const amount = ref('')
|
||||
const router = useRouter()
|
||||
payStatus.value = payStatus.value === 0 ? 1 : 0;
|
||||
};
|
||||
const amount = ref("");
|
||||
const router = useRouter();
|
||||
const confirmPay = async () => {
|
||||
if (payStatus.value === 1 && !amount.value) {
|
||||
message.warning(t('collectCode.payment.enterAmount'))
|
||||
return
|
||||
}
|
||||
if (Number(qrData.value.leftPrice) < Number(amount.value)) {
|
||||
message.warning(t('collectCode.payment.exceedTotal'))
|
||||
return
|
||||
}
|
||||
showLoadingToast({
|
||||
message: t('common.loading'),
|
||||
message: t("common.loading"),
|
||||
forbidClick: true,
|
||||
});
|
||||
const res = await createOrder({
|
||||
price: payStatus.value === 0 ? qrData.value.leftPrice : amount.value,
|
||||
currency: qrData.value.currency,
|
||||
qrUid:qrUid.value,
|
||||
testReturnHost:window.location.origin,
|
||||
testReturnEndPoint: '/collectCode/payment/result'
|
||||
})
|
||||
qrUid: qrUid.value,
|
||||
testReturnHost: window.location.origin,
|
||||
testReturnEndPoint: "/collectCode/payment/result",
|
||||
});
|
||||
if (res.status === 0) {
|
||||
codePKey.value=res.data.checkoutSessionUrl
|
||||
codePayUid.value=res.data.payUid
|
||||
codePKey.value = res.data.checkoutSessionUrl;
|
||||
codePayUid.value = res.data.payUid;
|
||||
router.push({
|
||||
path:'/checkoutPage',
|
||||
query:{
|
||||
payUid:res.data.payUid,
|
||||
returnUrl:'/collectCode/payment/result',
|
||||
stripeKey:res.data.checkoutSessionUrl
|
||||
path: "/checkoutPage",
|
||||
query: {
|
||||
payUid: res.data.payUid,
|
||||
returnUrl: "/collectCode/payment/result",
|
||||
stripeKey: res.data.checkoutSessionUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleInput = (e) => {
|
||||
// 只允许数字和小数点,且只保留两位小数
|
||||
const value = e.target.value
|
||||
const value = e.target.value;
|
||||
// 清除非数字和小数点
|
||||
let newValue = value.replace(/[^\d.]/g, '')
|
||||
let newValue = value.replace(/[^\d.]/g, "");
|
||||
// 确保只有一个小数点
|
||||
newValue = newValue.replace(/\.{2,}/g, '.')
|
||||
newValue = newValue.replace(/\.{2,}/g, ".");
|
||||
// 只保留第一个小数点
|
||||
newValue = newValue.replace(/^(\d*\.\d*)\./, '$1')
|
||||
newValue = newValue.replace(/^(\d*\.\d*)\./, "$1");
|
||||
// 保留两位小数
|
||||
if (newValue.indexOf('.') > 0) {
|
||||
newValue = newValue.slice(0, newValue.indexOf('.') + 3)
|
||||
if (newValue.indexOf(".") > 0) {
|
||||
newValue = newValue.slice(0, newValue.indexOf(".") + 3);
|
||||
}
|
||||
// 禁止输入以0开头的多位整数
|
||||
newValue = newValue.replace(/^0+(\d)/, '$1')
|
||||
newValue = newValue.replace(/^0+(\d)/, "$1");
|
||||
|
||||
amount.value = newValue
|
||||
}
|
||||
amount.value = newValue;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover flex-grow-1 flex flex-col items-center pt-183px px-30px">
|
||||
class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover flex-grow-1 flex flex-col items-center pt-183px px-30px"
|
||||
>
|
||||
<div class="mb-30px">
|
||||
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="">
|
||||
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="" />
|
||||
</div>
|
||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{ payStatus === 0 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</div>
|
||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">{{ qrData.currency }}
|
||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">
|
||||
{{
|
||||
payStatus === 0
|
||||
? $t("collectCode.payment.fullPayment")
|
||||
: $t("collectCode.payment.partialPayment")
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
class="text-#999999 text-16px mb-24px font-bold"
|
||||
v-if="payStatus === 0"
|
||||
>
|
||||
{{ qrData.currency }}
|
||||
{{ qrData?.leftPrice }}
|
||||
</div>
|
||||
<div class="mb-12px" v-else>
|
||||
<input v-model="amount" class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text"
|
||||
:placeholder="`${$t('collectCode.payment.maxAmount')} ${qrData.currency} ${qrData?.leftPrice}`" @input="handleInput">
|
||||
<input
|
||||
v-model="amount"
|
||||
class="w-272px h-48px bg-#F3F3F3 px-11px text-16px"
|
||||
type="text"
|
||||
:placeholder="`${$t('collectCode.payment.maxAmount')} ${
|
||||
qrData.currency
|
||||
} ${qrData?.leftPrice}`"
|
||||
@input="handleInput"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{ payStatus === 1 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</div>
|
||||
<div class="w-full mt-auto mb-40px">
|
||||
<van-button type="primary" block @click="confirmPay">
|
||||
{{ $t('collectCode.payment.confirmPayment') }}
|
||||
{{ $t("collectCode.payment.confirmPayment") }}
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
@ -1,37 +1,47 @@
|
||||
<script setup>
|
||||
import {orderQuery} from "~/api/goods/index.js";
|
||||
import { orderQuery } from "~/api/goods/index.js";
|
||||
definePageMeta({
|
||||
i18n: 'payment.text1',
|
||||
})
|
||||
const router = useRouter()
|
||||
const {t}=useI18n();
|
||||
i18n: "payment.text1",
|
||||
});
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const resData=ref({})
|
||||
const res=await orderQuery({
|
||||
orderNo:route.query.orderNo
|
||||
})
|
||||
if (res.status===0){
|
||||
resData.value=res.data
|
||||
}
|
||||
const statusLabel={
|
||||
1:t('payment.text2'),
|
||||
2:t('payment.text3'),
|
||||
3:t('payment.text4'),
|
||||
4:t('payment.text5'),
|
||||
}
|
||||
const goHome=()=>{
|
||||
router.push('/')
|
||||
const resData = ref({});
|
||||
const res = await orderQuery({
|
||||
orderNo: route.query.orderNo,
|
||||
});
|
||||
if (res.status === 0) {
|
||||
resData.value = res.data;
|
||||
}
|
||||
const statusLabel = {
|
||||
1: t("payment.text2"),
|
||||
2: t("payment.text3"),
|
||||
3: t("payment.text4"),
|
||||
4: t("payment.text5"),
|
||||
};
|
||||
const goHome = () => {
|
||||
router.push("/");
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px">
|
||||
<div
|
||||
class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px"
|
||||
>
|
||||
<div class="flex flex-col items-center mt-150px">
|
||||
<img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt="">
|
||||
<div class="text-#000 text-16px mb-25px">{{statusLabel[resData.status]}}!</div>
|
||||
<div class="text-#999 text-16px">{{resData.currency}}{{resData.money}}</div>
|
||||
<img
|
||||
class="w-119px h-120px mb-36px"
|
||||
src="@/static/images/5554@2x1.png"
|
||||
alt=""
|
||||
/>
|
||||
<div class="text-#000 text-16px mb-25px">
|
||||
{{ statusLabel[resData.status] }}!
|
||||
</div>
|
||||
<!-- <div class="w-full mt-auto mb-40px">
|
||||
<div class="text-#999 text-16px">
|
||||
{{ resData.currency }}{{ resData.money }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="w-full mt-auto mb-40px">
|
||||
<van-button type="primary" block @click="goHome">
|
||||
回到首页
|
||||
</van-button>
|
||||
@ -39,6 +49,4 @@ const goHome=()=>{
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
@ -1,37 +1,37 @@
|
||||
<script setup>
|
||||
import {useI18n} from "vue-i18n";
|
||||
import XVanSelect from '@/components/x-van-select/index.vue'
|
||||
import XVanDate from '@/components/x-van-date/index.vue'
|
||||
import {codeAuthStore} from "@/stores-collect-code/auth/index.js";
|
||||
import {message} from "@/components/x-message/useMessage.js";
|
||||
import {fddInfo, offlineQrcode} from "~/api-collect-code/goods/index.js";
|
||||
import {signOffline} from "~/api/goods/index.js";
|
||||
const {formData,number,auctionArtworkUuid,qrUid,qrData}=codeAuthStore()
|
||||
import { useI18n } from "vue-i18n";
|
||||
import XVanSelect from "@/components/x-van-select/index.vue";
|
||||
import XVanDate from "@/components/x-van-date/index.vue";
|
||||
import { codeAuthStore } from "@/stores-collect-code/auth/index.js";
|
||||
import { message } from "@/components/x-message/useMessage.js";
|
||||
import { fddInfo, offlineQrcode } from "~/api-collect-code/goods/index.js";
|
||||
import { signOffline } from "~/api/goods/index.js";
|
||||
const { formData, number, auctionArtworkUuid, qrUid, qrData } = codeAuthStore();
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
i18n: 'menu.profile',
|
||||
})
|
||||
layout: "default",
|
||||
i18n: "menu.profile",
|
||||
});
|
||||
|
||||
const {t} = useI18n()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const columns = ref([
|
||||
{text: t('realAuth.male'), value: 1},
|
||||
{text: t('realAuth.female'), value: 2},
|
||||
])
|
||||
{ text: t("realAuth.male"), value: 1 },
|
||||
{ text: t("realAuth.female"), value: 2 },
|
||||
]);
|
||||
const columns1 = ref([
|
||||
{text: t('realAuth.idTypeString'), value: 1},
|
||||
{text: t('realAuth.passport'), value: 2},
|
||||
{text: t('realAuth.other'), value: 3},
|
||||
])
|
||||
const goCountryRegion=()=>{
|
||||
{ text: t("realAuth.idTypeString"), value: 1 },
|
||||
{ text: t("realAuth.passport"), value: 2 },
|
||||
{ text: t("realAuth.other"), value: 3 },
|
||||
]);
|
||||
const goCountryRegion = () => {
|
||||
router.push({
|
||||
path:'/countryRegion'
|
||||
})
|
||||
}
|
||||
path: "/countryRegion",
|
||||
});
|
||||
};
|
||||
function isFormComplete(obj) {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
if (typeof obj[key] === "object" && obj[key] !== null) {
|
||||
if (!isFormComplete(obj[key])) {
|
||||
return false;
|
||||
}
|
||||
@ -42,116 +42,140 @@ function isFormComplete(obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const getData=async ()=>{
|
||||
const res=await offlineQrcode({
|
||||
qrUid:qrUid.value
|
||||
})
|
||||
if (res.status===0){
|
||||
qrData.value=res.data
|
||||
const getData = async () => {
|
||||
const res = await offlineQrcode({
|
||||
qrUid: qrUid.value,
|
||||
});
|
||||
if (res.status === 0) {
|
||||
qrData.value = res.data;
|
||||
}
|
||||
}
|
||||
const initData= async ()=>{
|
||||
if (route.query.number){
|
||||
number.value=Number(route.query.number)
|
||||
};
|
||||
const initData = async () => {
|
||||
if (route.query.number) {
|
||||
number.value = Number(route.query.number);
|
||||
}
|
||||
if (route.query.qrUid){
|
||||
qrUid.value=route.query.qrUid
|
||||
if (route.query.qrUid) {
|
||||
qrUid.value = route.query.qrUid;
|
||||
}
|
||||
//扫付款码进来才有的步骤
|
||||
if (number.value==2){
|
||||
await getData()
|
||||
if (qrData.value.payStatus===4){
|
||||
router.replace('/collectCode/payment')
|
||||
if (number.value == 2) {
|
||||
await getData();
|
||||
if (qrData.value.payStatus === 4) {
|
||||
router.replace("/collectCode/payment");
|
||||
}
|
||||
}
|
||||
|
||||
if (route.query.zone){
|
||||
formData.value.countryCode=route.query.zone
|
||||
}else {
|
||||
formData.value.countryCode='86'
|
||||
}
|
||||
}
|
||||
const nextClick=async ()=>{
|
||||
//扫号牌
|
||||
if (number.value==1){
|
||||
if (!isFormComplete(formData.value)){
|
||||
message.warning(t('signature.error.incompleteForm'))
|
||||
return
|
||||
}
|
||||
//国内签署要用法大大
|
||||
if (formData.value.countryCode==='86'&&formData.value.cardType===1){
|
||||
const res=await fddInfo({
|
||||
phone:formData.value.phone
|
||||
})
|
||||
if (res.status===0){
|
||||
if (res.data.status===2){
|
||||
router.push('/collectCode/signature/protocol')
|
||||
}else {
|
||||
const res1=await signOffline({
|
||||
userInfo:formData.value,
|
||||
signOrder:Number(number.value),
|
||||
testReturnHost:window.location.origin,
|
||||
testReturnEndPoint:'/collectCode/signature/protocol',
|
||||
})
|
||||
if (res1.status===0){
|
||||
window.location.href=res1.data.fddVerifyUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
if (route.query.zone) {
|
||||
formData.value.countryCode = route.query.zone;
|
||||
} else {
|
||||
//国外签署直接去确认然后签字版
|
||||
router.push('/collectCode/signature/protocol')
|
||||
formData.value.countryCode = "86";
|
||||
}
|
||||
} else if(number.value==2) {
|
||||
if (!formData.value.phone || !formData.value.countryCode || !formData.value.userName){
|
||||
message.warning('请填写完整信息')
|
||||
return
|
||||
};
|
||||
const nextClick = async () => {
|
||||
//扫号牌
|
||||
if (number.value == 2) {
|
||||
if (
|
||||
!formData.value.phone ||
|
||||
!formData.value.countryCode ||
|
||||
!formData.value.userName
|
||||
) {
|
||||
message.warning("请填写完整信息");
|
||||
return;
|
||||
}
|
||||
router.push('/collectCode/signature/protocol')
|
||||
router.push("/collectCode/signature/protocol");
|
||||
}
|
||||
}
|
||||
initData()
|
||||
};
|
||||
initData();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] h-screen-nav bg-cover pt-77px flex-grow-1 flex flex-col ">
|
||||
class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] h-screen-nav bg-cover pt-77px flex-grow-1 flex flex-col"
|
||||
>
|
||||
<div class="text-16px text-#191919 font-bold mb-40px px-34px">
|
||||
{{ $t('personal.title') }}
|
||||
{{ $t("personal.title") }}
|
||||
</div>
|
||||
<div class="grow-1 px-34px">
|
||||
<van-field v-model="formData.phone" type="tel" :label-width="161" :label="$t('personal.text')" class="mb-10px" :placeholder="$t('realAuth.phonePlaceholder')">
|
||||
<van-field
|
||||
v-model="formData.phone"
|
||||
type="tel"
|
||||
:label-width="161"
|
||||
:label="$t('personal.text')"
|
||||
class="mb-10px"
|
||||
:placeholder="$t('realAuth.phonePlaceholder')"
|
||||
>
|
||||
<template #label>
|
||||
<div class="flex">
|
||||
<div class="mr-41px whitespace-nowrap">{{ $t('profile.phone') }}</div>
|
||||
<div class="mr-41px whitespace-nowrap">
|
||||
{{ $t("profile.phone") }}
|
||||
</div>
|
||||
<div @click="goCountryRegion">
|
||||
<span class="mr-13px">+ {{ formData.countryCode }}</span>
|
||||
<van-icon name="arrow-down" class="text-#777777"/>
|
||||
<van-icon name="arrow-down" class="text-#777777" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field :label="$t('profile.name')" v-model="formData.userName" class="mb-10px" :placeholder="$t('realAuth.namePlaceholder')"/>
|
||||
<template v-if="number===1">
|
||||
<x-van-select v-model="formData.gender" :label="$t('realAuth.gender')" :columns="columns"/>
|
||||
<x-van-date :label="$t('realAuth.birthday')" v-model="formData.birthday" />
|
||||
<van-field :label="$t('realAuth.adress')" v-model="formData.address" class="mb-10px" :placeholder="$t('realAuth.adressPlaceholder')"/>
|
||||
<van-field :label="$t('realAuth.bank')" v-model="formData.bankName" class="mb-10px" :placeholder="$t('realAuth.bankPlaceholder')"/>
|
||||
<van-field :label="$t('realAuth.bankCard')" v-model="formData.bankNo" class="mb-10px" :placeholder="$t('realAuth.bankCardPlaceholder')"/>
|
||||
<x-van-select v-model="formData.cardType" :label="$t('realAuth.idTye')" :columns="columns1"/>
|
||||
<van-field :label="$t('realAuth.idCard')" v-model="formData.cardId" class="mb-10px" :placeholder="$t('realAuth.idCardPlaceholder')"/>
|
||||
<van-field
|
||||
:label="$t('profile.name')"
|
||||
v-model="formData.userName"
|
||||
class="mb-10px"
|
||||
:placeholder="$t('realAuth.namePlaceholder')"
|
||||
/>
|
||||
<template v-if="number === 1">
|
||||
<x-van-select
|
||||
v-model="formData.gender"
|
||||
:label="$t('realAuth.gender')"
|
||||
:columns="columns"
|
||||
/>
|
||||
<x-van-date
|
||||
:label="$t('realAuth.birthday')"
|
||||
v-model="formData.birthday"
|
||||
/>
|
||||
<van-field
|
||||
:label="$t('realAuth.adress')"
|
||||
v-model="formData.address"
|
||||
class="mb-10px"
|
||||
:placeholder="$t('realAuth.adressPlaceholder')"
|
||||
/>
|
||||
<van-field
|
||||
:label="$t('realAuth.bank')"
|
||||
v-model="formData.bankName"
|
||||
class="mb-10px"
|
||||
:placeholder="$t('realAuth.bankPlaceholder')"
|
||||
/>
|
||||
<van-field
|
||||
:label="$t('realAuth.bankCard')"
|
||||
v-model="formData.bankNo"
|
||||
class="mb-10px"
|
||||
:placeholder="$t('realAuth.bankCardPlaceholder')"
|
||||
/>
|
||||
<x-van-select
|
||||
v-model="formData.cardType"
|
||||
:label="$t('realAuth.idTye')"
|
||||
:columns="columns1"
|
||||
/>
|
||||
<van-field
|
||||
:label="$t('realAuth.idCard')"
|
||||
v-model="formData.cardId"
|
||||
class="mb-10px"
|
||||
:placeholder="$t('realAuth.idCardPlaceholder')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t shrink-0">
|
||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px" @click="nextClick">{{ $t('personal.next') }}</van-button>
|
||||
<van-button
|
||||
color="#2B53AC"
|
||||
class="w-213px van-btn-h-38px"
|
||||
@click="nextClick"
|
||||
>{{ $t("personal.next") }}</van-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
:deep(.van-cell.van-field){
|
||||
:deep(.van-cell.van-field) {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,22 +1,18 @@
|
||||
<script setup>
|
||||
import CheckoutPage from '@/components/stripe/CheckoutPage.vue'
|
||||
import CompletePage from '@/components/stripe/CompletePage.vue'
|
||||
import CheckoutPage from "@/components/stripe/CheckoutPage.vue";
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
title: 'Stripe支付'
|
||||
})
|
||||
const route = useRoute()
|
||||
const key=route.query.key??''
|
||||
|
||||
layout: "default",
|
||||
title: "Stripe支付",
|
||||
});
|
||||
const route = useRoute();
|
||||
const key = route.query.key ?? "";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<CheckoutPage/>
|
||||
<div>
|
||||
<CheckoutPage />
|
||||
<!-- <iframe class="w-100vw h-100vh" :src="`/stripe/checkout.html?key=${key}`"></iframe> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
@ -1,18 +0,0 @@
|
||||
<script setup>
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import xImage from '@/components/x-image/index.vue'
|
||||
const {
|
||||
auctionDetail
|
||||
} = goodStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="px-16px pt-14px">
|
||||
<div class="text-#575757 text-14px" v-html="auctionDetail.info">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@ -1,28 +0,0 @@
|
||||
<script setup>
|
||||
import xPopup from '@/components/x-popup/index.vue'
|
||||
import ItemDetail from "@/components/itemDetail/index.vue";
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
const {
|
||||
artWorkDetail
|
||||
} = goodStore()
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
detailInfo: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:show'])
|
||||
const handleClose = () => {
|
||||
emit('update:show', false)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<xPopup :show="show" :title="$t('home.lot_detail')" @update:show="handleClose">
|
||||
<ItemDetail :detailInfo="detailInfo" />
|
||||
</xPopup>
|
||||
</template>
|
@ -1,128 +0,0 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { goodStore } from "@/stores/goods"
|
||||
import DetailPopup from '../DetailPopup/index.vue'
|
||||
import WaterfallFlow from '@/components/waterfallFlow/index.vue'
|
||||
const {
|
||||
itemList,
|
||||
pageRef,
|
||||
currentItem,
|
||||
loading: storeLoading,
|
||||
getArtworkList,
|
||||
} = goodStore()
|
||||
|
||||
const localState = ref({
|
||||
finished: false,
|
||||
refreshing: false,
|
||||
showDetail: false,
|
||||
showHeight: ''
|
||||
})
|
||||
// 加载更多
|
||||
const loadMore = async () => {
|
||||
pageRef.value.page++
|
||||
const { finished } = await getArtworkList()
|
||||
localState.value.finished = finished
|
||||
}
|
||||
|
||||
// 刷新
|
||||
const onRefresh = async () => {
|
||||
try {
|
||||
localState.value.refreshing = true
|
||||
localState.value.finished = false
|
||||
const { finished } = await getArtworkList(true)
|
||||
localState.value.finished = finished
|
||||
} finally {
|
||||
localState.value.refreshing = false
|
||||
}
|
||||
}
|
||||
// 打开详情
|
||||
const openShow = async (item) => {
|
||||
localState.value.showDetail = true
|
||||
currentItem.value = item
|
||||
}
|
||||
/**
|
||||
* 将数字格式化为"250XX"格式,其中XX是两位数
|
||||
* @param {number} num - 要格式化的数字
|
||||
* @return {string} - 格式化后的字符串
|
||||
*/
|
||||
function formatNumber(num) {
|
||||
// 确保输入是有效数字
|
||||
if (typeof num !== 'number' && isNaN(Number(num))) {
|
||||
throw new Error('输入必须是有效数字');
|
||||
}
|
||||
|
||||
// 转换为数字类型(以防输入是字符串数字)
|
||||
const number = Number(num);
|
||||
|
||||
// 数字部分格式化为两位数,不足补0
|
||||
const formattedNum = number.toString().padStart(2, '0');
|
||||
|
||||
// 添加前缀"250"并返回结果
|
||||
return `250${formattedNum}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="px-[16px] pt-[16px]">
|
||||
<van-pull-refresh
|
||||
v-model="localState.refreshing"
|
||||
:success-duration="700"
|
||||
@refresh="onRefresh"
|
||||
>
|
||||
<template #success>
|
||||
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
||||
</template>
|
||||
<van-list
|
||||
v-model:loading="storeLoading"
|
||||
:finished="localState.finished"
|
||||
:finished-text="$t('home.finished_text')"
|
||||
@load="loadMore"
|
||||
>
|
||||
<div class="w-full flex gap-[16px]">
|
||||
<WaterfallFlow :items="itemList" :column-count="2">
|
||||
<template #default="{ item, index }">
|
||||
<div
|
||||
@click="openShow(item)"
|
||||
class="w-full"
|
||||
>
|
||||
<div class="relative w-full">
|
||||
<img
|
||||
:src="item.artwork?.hdPic"
|
||||
class="w-full object-cover rounded-4px"
|
||||
/>
|
||||
<div
|
||||
class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[55px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
|
||||
>
|
||||
Lot{{ formatNumber(item.index) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-[8px]">
|
||||
<div class="text-[14px] text-[#000000] leading-[20px]">
|
||||
{{ item?.artwork?.name }} | {{item?.artwork?.artistName}}
|
||||
</div>
|
||||
<div class="mt-[4px] text-[12px] text-[#575757]">
|
||||
{{ $t('home.start_price') }}:{{ item?.startPrice??0 }}
|
||||
</div>
|
||||
<div
|
||||
v-if="item.soldPrice"
|
||||
class="mt-[4px] text-[12px] text-[#b58047]"
|
||||
>
|
||||
{{ $t('home.close_price') }}:{{ item?.soldPrice??0 }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</WaterfallFlow>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
<DetailPopup v-model:show="localState.showDetail" :detailInfo="currentItem"></DetailPopup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.content {
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
</style>
|
@ -1,95 +0,0 @@
|
||||
<script setup>
|
||||
import liveRoom from '@/pages/liveRoom/index.client.vue';
|
||||
import {goodStore} from "@/stores/goods/index.js";
|
||||
import ItemList from './components/ItemList/index.vue'
|
||||
import Cescribe from './components/Cescribe/index.vue'
|
||||
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
const {auctionDetail,getArtworkList} = goodStore();
|
||||
const {fullLive} = liveStore()
|
||||
const changeLive = () => {
|
||||
if (!fullLive.value){
|
||||
if (auctionDetail.value.isLiving===1){
|
||||
fullLive.value = true;
|
||||
getArtworkList(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="grow-1">
|
||||
<client-only>
|
||||
<div class="relative" @click="changeLive">
|
||||
<liveRoom :class="['changeLive', fullLive ? 'expanded' : 'collapsed']"/>
|
||||
<div v-if="auctionDetail.isLiving===1" class="absolute h-188px w-screen pt-36px flex flex-col text-#fff top-0 left-0 items-center">
|
||||
<div class="text-18px mb-5px">{{ auctionDetail.title }}</div>
|
||||
<div class="text-12px mb-54px">{{ $t('home.text1') }}<van-icon name="arrow" /></div>
|
||||
<div><span>-</span> <span class="text-12px mx-5px">{{auctionDetail.totalNum}}{{ $t('common.items') }}{{ $t('common.auction') }}</span> <span>-</span></div>
|
||||
<div class="text-12px">{{auctionDetail.startDate}} {{auctionDetail.startTitle}}</div>
|
||||
</div>
|
||||
<div v-else class="absolute h-188px w-screen pt-36px flex flex-col text-#fff top-0 left-0 items-center bg-[url('@/static/images/z6022@2x.png')]">
|
||||
<div class="text-18px mb-5px">{{ auctionDetail.title }}</div>
|
||||
<div class="text-12px mb-54px">{{$t('home.text3')}}{{auctionDetail.isLiving===2?$t('home.text4'):$t('home.text5')}}</div>
|
||||
<div><span>-</span> <span class="text-12px mx-5px">{{auctionDetail.totalNum}}{{ $t('common.items') }}{{ $t('common.auction') }}</span> <span>-</span></div>
|
||||
<div class="text-12px">{{auctionDetail.startDate}} {{auctionDetail.startTitle}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</client-only>
|
||||
<div v-if="!fullLive" class="bg-#fff">
|
||||
<van-tabs sticky animated>
|
||||
<van-tab :title="$t('home.tab1')">
|
||||
<ItemList></ItemList>
|
||||
</van-tab>
|
||||
<van-tab :title="$t('home.tab2')">
|
||||
<Cescribe></Cescribe>
|
||||
</van-tab>
|
||||
</van-tabs>
|
||||
<van-back-top right="15vw" bottom="10vh"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
.ellipsis {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:deep(.van-swipe__indicator) {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 1s;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
:deep(.van-swipe__indicator:not(.van-swipe__indicator--active)) {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.changeLive {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
transition: height 0.4s ease, transform 0.4s ease;
|
||||
}
|
||||
|
||||
.changeLive.collapsed {
|
||||
height: 188px;
|
||||
}
|
||||
|
||||
.changeLive.expanded {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
height: calc(100vh - var(--van-nav-bar-height));
|
||||
}
|
||||
</style>
|
@ -1,10 +1,10 @@
|
||||
<script setup>
|
||||
import Home from './home/index.vue'
|
||||
import Payment from "./payment/index.vue";
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
i18n: 'menu.home',
|
||||
})
|
||||
layout: "default",
|
||||
i18n: "menu.payment",
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Home/>
|
||||
<Payment />
|
||||
</template>
|
@ -1,97 +1,118 @@
|
||||
<script setup>
|
||||
import {liveStore} from "~/stores/live/index.js";
|
||||
import {createBuyOrder} from "~/api/goods/index.js";
|
||||
import {goodStore} from "~/stores/goods/index.js";
|
||||
import { showLoadingToast ,closeToast} from 'vant';
|
||||
import {authStore} from "~/stores/auth/index.js";
|
||||
import { liveStore } from "~/stores/live/index.js";
|
||||
import { createBuyOrder } from "~/api/goods/index.js";
|
||||
import { goodStore } from "~/stores/goods/index.js";
|
||||
import { showLoadingToast, closeToast } from "vant";
|
||||
import { authStore } from "~/stores/auth/index.js";
|
||||
|
||||
import {message} from "~/components/x-message/useMessage.js";
|
||||
const {checkoutSessionUrl,payment,payUid}= authStore()
|
||||
const payStatus=ref(0)
|
||||
import { message } from "~/components/x-message/useMessage.js";
|
||||
const { checkoutSessionUrl, payment, payUid } = authStore();
|
||||
const payStatus = ref(0);
|
||||
definePageMeta({
|
||||
i18n: 'payment.title'
|
||||
})
|
||||
const {t}=useI18n()
|
||||
const router=useRouter()
|
||||
const changePayStatus=()=>{
|
||||
payStatus.value=payStatus.value===0?1:0
|
||||
}
|
||||
const { auctionData} = liveStore()
|
||||
const amount=ref('')
|
||||
const confirmPay=async ()=>{
|
||||
if (payStatus.value===1&&!amount.value){
|
||||
message.warning(t('payment.amountRequired'))
|
||||
return
|
||||
i18n: "payment.title",
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const changePayStatus = () => {
|
||||
payStatus.value = payStatus.value === 0 ? 1 : 0;
|
||||
};
|
||||
const { auctionData } = liveStore();
|
||||
const amount = ref("");
|
||||
const confirmPay = async () => {
|
||||
if (payStatus.value === 1 && !amount.value) {
|
||||
message.warning(t("payment.amountRequired"));
|
||||
return;
|
||||
}
|
||||
if (Number(payment.value.leftPrice)<Number(amount.value)){
|
||||
message.warning(t('payment.exceedAmount'))
|
||||
return
|
||||
if (Number(payment.value.leftPrice) < Number(amount.value)) {
|
||||
message.warning(t("payment.exceedAmount"));
|
||||
return;
|
||||
}
|
||||
showLoadingToast({
|
||||
message: t('payment.loading'),
|
||||
message: t("payment.loading"),
|
||||
forbidClick: true,
|
||||
});
|
||||
|
||||
const res=await createBuyOrder({
|
||||
buyUid:payment.value.buyUid,
|
||||
price:payStatus.value===0?payment.value.leftPrice:amount.value,
|
||||
currency:payment.value.leftCurrency,
|
||||
testReturnHost:window.location.origin,
|
||||
testReturnEndPoint:'/payment/result'
|
||||
})
|
||||
const res = await createBuyOrder({
|
||||
buyUid: payment.value.buyUid,
|
||||
price: payStatus.value === 0 ? payment.value.leftPrice : amount.value,
|
||||
currency: payment.value.leftCurrency,
|
||||
testReturnHost: window.location.origin,
|
||||
testReturnEndPoint: "/payment/result",
|
||||
});
|
||||
|
||||
if (res.status===0){
|
||||
checkoutSessionUrl.value=res.data.checkoutSessionUrl
|
||||
payUid.value=res.data.payUid
|
||||
if (res.status === 0) {
|
||||
checkoutSessionUrl.value = res.data.checkoutSessionUrl;
|
||||
payUid.value = res.data.payUid;
|
||||
router.push({
|
||||
path:'/checkoutPage',
|
||||
query:{
|
||||
payUid:res.data.payUid,
|
||||
returnUrl:'/payment/result',
|
||||
stripeKey:res.data.checkoutSessionUrl
|
||||
path: "/checkoutPage",
|
||||
query: {
|
||||
payUid: res.data.payUid,
|
||||
returnUrl: "/payment/result",
|
||||
stripeKey: res.data.checkoutSessionUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleInput = (e) => {
|
||||
// 只允许数字和小数点,且只保留两位小数
|
||||
const value = e.target.value
|
||||
const value = e.target.value;
|
||||
// 清除非数字和小数点
|
||||
let newValue = value.replace(/[^\d.]/g, '')
|
||||
let newValue = value.replace(/[^\d.]/g, "");
|
||||
// 确保只有一个小数点
|
||||
newValue = newValue.replace(/\.{2,}/g, '.')
|
||||
newValue = newValue.replace(/\.{2,}/g, ".");
|
||||
// 只保留第一个小数点
|
||||
newValue = newValue.replace(/^(\d*\.\d*)\./, '$1')
|
||||
newValue = newValue.replace(/^(\d*\.\d*)\./, "$1");
|
||||
// 保留两位小数
|
||||
if (newValue.indexOf('.') > 0) {
|
||||
newValue = newValue.slice(0, newValue.indexOf('.') + 3)
|
||||
if (newValue.indexOf(".") > 0) {
|
||||
newValue = newValue.slice(0, newValue.indexOf(".") + 3);
|
||||
}
|
||||
// 禁止输入以0开头的多位整数
|
||||
newValue = newValue.replace(/^0+(\d)/, '$1')
|
||||
newValue = newValue.replace(/^0+(\d)/, "$1");
|
||||
|
||||
amount.value = newValue
|
||||
}
|
||||
amount.value = newValue;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover flex-grow-1 flex flex-col items-center pt-183px px-30px">
|
||||
<div
|
||||
class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover flex-grow-1 flex flex-col items-center pt-183px px-30px"
|
||||
>
|
||||
<div class="mb-30px">
|
||||
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="">
|
||||
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="" />
|
||||
</div>
|
||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">
|
||||
{{
|
||||
payStatus === 0 ? t("payment.fullPayment") : t("payment.partialPayment")
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
class="text-#999999 text-16px mb-24px font-bold"
|
||||
v-if="payStatus === 0"
|
||||
>
|
||||
{{ payment.leftCurrency }} {{ payment?.leftPrice }}
|
||||
</div>
|
||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{payStatus===0 ? t('payment.fullPayment') : t('payment.partialPayment')}}</div>
|
||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">{{payment.leftCurrency}} {{payment?.leftPrice}}</div>
|
||||
<div class="mb-12px" v-else>
|
||||
<input v-model="amount" class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" :placeholder="`${t('payment.placeholder.amount')}${payment.leftCurrency}${payment?.leftPrice}`" @input="handleInput">
|
||||
<input
|
||||
v-model="amount"
|
||||
class="w-272px h-48px bg-#F3F3F3 px-11px text-16px"
|
||||
type="text"
|
||||
:placeholder="`${t('payment.placeholder.amount')}${
|
||||
payment.leftCurrency
|
||||
}${payment?.leftPrice}`"
|
||||
@input="handleInput"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">
|
||||
{{
|
||||
payStatus === 1 ? t("payment.fullPayment") : t("payment.partialPayment")
|
||||
}}
|
||||
</div>
|
||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===1 ? t('payment.fullPayment') : t('payment.partialPayment')}}</div>
|
||||
<div class="w-full mt-auto mb-40px">
|
||||
<van-button type="primary" block @click="confirmPay">
|
||||
{{ t('payment.confirm') }}
|
||||
{{ t("payment.confirm") }}
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
@ -1,94 +1,102 @@
|
||||
<script setup>
|
||||
import {orderQuery} from "~/api/goods/index.js";
|
||||
import { showLoadingToast, closeToast } from 'vant';
|
||||
// 支付回调
|
||||
import { orderQuery } from "~/api/goods/index.js";
|
||||
import { showLoadingToast, closeToast } from "vant";
|
||||
|
||||
definePageMeta({
|
||||
i18n: 'payment.text1',
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const {t} = useI18n();
|
||||
i18n: "payment.text1",
|
||||
});
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const resData = ref({})
|
||||
let timer = null
|
||||
let startTime = Date.now()
|
||||
const resData = ref({});
|
||||
let timer = null;
|
||||
let startTime = Date.now();
|
||||
|
||||
const queryOrder = async () => {
|
||||
// 首先检查是否已经超过5秒
|
||||
if (Date.now() - startTime > 5000) {
|
||||
clearInterval(timer)
|
||||
closeToast()
|
||||
return
|
||||
clearInterval(timer);
|
||||
closeToast();
|
||||
return;
|
||||
}
|
||||
|
||||
showLoadingToast({
|
||||
message: '加载中...',
|
||||
message: "加载中...",
|
||||
forbidClick: true,
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await orderQuery({
|
||||
orderNo: route.query.orderNo
|
||||
})
|
||||
orderNo: route.query.orderNo,
|
||||
});
|
||||
|
||||
if (res.status === 0) {
|
||||
resData.value = res.data
|
||||
resData.value = res.data;
|
||||
|
||||
// 只在支付成功时停止轮询
|
||||
if (resData.value.status === 1) {
|
||||
clearInterval(timer)
|
||||
closeToast()
|
||||
clearInterval(timer);
|
||||
closeToast();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
clearInterval(timer)
|
||||
closeToast()
|
||||
clearInterval(timer);
|
||||
closeToast();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 立即执行一次
|
||||
await queryOrder()
|
||||
await queryOrder();
|
||||
|
||||
// 开始轮询
|
||||
timer = setInterval(async () => {
|
||||
await queryOrder()
|
||||
}, 1000)
|
||||
await queryOrder();
|
||||
}, 1000);
|
||||
|
||||
// 组件卸载时清除定时器
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
closeToast()
|
||||
clearInterval(timer);
|
||||
closeToast();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const statusLabel = {
|
||||
1: t('payment.text2'),
|
||||
2: t('payment.text3'),
|
||||
3: t('payment.text4'),
|
||||
4: t('payment.text5'),
|
||||
}
|
||||
1: t("payment.text2"),
|
||||
2: t("payment.text3"),
|
||||
3: t("payment.text4"),
|
||||
4: t("payment.text5"),
|
||||
};
|
||||
|
||||
const goHome = () => {
|
||||
router.push('/')
|
||||
}
|
||||
router.push("/");
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px">
|
||||
class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px"
|
||||
>
|
||||
<div class="flex flex-col items-center mt-150px">
|
||||
<img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt="">
|
||||
<div class="text-#000 text-16px mb-25px">{{ statusLabel[resData.status] }}!</div>
|
||||
<div class="text-#999 text-16px">{{ resData.currency }}{{ resData.money }}</div>
|
||||
<img
|
||||
class="w-119px h-120px mb-36px"
|
||||
src="@/static/images/5554@2x1.png"
|
||||
alt=""
|
||||
/>
|
||||
<div class="text-#000 text-16px mb-25px">
|
||||
{{ statusLabel[resData.status] }}!
|
||||
</div>
|
||||
<div class="text-#999 text-16px">
|
||||
{{ resData.currency }}{{ resData.money }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full mt-auto mb-40px">
|
||||
<van-button type="primary" block @click="goHome">
|
||||
{{ t('payment.result.backToHome') }}
|
||||
{{ t("payment.result.backToHome") }}
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
Loading…
Reference in New Issue
Block a user