Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
02066e2029 | ||
|
32eb6d5836 | ||
|
75ba717203 | ||
|
9eb376d780 | ||
|
18e6fd43f5 | ||
|
80f7297467 | ||
|
3c862d7dc4 |
@ -53,10 +53,10 @@ export async function offlineQrcode(data) {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export async function createOrder(data) {
|
|
||||||
|
|
||||||
return await request( {
|
export async function createOrder (data) {
|
||||||
url:'/api/v1/offlineQrcode/createOrder/V2',
|
return await request({
|
||||||
|
url: '/api/v1/offlineQrcode/antom/createOrder',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
@ -69,7 +69,6 @@ export function setupHttp() {
|
|||||||
if (data.status === 401) {
|
if (data.status === 401) {
|
||||||
message.error(i18n.t('http.error.loginExpired'))
|
message.error(i18n.t('http.error.loginExpired'))
|
||||||
token.value = '' // 清除 token
|
token.value = '' // 清除 token
|
||||||
router.replace('/login')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<main class="flex flex-col min-h-svh">
|
<main class="flex flex-col min-h-svh">
|
||||||
<AppHeader class="h-[var(--van-nav-bar-height)]" />
|
|
||||||
<div class="flex-1 flex flex-col">
|
<div class="flex-1 flex flex-col">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<AppFooter />
|
|
||||||
</main>
|
</main>
|
||||||
</template>
|
</template>
|
||||||
<script setup >
|
<script setup></script>
|
||||||
</script>
|
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import itemDetail from '@/components/itemDetail/index.vue'
|
|
||||||
import {userArtwork} from "~/api/goods/index.js";
|
|
||||||
import {useRouter} from "#vue-router";
|
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
|
||||||
definePageMeta({
|
|
||||||
i18n: 'detail.text8'
|
|
||||||
})
|
|
||||||
const { userInfo, payment } = authStore()
|
|
||||||
const route = useRoute()
|
|
||||||
const detail = ref({})
|
|
||||||
const uuid = route.query.uuid
|
|
||||||
|
|
||||||
const initData = async () => {
|
|
||||||
const res = await userArtwork({uuid})
|
|
||||||
if (res.status === 0) {
|
|
||||||
detail.value = res.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const router = useRouter();
|
|
||||||
const position = ref({x: window?.innerWidth - 120 || 0, y: 240})
|
|
||||||
const startPosition = ref({x: 0, y: 0})
|
|
||||||
const isDragging = ref(false)
|
|
||||||
|
|
||||||
const startDrag = (e) => {
|
|
||||||
isDragging.value = true
|
|
||||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
|
||||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
|
||||||
startPosition.value = {
|
|
||||||
x: clientX - position.value.x,
|
|
||||||
y: clientY - position.value.y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDrag = (e) => {
|
|
||||||
if (isDragging.value) {
|
|
||||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
|
||||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
|
||||||
|
|
||||||
const maxX = window.innerWidth - 108
|
|
||||||
const maxY = window.innerHeight - 137
|
|
||||||
|
|
||||||
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
|
||||||
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
|
||||||
position.value = {x, y}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const stopDrag = () => {
|
|
||||||
isDragging.value = false
|
|
||||||
}
|
|
||||||
const goPay=()=>{
|
|
||||||
payment.value.leftPrice=detail.value.leftPrice
|
|
||||||
payment.value.leftCurrency=detail.value.leftCurrency
|
|
||||||
payment.value.buyUid=detail.value.uuid
|
|
||||||
payment.value.auctionArtworkUuid=detail.value?.auctionArtworkUuid
|
|
||||||
if (detail.value.status===1){
|
|
||||||
router.push('/signature/protocol')
|
|
||||||
}else if (detail.value.status===4){
|
|
||||||
router.push('/payment')
|
|
||||||
}
|
|
||||||
//router.push('/payment')
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
document.addEventListener('mousemove', onDrag)
|
|
||||||
document.addEventListener('mouseup', stopDrag)
|
|
||||||
document.addEventListener('touchmove', onDrag)
|
|
||||||
document.addEventListener('touchend', stopDrag)
|
|
||||||
})
|
|
||||||
onUnmounted(() => {
|
|
||||||
document.removeEventListener('mousemove', onDrag)
|
|
||||||
document.removeEventListener('mouseup', stopDrag)
|
|
||||||
document.removeEventListener('touchmove', onDrag)
|
|
||||||
document.removeEventListener('touchend', stopDrag)
|
|
||||||
})
|
|
||||||
function formatThousands(num) {
|
|
||||||
|
|
||||||
return Number(num).toLocaleString();
|
|
||||||
}
|
|
||||||
initData()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="relative h-screen-nav flex flex-col">
|
|
||||||
<itemDetail class="grow-1" :detail-info="detail.auctionArtworkInfo"/>
|
|
||||||
<div v-if="[1,3,4].includes(detail.status)" class="h-81px bg-#fff flex justify-center pt-7px shrink-0">
|
|
||||||
<van-button class="w-213px !h-38px" type="primary" @click="goPay">
|
|
||||||
<span class="text-#fff text-14px">{{ $t('art_detail_page.button') }} {{detail.leftCurrency}}{{formatThousands(detail.leftPrice)}}</span>
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="w-108px h-137px absolute cursor-move"
|
|
||||||
:style="{
|
|
||||||
left: position.x + 'px',
|
|
||||||
top: position.y + 'px'
|
|
||||||
}"
|
|
||||||
@mousedown="startDrag"
|
|
||||||
@touchstart.prevent="startDrag"
|
|
||||||
>
|
|
||||||
<img src="@/static/images/zd5530@2x.png" class="w-full h-full" alt="">
|
|
||||||
<div
|
|
||||||
class="flex flex-col items-center absolute bottom-25px text-14px text-#B58047 left-1/2 transform translate-x--1/2 whitespace-nowrap shrink-0">
|
|
||||||
<div>{{ $t('art_detail_page.prompt_title')}}</div>
|
|
||||||
<div>{{ $t('art_detail_page.prompt_desc')}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.cursor-move {
|
|
||||||
touch-action: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,145 +1,140 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref } from 'vue'
|
// stripe支付页面
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
import { onMounted, ref } from "vue";
|
||||||
import {orderQuery} from "~/api/goods/index.js";
|
import { authStore } from "~/stores/auth/index.js";
|
||||||
import { WebSocketClient } from '@/utils/websocket'
|
import { orderQuery } from "~/api/goods/index.js";
|
||||||
const config = useRuntimeConfig()
|
import { WebSocketClient } from "@/utils/websocket";
|
||||||
|
const config = useRuntimeConfig();
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: "default",
|
||||||
title: 'Stripe支付'
|
title: "Stripe支付",
|
||||||
})
|
});
|
||||||
|
|
||||||
const stripe = Stripe(config.public.NUXT_PUBLIC_PKEY)
|
const stripe = Stripe(config.public.NUXT_PUBLIC_PKEY);
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const baseURL = config.public.NUXT_PUBLIC_API_BASE
|
const baseURL = config.public.NUXT_PUBLIC_API_BASE;
|
||||||
const items = [{ id: "xl-tshirt", amount: 1000 }]
|
const items = [{ id: "xl-tshirt", amount: 1000 }];
|
||||||
const elements = ref(null)
|
const elements = ref(null);
|
||||||
const paymentMessage = ref('')
|
const paymentMessage = ref("");
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false);
|
||||||
const showSpinner = ref(false)
|
const showSpinner = ref(false);
|
||||||
let pollTimer = null
|
let pollTimer = null;
|
||||||
let timeoutTimer = null
|
let timeoutTimer = null;
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const startPolling = () => {
|
const startPolling = () => {
|
||||||
pollTimer = setInterval(async () => {
|
pollTimer = setInterval(async () => {
|
||||||
const res = await orderQuery({
|
const res = await orderQuery({
|
||||||
orderNo: route.query.payUid
|
orderNo: route.query.payUid,
|
||||||
})
|
});
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
if (res.data.status !== 3) {
|
if (res.data.status !== 3) {
|
||||||
clearInterval(pollTimer)
|
clearInterval(pollTimer);
|
||||||
clearTimeout(timeoutTimer)
|
clearTimeout(timeoutTimer);
|
||||||
router.replace({
|
router.replace({
|
||||||
path: route.query.returnUrl,
|
path: route.query.returnUrl,
|
||||||
query: {
|
query: {
|
||||||
orderNo: route.query.payUid
|
orderNo: route.query.payUid,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000);
|
||||||
|
|
||||||
/* timeoutTimer = setTimeout(() => {
|
/* timeoutTimer = setTimeout(() => {
|
||||||
clearInterval(pollTimer)
|
clearInterval(pollTimer)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}, 180000)*/
|
}, 180000)*/
|
||||||
}
|
};
|
||||||
let wsClient=null
|
let wsClient = null;
|
||||||
const watchWebSocket = () => {
|
const watchWebSocket = () => {
|
||||||
wsClient = new WebSocketClient(
|
wsClient = new WebSocketClient(config.public.NUXT_PUBLIC_SOCKET_URL);
|
||||||
config.public.NUXT_PUBLIC_SOCKET_URL
|
const ws = wsClient.connect("/api/v1/order/ws/v2", {
|
||||||
)
|
|
||||||
const ws = wsClient.connect('/api/v1/order/ws/v2', {
|
|
||||||
PayUid: route.query.payUid,
|
PayUid: route.query.payUid,
|
||||||
})
|
});
|
||||||
ws.onOpen(() => {
|
ws.onOpen(() => {});
|
||||||
})
|
ws.onMessage((event) => {
|
||||||
ws.onMessage((event) => {
|
router.replace({
|
||||||
router.replace({
|
path: route.query.returnUrl,
|
||||||
path: route.query.returnUrl,
|
query: {
|
||||||
query: {
|
orderNo: route.query.payUid,
|
||||||
orderNo: route.query.payUid
|
},
|
||||||
}
|
});
|
||||||
})
|
});
|
||||||
})
|
ws.onClose(() => {});
|
||||||
ws.onClose(() => {
|
};
|
||||||
})
|
|
||||||
}
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
const clientSecret = route.query.stripeKey
|
const clientSecret = route.query.stripeKey;
|
||||||
const appearance = {
|
const appearance = {
|
||||||
theme: 'stripe',
|
theme: "stripe",
|
||||||
}
|
};
|
||||||
elements.value = stripe.elements({ appearance, clientSecret })
|
elements.value = stripe.elements({ appearance, clientSecret });
|
||||||
|
|
||||||
const paymentElementOptions = {
|
const paymentElementOptions = {
|
||||||
layout: "accordion",
|
layout: "accordion",
|
||||||
}
|
};
|
||||||
|
|
||||||
const paymentElement = elements.value.create("payment", paymentElementOptions)
|
const paymentElement = elements.value.create(
|
||||||
paymentElement.mount("#payment-element")
|
"payment",
|
||||||
|
paymentElementOptions
|
||||||
|
);
|
||||||
|
paymentElement.mount("#payment-element");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubmit(e) {
|
async function handleSubmit(e) {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
setLoading(true)
|
setLoading(true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const { error } = await stripe.confirmPayment({
|
const { error } = await stripe.confirmPayment({
|
||||||
elements: elements.value,
|
elements: elements.value,
|
||||||
confirmParams: {
|
confirmParams: {
|
||||||
return_url: `${baseURL}${route.query.returnUrl}?orderNo=${route.query.payUid}`,
|
return_url: `${baseURL}${route.query.returnUrl}?orderNo=${route.query.payUid}`,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
/* clearInterval(pollTimer)
|
|
||||||
clearTimeout(timeoutTimer)*/
|
|
||||||
if (error.type === "card_error" || error.type === "validation_error") {
|
if (error.type === "card_error" || error.type === "validation_error") {
|
||||||
showMessage(error.message)
|
showMessage(error.message);
|
||||||
} else {
|
} else {
|
||||||
showMessage("An unexpected error occurred.")
|
showMessage("An unexpected error occurred.");
|
||||||
}
|
}
|
||||||
setLoading(false)
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMessage(messageText) {
|
function showMessage(messageText) {
|
||||||
paymentMessage.value = messageText
|
paymentMessage.value = messageText;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
paymentMessage.value = ''
|
paymentMessage.value = "";
|
||||||
}, 4000)
|
}, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLoading(loading) {
|
function setLoading(loading) {
|
||||||
isLoading.value = loading
|
isLoading.value = loading;
|
||||||
showSpinner.value = loading
|
showSpinner.value = loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
onUnmounted(()=>{
|
wsClient.disconnect();
|
||||||
wsClient.disconnect()
|
clearTimeout(timeoutTimer);
|
||||||
clearTimeout(timeoutTimer)
|
clearInterval(pollTimer);
|
||||||
clearInterval(pollTimer)
|
});
|
||||||
|
|
||||||
})
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
watchWebSocket()
|
watchWebSocket();
|
||||||
initialize()
|
initialize();
|
||||||
startPolling()
|
startPolling();
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form id="payment-form" @submit="handleSubmit">
|
<form id="payment-form" @submit="handleSubmit">
|
||||||
<div id="payment-element">
|
<div id="payment-element"></div>
|
||||||
</div>
|
|
||||||
<button id="submit">
|
<button id="submit">
|
||||||
<div class="spinner" :class="{ hidden: !showSpinner }" id="spinner"></div>
|
<div class="spinner" :class="{ hidden: !showSpinner }" id="spinner"></div>
|
||||||
<span id="button-text" :class="{ hidden: showSpinner }">Pay now</span>
|
<span id="button-text" :class="{ hidden: showSpinner }">Pay now</span>
|
||||||
</button>
|
</button>
|
||||||
<div id="payment-message" :class="{ hidden: !paymentMessage }">{{ paymentMessage }}</div>
|
<div id="payment-message" :class="{ hidden: !paymentMessage }">
|
||||||
|
{{ paymentMessage }}
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -188,7 +183,7 @@ form {
|
|||||||
|
|
||||||
/* Buttons and links */
|
/* Buttons and links */
|
||||||
button {
|
button {
|
||||||
background: #0055DE;
|
background: #0055de;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@ -237,7 +232,7 @@ button:disabled {
|
|||||||
.spinner:before {
|
.spinner:before {
|
||||||
width: 10.4px;
|
width: 10.4px;
|
||||||
height: 20.4px;
|
height: 20.4px;
|
||||||
background: #0055DE;
|
background: #0055de;
|
||||||
border-radius: 20.4px 0 0 20.4px;
|
border-radius: 20.4px 0 0 20.4px;
|
||||||
top: -0.2px;
|
top: -0.2px;
|
||||||
left: -0.2px;
|
left: -0.2px;
|
||||||
@ -249,7 +244,7 @@ button:disabled {
|
|||||||
.spinner:after {
|
.spinner:after {
|
||||||
width: 10.4px;
|
width: 10.4px;
|
||||||
height: 10.2px;
|
height: 10.2px;
|
||||||
background: #0055DE;
|
background: #0055de;
|
||||||
border-radius: 0 10.2px 10.2px 0;
|
border-radius: 0 10.2px 10.2px 0;
|
||||||
top: -0.1px;
|
top: -0.1px;
|
||||||
left: 10.2px;
|
left: 10.2px;
|
||||||
@ -289,7 +284,7 @@ button:disabled {
|
|||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #30313D;
|
color: #30313d;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,11 +310,11 @@ table {
|
|||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
table tbody tr:first-child td {
|
table tbody tr:first-child td {
|
||||||
border-top: 1px solid #E6E6E6; /* Top border */
|
border-top: 1px solid #e6e6e6; /* Top border */
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
table tbody tr:last-child td {
|
table tbody tr:last-child td {
|
||||||
border-bottom: 1px solid #E6E6E6; /* Bottom border */
|
border-bottom: 1px solid #e6e6e6; /* Bottom border */
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
@ -327,21 +322,21 @@ td {
|
|||||||
|
|
||||||
.TableContent {
|
.TableContent {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: #6D6E78;
|
color: #6d6e78;
|
||||||
}
|
}
|
||||||
|
|
||||||
.TableLabel {
|
.TableLabel {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #30313D;
|
color: #30313d;
|
||||||
}
|
}
|
||||||
|
|
||||||
#view-details {
|
#view-details {
|
||||||
color: #0055DE;
|
color: #0055de;
|
||||||
}
|
}
|
||||||
|
|
||||||
#retry-button {
|
#retry-button {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: #0055DE;
|
background: #0055de;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 0;
|
border: 0;
|
||||||
@ -373,12 +368,13 @@ td {
|
|||||||
}
|
}
|
||||||
@keyframes fadeInAnimation {
|
@keyframes fadeInAnimation {
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
form, #payment-status{
|
form,
|
||||||
|
#payment-status {
|
||||||
width: 80vw;
|
width: 80vw;
|
||||||
min-width: initial;
|
min-width: initial;
|
||||||
}
|
}
|
||||||
@ -388,7 +384,7 @@ td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
width:100vw;
|
width: 100vw;
|
||||||
align-self: center;
|
align-self: center;
|
||||||
box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1),
|
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);
|
0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07);
|
||||||
|
@ -1,104 +1,103 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {liveStore} from "~/stores/live/index.js";
|
import { liveStore } from "~/stores/live/index.js";
|
||||||
import {createBuyOrder} from "~/api/goods/index.js";
|
import { createBuyOrder } from "~/api/goods/index.js";
|
||||||
import {goodStore} from "~/stores/goods/index.js";
|
import { goodStore } from "~/stores/goods/index.js";
|
||||||
import {showLoadingToast, closeToast} from 'vant';
|
import { showLoadingToast, closeToast } from "vant";
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
import { authStore } from "~/stores/auth/index.js";
|
||||||
import {message} from "~/components/x-message/useMessage.js";
|
import { message } from "~/components/x-message/useMessage.js";
|
||||||
import {createOrder} from "~/api-collect-code/goods/index.js";
|
import { createOrder, offlineQrcode } from "~/api-collect-code/goods/index.js";
|
||||||
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
import { codeAuthStore } from "~/stores-collect-code/auth/index.js";
|
||||||
import {useI18n} from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const {t} = useI18n();
|
const amount = ref("");
|
||||||
const {checkoutSessionUrl,qrUid,qrData,codePKey,codePayUid} = codeAuthStore()
|
const router = useRouter();
|
||||||
const payStatus = ref(0)
|
const route = useRoute();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { checkoutSessionUrl, qrUid, qrData, codePKey, codePayUid } =
|
||||||
|
codeAuthStore();
|
||||||
|
const payStatus = ref(0);
|
||||||
|
const state = reactive({
|
||||||
|
pageRequest: false,
|
||||||
|
});
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
i18n: 'payment.title'
|
i18n: "payment.title",
|
||||||
})
|
});
|
||||||
const changePayStatus = () => {
|
const getData = async () => {
|
||||||
payStatus.value = payStatus.value === 0 ? 1 : 0
|
state.pageRequest = true;
|
||||||
}
|
const res = await offlineQrcode({
|
||||||
const amount = ref('')
|
qrUid: route.query.qrUid,
|
||||||
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'),
|
|
||||||
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'
|
|
||||||
})
|
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
codePKey.value=res.data.checkoutSessionUrl
|
qrData.value = res.data;
|
||||||
codePayUid.value=res.data.payUid
|
payStatus.value = res.data.payStatus;
|
||||||
|
if (qrData.value.payStatus === 2) {
|
||||||
|
state.pageRequest = false;
|
||||||
|
} else {
|
||||||
|
confirmPay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 获取二维码价格
|
||||||
|
getData();
|
||||||
|
const confirmPay = async () => {
|
||||||
|
const res = await createOrder({
|
||||||
|
price: qrData.value.price,
|
||||||
|
currency: qrData.value.currency,
|
||||||
|
qrUid: route.query.qrUid,
|
||||||
|
testReturnHost: window.location.origin,
|
||||||
|
testReturnEndPoint: "/collectCode/payment/result",
|
||||||
|
});
|
||||||
|
if (res.status === 0) {
|
||||||
|
codePKey.value = res.data.checkoutSessionUrl;
|
||||||
|
codePayUid.value = res.data.payUid;
|
||||||
|
window.location.href = res.data.checkoutSessionUrl;
|
||||||
|
return;
|
||||||
router.push({
|
router.push({
|
||||||
path:'/checkoutPage',
|
path: "/checkoutPage",
|
||||||
query:{
|
query: {
|
||||||
payUid:res.data.payUid,
|
payUid: res.data.payUid,
|
||||||
returnUrl:'/collectCode/payment/result',
|
returnUrl: "/collectCode/payment/result",
|
||||||
stripeKey:res.data.checkoutSessionUrl
|
stripeKey: res.data.checkoutSessionUrl,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleInput = (e) => {
|
|
||||||
// 只允许数字和小数点,且只保留两位小数
|
|
||||||
const value = e.target.value
|
|
||||||
// 清除非数字和小数点
|
|
||||||
let newValue = value.replace(/[^\d.]/g, '')
|
|
||||||
// 确保只有一个小数点
|
|
||||||
newValue = newValue.replace(/\.{2,}/g, '.')
|
|
||||||
// 只保留第一个小数点
|
|
||||||
newValue = newValue.replace(/^(\d*\.\d*)\./, '$1')
|
|
||||||
// 保留两位小数
|
|
||||||
if (newValue.indexOf('.') > 0) {
|
|
||||||
newValue = newValue.slice(0, newValue.indexOf('.') + 3)
|
|
||||||
}
|
|
||||||
// 禁止输入以0开头的多位整数
|
|
||||||
newValue = newValue.replace(/^0+(\d)/, '$1')
|
|
||||||
|
|
||||||
amount.value = newValue
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<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="">
|
<div
|
||||||
|
v-if="state.pageRequest"
|
||||||
|
class="fixed left-0 top-0 w-full h-full bg-white/50 flex items-center justify-center z-50"
|
||||||
|
>
|
||||||
|
<van-loading color="#1989fa" size="36px" vertical
|
||||||
|
>跳转支付处理中...</van-loading
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{ payStatus === 0 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</div>
|
<div v-if="!state.pageRequest" class="mb-30px">
|
||||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">{{ qrData.currency }}
|
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="" />
|
||||||
{{ qrData?.leftPrice }}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-12px" v-else>
|
<div
|
||||||
<input v-model="amount" class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text"
|
v-if="!state.pageRequest"
|
||||||
:placeholder="`${$t('collectCode.payment.maxAmount')} ${qrData.currency} ${qrData?.leftPrice}`" @input="handleInput">
|
class="text-#999999 text-16px mb-24px font-bold"
|
||||||
|
>
|
||||||
|
{{ qrData.price + " " + qrData.currency }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{ payStatus === 1 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</div>
|
<div
|
||||||
<div class="w-full mt-auto mb-40px">
|
v-if="!state.pageRequest"
|
||||||
|
class="text-#1A1A1A text-16px mb-25px font-bold"
|
||||||
|
>
|
||||||
|
你已完成全部支付!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <div class="w-full mt-auto mb-40px">
|
||||||
<van-button type="primary" block @click="confirmPay">
|
<van-button type="primary" block @click="confirmPay">
|
||||||
{{ $t('collectCode.payment.confirmPayment') }}
|
{{ $t("collectCode.payment.confirmPayment") }}
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
@ -1,37 +1,47 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {orderQuery} from "~/api/goods/index.js";
|
import { orderQuery } from "~/api/goods/index.js";
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
i18n: 'payment.text1',
|
i18n: "payment.text1",
|
||||||
})
|
});
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const {t}=useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const resData=ref({})
|
const resData = ref({});
|
||||||
const res=await orderQuery({
|
const res = await orderQuery({
|
||||||
orderNo:route.query.orderNo
|
orderNo: route.query.orderNo,
|
||||||
})
|
});
|
||||||
if (res.status===0){
|
if (res.status === 0) {
|
||||||
resData.value=res.data
|
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 statusLabel = {
|
||||||
|
1: t("payment.text2"),
|
||||||
|
2: t("payment.text3"),
|
||||||
|
3: t("payment.text4"),
|
||||||
|
4: t("payment.text5"),
|
||||||
|
};
|
||||||
|
const goHome = () => {
|
||||||
|
router.push("/");
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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">
|
<div class="flex flex-col items-center mt-150px">
|
||||||
<img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt="">
|
<img
|
||||||
<div class="text-#000 text-16px mb-25px">{{statusLabel[resData.status]}}!</div>
|
class="w-119px h-120px mb-36px"
|
||||||
<div class="text-#999 text-16px">{{resData.currency}}{{resData.money}}</div>
|
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>
|
||||||
<!-- <div class="w-full mt-auto mb-40px">
|
<!-- <div class="w-full mt-auto mb-40px">
|
||||||
<van-button type="primary" block @click="goHome">
|
<van-button type="primary" block @click="goHome">
|
||||||
回到首页
|
回到首页
|
||||||
</van-button>
|
</van-button>
|
||||||
@ -39,6 +49,4 @@ const goHome=()=>{
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
@ -1,37 +1,37 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useI18n} from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import XVanSelect from '@/components/x-van-select/index.vue'
|
import XVanSelect from "@/components/x-van-select/index.vue";
|
||||||
import XVanDate from '@/components/x-van-date/index.vue'
|
import XVanDate from "@/components/x-van-date/index.vue";
|
||||||
import {codeAuthStore} from "@/stores-collect-code/auth/index.js";
|
import { codeAuthStore } from "@/stores-collect-code/auth/index.js";
|
||||||
import {message} from "@/components/x-message/useMessage.js";
|
import { message } from "@/components/x-message/useMessage.js";
|
||||||
import {fddInfo, offlineQrcode} from "~/api-collect-code/goods/index.js";
|
import { fddInfo, offlineQrcode } from "~/api-collect-code/goods/index.js";
|
||||||
import {signOffline} from "~/api/goods/index.js";
|
import { signOffline } from "~/api/goods/index.js";
|
||||||
const {formData,number,auctionArtworkUuid,qrUid,qrData}=codeAuthStore()
|
const { formData, number, auctionArtworkUuid, qrUid, qrData } = codeAuthStore();
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: "default",
|
||||||
i18n: 'menu.profile',
|
i18n: "menu.profile",
|
||||||
})
|
});
|
||||||
|
|
||||||
const {t} = useI18n()
|
const { t } = useI18n();
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const columns = ref([
|
const columns = ref([
|
||||||
{text: t('realAuth.male'), value: 1},
|
{ text: t("realAuth.male"), value: 1 },
|
||||||
{text: t('realAuth.female'), value: 2},
|
{ text: t("realAuth.female"), value: 2 },
|
||||||
])
|
]);
|
||||||
const columns1 = ref([
|
const columns1 = ref([
|
||||||
{text: t('realAuth.idTypeString'), value: 1},
|
{ text: t("realAuth.idTypeString"), value: 1 },
|
||||||
{text: t('realAuth.passport'), value: 2},
|
{ text: t("realAuth.passport"), value: 2 },
|
||||||
{text: t('realAuth.other'), value: 3},
|
{ text: t("realAuth.other"), value: 3 },
|
||||||
])
|
]);
|
||||||
const goCountryRegion=()=>{
|
const goCountryRegion = () => {
|
||||||
router.push({
|
router.push({
|
||||||
path:'/countryRegion'
|
path: "/countryRegion",
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
function isFormComplete(obj) {
|
function isFormComplete(obj) {
|
||||||
for (const key in 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])) {
|
if (!isFormComplete(obj[key])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -42,116 +42,140 @@ function isFormComplete(obj) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getData=async ()=>{
|
const getData = async () => {
|
||||||
const res=await offlineQrcode({
|
const res = await offlineQrcode({
|
||||||
qrUid:qrUid.value
|
qrUid: qrUid.value,
|
||||||
})
|
});
|
||||||
if (res.status===0){
|
if (res.status === 0) {
|
||||||
qrData.value=res.data
|
qrData.value = res.data;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const initData= async ()=>{
|
const initData = async () => {
|
||||||
if (route.query.number){
|
if (route.query.number) {
|
||||||
number.value=Number(route.query.number)
|
number.value = Number(route.query.number);
|
||||||
}
|
}
|
||||||
if (route.query.qrUid){
|
if (route.query.qrUid) {
|
||||||
qrUid.value=route.query.qrUid
|
qrUid.value = route.query.qrUid;
|
||||||
}
|
}
|
||||||
//扫付款码进来才有的步骤
|
//扫付款码进来才有的步骤
|
||||||
if (number.value==2){
|
if (number.value == 2) {
|
||||||
await getData()
|
await getData();
|
||||||
if (qrData.value.payStatus===4){
|
if (qrData.value.payStatus === 4) {
|
||||||
router.replace('/collectCode/payment')
|
router.replace("/collectCode/payment");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.query.zone){
|
if (route.query.zone) {
|
||||||
formData.value.countryCode=route.query.zone
|
formData.value.countryCode = route.query.zone;
|
||||||
}else {
|
} else {
|
||||||
formData.value.countryCode='86'
|
formData.value.countryCode = "86";
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const nextClick=async ()=>{
|
const nextClick = async () => {
|
||||||
//扫号牌
|
//扫号牌
|
||||||
if (number.value==1){
|
if (number.value == 2) {
|
||||||
if (!isFormComplete(formData.value)){
|
if (
|
||||||
message.warning(t('signature.error.incompleteForm'))
|
!formData.value.phone ||
|
||||||
return
|
!formData.value.countryCode ||
|
||||||
|
!formData.value.userName
|
||||||
|
) {
|
||||||
|
message.warning("请填写完整信息");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
//国内签署要用法大大
|
router.push("/collectCode/signature/protocol");
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//国外签署直接去确认然后签字版
|
|
||||||
router.push('/collectCode/signature/protocol')
|
|
||||||
}
|
|
||||||
} else if(number.value==2) {
|
|
||||||
if (!formData.value.phone || !formData.value.countryCode || !formData.value.userName){
|
|
||||||
message.warning('请填写完整信息')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
router.push('/collectCode/signature/protocol')
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
initData()
|
initData();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<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">
|
<div class="text-16px text-#191919 font-bold mb-40px px-34px">
|
||||||
{{ $t('personal.title') }}
|
{{ $t("personal.title") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="grow-1 px-34px">
|
<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>
|
<template #label>
|
||||||
<div class="flex">
|
<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">
|
<div @click="goCountryRegion">
|
||||||
<span class="mr-13px">+ {{ formData.countryCode }}</span>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
<van-field :label="$t('profile.name')" v-model="formData.userName" class="mb-10px" :placeholder="$t('realAuth.namePlaceholder')"/>
|
<van-field
|
||||||
<template v-if="number===1">
|
:label="$t('profile.name')"
|
||||||
<x-van-select v-model="formData.gender" :label="$t('realAuth.gender')" :columns="columns"/>
|
v-model="formData.userName"
|
||||||
<x-van-date :label="$t('realAuth.birthday')" v-model="formData.birthday" />
|
class="mb-10px"
|
||||||
<van-field :label="$t('realAuth.adress')" v-model="formData.address" class="mb-10px" :placeholder="$t('realAuth.adressPlaceholder')"/>
|
:placeholder="$t('realAuth.namePlaceholder')"
|
||||||
<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')"/>
|
<template v-if="number === 1">
|
||||||
<x-van-select v-model="formData.cardType" :label="$t('realAuth.idTye')" :columns="columns1"/>
|
<x-van-select
|
||||||
<van-field :label="$t('realAuth.idCard')" v-model="formData.cardId" class="mb-10px" :placeholder="$t('realAuth.idCardPlaceholder')"/>
|
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>
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t shrink-0">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
:deep(.van-cell.van-field){
|
:deep(.van-cell.van-field) {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
File diff suppressed because it is too large
Load Diff
@ -1,225 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {ref, computed, watch} from 'vue';
|
|
||||||
import pinyin from 'pinyin';
|
|
||||||
import countryCode from './data/index.js';
|
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
definePageMeta({
|
|
||||||
i18n: 'countryRegion.title',
|
|
||||||
})
|
|
||||||
const router = useRouter()
|
|
||||||
const { t, locale } = useI18n()
|
|
||||||
const value = ref('');
|
|
||||||
const alphabet = computed(() => {
|
|
||||||
if (!groupedCountries.value) return ['#'];
|
|
||||||
|
|
||||||
// 获取所有实际存在的分组字母
|
|
||||||
const letters = Object.keys(groupedCountries.value)
|
|
||||||
.filter(key => key !== '#')
|
|
||||||
.sort();
|
|
||||||
|
|
||||||
// 确保 # 永远在最前
|
|
||||||
return ['#', ...letters];
|
|
||||||
});
|
|
||||||
|
|
||||||
// 常用国家的代码列表
|
|
||||||
const frequentCountryCodes = ['CN', 'TW', 'JP', 'US'];
|
|
||||||
|
|
||||||
function groupByPinyinInitial(data) {
|
|
||||||
const grouped = {};
|
|
||||||
|
|
||||||
// 先处理常用国家
|
|
||||||
grouped['#'] = [];
|
|
||||||
data.forEach(country => {
|
|
||||||
if (frequentCountryCodes.includes(country.code)) {
|
|
||||||
const countryName = locale.value === 'zh-CN' ? country.cn :
|
|
||||||
locale.value === 'zh-TW' ? country.tw :
|
|
||||||
locale.value === 'ja-JP' ? country.ja :
|
|
||||||
country.en;
|
|
||||||
grouped['#'].push({
|
|
||||||
...country,
|
|
||||||
displayName: countryName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// 处理其他国家
|
|
||||||
data.forEach(country => {
|
|
||||||
if (!frequentCountryCodes.includes(country.code)) {
|
|
||||||
const countryName = locale.value === 'zh-CN' ? country.cn :
|
|
||||||
locale.value === 'zh-TW' ? country.tw :
|
|
||||||
locale.value === 'ja-JP' ? country.ja :
|
|
||||||
country.en;
|
|
||||||
|
|
||||||
// 根据语言环境决定使用拼音还是英文首字母
|
|
||||||
let initial;
|
|
||||||
if (locale.value === 'zh-CN' || locale.value === 'zh-TW') {
|
|
||||||
// 中文和繁体使用拼音首字母
|
|
||||||
const pinyinName = locale.value === 'zh-CN' ? country.cn : country.tw;
|
|
||||||
initial = pinyin(pinyinName, {style: pinyin.STYLE_FIRST_LETTER})[0][0].toUpperCase();
|
|
||||||
} else if (locale.value === 'ja-JP') {
|
|
||||||
initial = '';
|
|
||||||
} else {
|
|
||||||
// 英文使用 en 字段首字母
|
|
||||||
initial = country.en.charAt(0).toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!grouped[initial]) {
|
|
||||||
grouped[initial] = [];
|
|
||||||
}
|
|
||||||
grouped[initial].push({
|
|
||||||
...country,
|
|
||||||
displayName: countryName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 对每个分组内的国家按照对应语言排序
|
|
||||||
Object.keys(grouped).forEach(key => {
|
|
||||||
grouped[key].sort((a, b) => {
|
|
||||||
if (locale.value === 'zh-CN' || locale.value === 'zh-TW') {
|
|
||||||
// 中文和繁体使用拼音排序
|
|
||||||
const pinyinA = pinyin(locale.value === 'zh-CN' ? a.cn : a.tw, {style: pinyin.STYLE_NORMAL}).join('');
|
|
||||||
const pinyinB = pinyin(locale.value === 'zh-CN' ? b.cn : b.tw, {style: pinyin.STYLE_NORMAL}).join('');
|
|
||||||
return pinyinA.localeCompare(pinyinB);
|
|
||||||
} else if (locale.value === 'ja-JP') {
|
|
||||||
return a.displayName.localeCompare(b.displayName, 'ja-JP');
|
|
||||||
} else {
|
|
||||||
return a.en.localeCompare(b.en);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (locale.value === 'ja-JP') {
|
|
||||||
return grouped;
|
|
||||||
} else {
|
|
||||||
// 按字母顺序返回排序后的对象
|
|
||||||
const sortedGrouped = {};
|
|
||||||
// 确保 # 永远在最前
|
|
||||||
sortedGrouped['#'] = grouped['#'];
|
|
||||||
// 其他字母按顺序排序
|
|
||||||
Object.keys(grouped)
|
|
||||||
.filter(key => key !== '#')
|
|
||||||
.sort()
|
|
||||||
.forEach(key => {
|
|
||||||
sortedGrouped[key] = grouped[key];
|
|
||||||
});
|
|
||||||
return sortedGrouped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const groupedCountries = ref([])
|
|
||||||
const initData = () => {
|
|
||||||
groupedCountries.value = groupByPinyinInitial(countryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchCountry = computed(() => {
|
|
||||||
if (!value.value) {
|
|
||||||
return groupedCountries.value;
|
|
||||||
}
|
|
||||||
return Object.keys(groupedCountries.value).reduce((filtered, initial) => {
|
|
||||||
const countries = groupedCountries.value[initial].filter(country =>
|
|
||||||
country.displayName.toLowerCase().includes(value.value.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
if (countries.length > 0) {
|
|
||||||
filtered[initial] = countries;
|
|
||||||
}
|
|
||||||
return filtered;
|
|
||||||
}, {});
|
|
||||||
});
|
|
||||||
|
|
||||||
const showIndexBar = computed(() => locale.value !== 'ja-JP')
|
|
||||||
const route = useRoute()
|
|
||||||
const handleCountrySelect = (country) => {
|
|
||||||
router.replace({
|
|
||||||
path: window.history.state.back,
|
|
||||||
query: {
|
|
||||||
zone: country.zone,
|
|
||||||
countryName: country.displayName
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
initData()
|
|
||||||
// 监听语言变化,重新初始化数据
|
|
||||||
watch(locale, () => {
|
|
||||||
initData()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<van-sticky>
|
|
||||||
<van-search v-model="value" :placeholder="t('countryRegion.searchPlaceholder')"/>
|
|
||||||
</van-sticky>
|
|
||||||
<van-index-bar
|
|
||||||
v-if="showIndexBar"
|
|
||||||
sticky
|
|
||||||
:sticky-offset-top="55"
|
|
||||||
:index-list="alphabet"
|
|
||||||
>
|
|
||||||
<!-- 常用国家分类 -->
|
|
||||||
<van-index-anchor index="#">{{ t('countryRegion.frequentCountry') }}</van-index-anchor>
|
|
||||||
<van-cell
|
|
||||||
v-for="country in searchCountry['#']"
|
|
||||||
:key="country.code"
|
|
||||||
:title="country.displayName"
|
|
||||||
@click="handleCountrySelect(country)"
|
|
||||||
clickable
|
|
||||||
>
|
|
||||||
<div class="pr-[25px]"> +{{ country.zone }}</div>
|
|
||||||
</van-cell>
|
|
||||||
|
|
||||||
<!-- 其他国家按字母分类 -->
|
|
||||||
<template v-for="(countries, index) in searchCountry" :key="index">
|
|
||||||
<template v-if="index !== '#'">
|
|
||||||
<van-index-anchor
|
|
||||||
:index="index"
|
|
||||||
></van-index-anchor>
|
|
||||||
<van-cell
|
|
||||||
v-for="country in countries"
|
|
||||||
:key="country.code"
|
|
||||||
:title="country.displayName"
|
|
||||||
@click="handleCountrySelect(country)"
|
|
||||||
clickable
|
|
||||||
>
|
|
||||||
<div class="pr-[25px]"> +{{ country.zone }}</div>
|
|
||||||
</van-cell>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</van-index-bar>
|
|
||||||
|
|
||||||
<div v-else>
|
|
||||||
<div class="mb-4">
|
|
||||||
<div class="px-4 py-2 text-gray-600">{{ t('countryRegion.frequentCountry') }}</div>
|
|
||||||
<van-cell
|
|
||||||
v-for="country in searchCountry['#']"
|
|
||||||
:key="country.code"
|
|
||||||
:title="country.displayName"
|
|
||||||
@click="handleCountrySelect(country)"
|
|
||||||
clickable
|
|
||||||
>
|
|
||||||
<div class="pr-[25px]"> +{{ country.zone }}</div>
|
|
||||||
</van-cell>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<van-cell
|
|
||||||
v-for="country in Object.values(searchCountry).flat().filter(c => !frequentCountryCodes.includes(c.code))"
|
|
||||||
:key="country.code"
|
|
||||||
:title="country.displayName"
|
|
||||||
@click="handleCountrySelect(country)"
|
|
||||||
clickable
|
|
||||||
>
|
|
||||||
<div class="pr-[25px]"> +{{ country.zone }}</div>
|
|
||||||
</van-cell>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<van-back-top v-if="showIndexBar" right="15vw" bottom="10vh"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,22 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import CheckoutPage from '@/components/stripe/CheckoutPage.vue'
|
|
||||||
import CompletePage from '@/components/stripe/CompletePage.vue'
|
|
||||||
definePageMeta({
|
|
||||||
layout: 'default',
|
|
||||||
title: 'Stripe支付'
|
|
||||||
})
|
|
||||||
const route = useRoute()
|
|
||||||
const key=route.query.key??''
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<CheckoutPage/>
|
|
||||||
<!-- <iframe class="w-100vw h-100vh" :src="`/stripe/checkout.html?key=${key}`"></iframe> -->
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<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>
|
<script setup>
|
||||||
import Home from './home/index.vue'
|
import CollectCodePayment from "./collectCode/payment/index.vue";
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: "default",
|
||||||
i18n: 'menu.home',
|
i18n: "menu.payment",
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Home/>
|
<CollectCodePayment />
|
||||||
</template>
|
</template>
|
@ -1,67 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {liveStore} from "@/stores/live/index.js";
|
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
|
||||||
import {useI18n} from 'vue-i18n'
|
|
||||||
const {auctionData} = liveStore()
|
|
||||||
const {userInfo}= authStore()
|
|
||||||
function formatThousands(num) {
|
|
||||||
|
|
||||||
return Number(num).toLocaleString();
|
|
||||||
}
|
|
||||||
const headList=[
|
|
||||||
{
|
|
||||||
label:useI18n().t('live_room.head'),
|
|
||||||
color:'#D03050',
|
|
||||||
value:'head'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:useI18n().t('live_room.out'),
|
|
||||||
color:'#939393',
|
|
||||||
value:'out'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label:useI18n().t('live_room.success'),
|
|
||||||
color:'#34B633',
|
|
||||||
value:'success'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const headItem=(statusCode)=>{
|
|
||||||
return headList.find(x=>x.value===statusCode)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
id="list-container"
|
|
||||||
class="w-344px h-86px overflow-y-auto bg-#fff rounded-4px text-14px text-#939393 pt-7px pb-7px px-11px flex flex-col justify-between"
|
|
||||||
>
|
|
||||||
<transition-group name="list" tag="div">
|
|
||||||
<template v-if="auctionData.wsType==='stopArtwork'">
|
|
||||||
<div class="text-#939393 text-14px">{{ $t('live_room.next_lot') }}</div>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="auctionData.auctionPriceList?.buys?.length>0">
|
|
||||||
<div v-for="(item, index) in auctionData.auctionPriceList?.buys" :key="index" class="flex flex-shrink-0">
|
|
||||||
<div class="text-start shrink-0 w-60px" :style="`color: ${headItem(item.statusCode).color}`" >{{ headItem(item.statusCode).label }}</div>
|
|
||||||
<div class="text-start shrink-0 w-80px">{{ item.auctionType==='local'? $t('live_room.spot'):$t('live_room.network') }}</div>
|
|
||||||
<div class="text-start shrink-0 w-80px">{{ item.createdAt }}</div>
|
|
||||||
<div class="text-start shrink-0 w-80px">{{item.baseCurrency}}{{ formatThousands(item.baseMoney) }}</div>
|
|
||||||
<div class="text-start text-#2B53AC shrink-0 w-20px">{{ item.userId===userInfo.ID?$t('live_room.me'):'' }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-if="auctionData.wsType==='newArtwork'">
|
|
||||||
<div class="text-#939393 text-14px">{{ $t('live_room.start') }}</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</transition-group>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.list-enter-active, .list-leave-active {
|
|
||||||
transition: all 0.5s ease;
|
|
||||||
}
|
|
||||||
.list-enter-from, .list-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20px);
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,89 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {liveStore} from "~/stores/live/index.js";
|
|
||||||
import { showMinWindow, hideMinWindow } from '@/components/liveMinWindow/createMinWindow.js'
|
|
||||||
const {lastSnapshot,fullLive} = liveStore()
|
|
||||||
const props = defineProps({
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
price: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const router = useRouter()
|
|
||||||
const emit = defineEmits(['update:show'])
|
|
||||||
const payStatus=ref(0)
|
|
||||||
const changePayStatus=()=>{
|
|
||||||
payStatus.value=payStatus.value===0?1:0
|
|
||||||
}
|
|
||||||
const close=()=>{
|
|
||||||
emit('update:show',false)
|
|
||||||
}
|
|
||||||
const confirm=()=>{
|
|
||||||
router.push('/signature/protocol')
|
|
||||||
handleCapture()
|
|
||||||
emit('update:show',false)
|
|
||||||
}
|
|
||||||
const captureVideoFrame = () => {
|
|
||||||
try {
|
|
||||||
const video = document.querySelector('#J_prismPlayer video')
|
|
||||||
if (!video) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = document.createElement('canvas')
|
|
||||||
canvas.width = video.videoWidth
|
|
||||||
canvas.height = video.videoHeight
|
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d')
|
|
||||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
|
|
||||||
return canvas.toDataURL('image/jpeg', 0.9)
|
|
||||||
} catch (error) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handleCapture = () => {
|
|
||||||
const imageUrl = captureVideoFrame()
|
|
||||||
if (imageUrl) {
|
|
||||||
lastSnapshot.value=imageUrl
|
|
||||||
showMinWindow(lastSnapshot.value,{
|
|
||||||
onClick:()=>{
|
|
||||||
router.replace('/')
|
|
||||||
fullLive.value=true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<van-dialog :show="show" show-cancel-button @cancel="close" @confirm="confirm">
|
|
||||||
<div class="flex flex-col pt-18px pb-13px justify-between items-center h-144px">
|
|
||||||
<template v-if="payStatus===0">
|
|
||||||
<div class="text-#000 text-16px font-600 ">{{ $t('live_room.all_pay') }}</div>
|
|
||||||
<div class="text-#000 text-16px ">RMB 5,000</div>
|
|
||||||
</template>
|
|
||||||
<template v-if="payStatus===1">
|
|
||||||
<div class="text-#000 text-16px font-600 ">{{ $t('live_room.part_pay') }}</div>
|
|
||||||
<input class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" placeholder="最多RMB5,000">
|
|
||||||
</template>
|
|
||||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===0 ? $t('live_room.part_pay') : $t('live_room.all_pay')}}</div>
|
|
||||||
</div>
|
|
||||||
</van-dialog>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
:deep(.van-hairline--top.van-dialog__footer){
|
|
||||||
&>.van-button{
|
|
||||||
border-top: 1px solid #E7E7E7;
|
|
||||||
&.van-dialog__cancel{
|
|
||||||
border-right: 1px solid #E7E7E7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,42 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import successImg from '@/static/images/zu5554@2x.png'
|
|
||||||
import errorImg from '@/static/images/zu5561@2x.png'
|
|
||||||
const props = defineProps({
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: 'success'
|
|
||||||
},
|
|
||||||
price: {
|
|
||||||
type: Number,
|
|
||||||
default: 1000
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const emit = defineEmits(['cancel','update:show'])
|
|
||||||
const cancel= () => {
|
|
||||||
emit('update:show', false)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<van-dialog style="overflow: visible" :show="show" show-cancel-button :show-confirm-button="false" :cancelButtonText="$t('login.back')" cancelButtonColor="#2B53AC" @cancel="cancel">
|
|
||||||
<div class="h-145px relative flex justify-center">
|
|
||||||
<img :src="type==='success' ? successImg : errorImg" class="w-119px h-120px absolute top--74px z-9999 left-1/2 transform translate-x--1/2" alt="">
|
|
||||||
<div class="mt-94px text-#A9A9A9 text-16px">{{price}}</div>
|
|
||||||
</div>
|
|
||||||
</van-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
:deep(.van-hairline--top.van-dialog__footer){
|
|
||||||
border-top: 1px solid #E7E7E7;
|
|
||||||
border-bottom-left-radius:8px ;
|
|
||||||
border-bottom-right-radius:8px ;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,259 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref, computed, onMounted, onBeforeUnmount } from "vue"
|
|
||||||
import lockClosed from "@/static/images/lockdfd@2x.png"
|
|
||||||
import lockOpen from "@/static/images/lock4@2x.png"
|
|
||||||
import { liveStore } from "@/stores/live/index.js"
|
|
||||||
import xButton from '@/components/x-button/index.vue'
|
|
||||||
import tangPopup from './tangPopup.vue'
|
|
||||||
import { goodStore } from "@/stores/goods/index.js"
|
|
||||||
import { authStore } from "~/stores/auth/index.js"
|
|
||||||
import {showMinWindow} from "~/components/liveMinWindow/createMinWindow.js";
|
|
||||||
import {hideMinWindow1, showMinWindow1} from "~/components/floatingBubble/floating.js";
|
|
||||||
|
|
||||||
const { quoteStatus, changeStatus, show, auctionData, getSocketData ,lastSnapshot,fullLive} = liveStore()
|
|
||||||
const { pageRef } = goodStore()
|
|
||||||
const { userInfo ,payment} = authStore()
|
|
||||||
const showTang = ref(false)
|
|
||||||
const router = useRouter()
|
|
||||||
// 拖动相关状态
|
|
||||||
const isDragging = ref(false)
|
|
||||||
const startX = ref(0)
|
|
||||||
const startY = ref(0)
|
|
||||||
const currentTop = ref(196)
|
|
||||||
const currentLeft = ref(window.innerWidth - 60)
|
|
||||||
const sidebarRef = ref(null)
|
|
||||||
|
|
||||||
// 限制拖动范围
|
|
||||||
const minTop = 0
|
|
||||||
const maxTop = window.innerHeight - 180
|
|
||||||
const minLeft = 0
|
|
||||||
const maxLeft = window.innerWidth - 60
|
|
||||||
|
|
||||||
// 吸附相关
|
|
||||||
const snapThreshold = 30
|
|
||||||
const snapPosition = () => {
|
|
||||||
const centerX = currentLeft.value + 30
|
|
||||||
if (centerX < window.innerWidth / 2) {
|
|
||||||
currentLeft.value = 0
|
|
||||||
} else {
|
|
||||||
currentLeft.value = window.innerWidth - 60
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始拖动
|
|
||||||
const handleMouseDown = (e) => {
|
|
||||||
isDragging.value = true
|
|
||||||
startX.value = e.clientX - currentLeft.value
|
|
||||||
startY.value = e.clientY - currentTop.value
|
|
||||||
document.addEventListener('mousemove', handleMouseMove)
|
|
||||||
document.addEventListener('mouseup', handleMouseUp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拖动中
|
|
||||||
const handleMouseMove = (e) => {
|
|
||||||
if (!isDragging.value) return
|
|
||||||
|
|
||||||
let newTop = e.clientY - startY.value
|
|
||||||
let newLeft = e.clientX - startX.value
|
|
||||||
|
|
||||||
// 限制范围
|
|
||||||
newTop = Math.max(minTop, Math.min(newTop, maxTop))
|
|
||||||
newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft))
|
|
||||||
|
|
||||||
currentTop.value = newTop
|
|
||||||
currentLeft.value = newLeft
|
|
||||||
|
|
||||||
// 更新位置
|
|
||||||
if (sidebarRef.value) {
|
|
||||||
sidebarRef.value.style.top = `${newTop}px`
|
|
||||||
sidebarRef.value.style.left = `${newLeft}px`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 结束拖动
|
|
||||||
const handleMouseUp = () => {
|
|
||||||
isDragging.value = false
|
|
||||||
snapPosition()
|
|
||||||
if (sidebarRef.value) {
|
|
||||||
sidebarRef.value.style.left = `${currentLeft.value}px`
|
|
||||||
}
|
|
||||||
document.removeEventListener('mousemove', handleMouseMove)
|
|
||||||
document.removeEventListener('mouseup', handleMouseUp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触摸事件处理
|
|
||||||
const handleTouchStart = (e) => {
|
|
||||||
isDragging.value = true
|
|
||||||
startX.value = e.touches[0].clientX - currentLeft.value
|
|
||||||
startY.value = e.touches[0].clientY - currentTop.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTouchMove = (e) => {
|
|
||||||
if (!isDragging.value) return
|
|
||||||
|
|
||||||
let newTop = e.touches[0].clientY - startY.value
|
|
||||||
let newLeft = e.touches[0].clientX - startX.value
|
|
||||||
|
|
||||||
newTop = Math.max(minTop, Math.min(newTop, maxTop))
|
|
||||||
newLeft = Math.max(minLeft, Math.min(newLeft, maxLeft))
|
|
||||||
|
|
||||||
currentTop.value = newTop
|
|
||||||
currentLeft.value = newLeft
|
|
||||||
|
|
||||||
if (sidebarRef.value) {
|
|
||||||
sidebarRef.value.style.top = `${newTop}px`
|
|
||||||
sidebarRef.value.style.left = `${newLeft}px`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTouchEnd = () => {
|
|
||||||
isDragging.value = false
|
|
||||||
snapPosition()
|
|
||||||
if (sidebarRef.value) {
|
|
||||||
sidebarRef.value.style.left = `${currentLeft.value}px`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const captureVideoFrame = () => {
|
|
||||||
try {
|
|
||||||
const video = document.querySelector('#J_prismPlayer video')
|
|
||||||
if (!video) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = document.createElement('canvas')
|
|
||||||
canvas.width = video.videoWidth
|
|
||||||
canvas.height = video.videoHeight
|
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d')
|
|
||||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
|
|
||||||
return canvas.toDataURL('image/jpeg', 0.9)
|
|
||||||
} catch (error) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCapture = () => {
|
|
||||||
/* const imageUrl = captureVideoFrame()
|
|
||||||
if (imageUrl) {
|
|
||||||
lastSnapshot.value=imageUrl
|
|
||||||
|
|
||||||
/!* showMinWindow(lastSnapshot.value,{
|
|
||||||
onClick:()=>{
|
|
||||||
router.replace('/')
|
|
||||||
fullLive.value=true
|
|
||||||
}
|
|
||||||
})*!/
|
|
||||||
}*/
|
|
||||||
showMinWindow1({
|
|
||||||
onClick:()=>{
|
|
||||||
router.replace('/')
|
|
||||||
fullLive.value=true
|
|
||||||
hideMinWindow1()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 组件挂载时添加事件监听
|
|
||||||
onMounted(() => {
|
|
||||||
if (sidebarRef.value) {
|
|
||||||
sidebarRef.value.style.top = `${currentTop.value}px`
|
|
||||||
sidebarRef.value.style.left = `${currentLeft.value}px`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 组件卸载时清理事件监听
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
document.removeEventListener('mousemove', handleMouseMove)
|
|
||||||
document.removeEventListener('mouseup', handleMouseUp)
|
|
||||||
})
|
|
||||||
|
|
||||||
const openOne = () => {
|
|
||||||
showTang.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const paySide = computed(() => {
|
|
||||||
//当前是否已成交
|
|
||||||
return auctionData.value.needPayBuys?.length>0
|
|
||||||
})
|
|
||||||
|
|
||||||
const goPay = () => {
|
|
||||||
payment.value.leftCurrency=auctionData.value.needPayBuys?.[0]?.leftCurrency
|
|
||||||
payment.value.leftPrice=auctionData.value.needPayBuys?.[0]?.leftPrice
|
|
||||||
payment.value.buyUid=auctionData.value.needPayBuys?.[0]?.uuid
|
|
||||||
payment.value.auctionArtworkUuid=auctionData.value.needPayBuys?.[0]?.auctionArtworkUuid
|
|
||||||
handleCapture()
|
|
||||||
router.push('/signature/protocol')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
ref="sidebarRef"
|
|
||||||
class="bg-white w-60px rounded-4px overflow-hidden absolute z-999 cursor-move"
|
|
||||||
@mousedown="handleMouseDown"
|
|
||||||
@touchstart="handleTouchStart"
|
|
||||||
@touchmove="handleTouchMove"
|
|
||||||
@touchend="handleTouchEnd"
|
|
||||||
>
|
|
||||||
<!-- 拍品信息 -->
|
|
||||||
<van-button
|
|
||||||
class="w-60px !h-60px"
|
|
||||||
@click.stop="openOne"
|
|
||||||
style="border: none;border-radius: 0"
|
|
||||||
>
|
|
||||||
<div class="text-center flex flex-col justify-center items-center text-#7D7D7F text-12px">
|
|
||||||
<div>{{ $t('live_room.lots') }}</div>
|
|
||||||
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
|
||||||
</div>
|
|
||||||
</van-button>
|
|
||||||
|
|
||||||
<tangPopup v-model:show="showTang"></tangPopup>
|
|
||||||
|
|
||||||
<!-- 出价开关 -->
|
|
||||||
<van-button
|
|
||||||
class="w-60px !h-60px"
|
|
||||||
@click.stop="changeStatus"
|
|
||||||
style="border-right: none;border-left: none;border-radius: 0;padding: 0"
|
|
||||||
>
|
|
||||||
<div class="text-center flex flex-col justify-center items-center">
|
|
||||||
<div class="mb-4px">
|
|
||||||
<img
|
|
||||||
:src="quoteStatus ? lockClosed : lockOpen"
|
|
||||||
class="w-16px h-21px"
|
|
||||||
alt="锁图标"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
:class="quoteStatus ? 'text-gray-500' : 'text-blue-600'"
|
|
||||||
class="text-10px transition-colors duration-200"
|
|
||||||
>
|
|
||||||
{{ quoteStatus ? $t('live_room.colse_bid') : $t('live_room.start_bid') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-button>
|
|
||||||
|
|
||||||
<!-- 支付 -->
|
|
||||||
<van-button
|
|
||||||
v-if="paySide"
|
|
||||||
class="w-60px !h-60px"
|
|
||||||
style="border: none;border-radius: 0"
|
|
||||||
@click.stop="goPay"
|
|
||||||
>
|
|
||||||
<div class="text-center flex flex-col justify-center items-center text-yellow-600">
|
|
||||||
<div class="text-10px">{{auctionData.needPayBuys?.[0]?.leftCurrency}}</div>
|
|
||||||
<div class="text-12px">{{auctionData.needPayBuys?.[0]?.leftPrice}}</div>
|
|
||||||
<div class="text-10px">{{ $t('art_detail_page.button') }}</div>
|
|
||||||
</div>
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.cursor-move {
|
|
||||||
cursor: move;
|
|
||||||
user-select: none;
|
|
||||||
touch-action: none;
|
|
||||||
transition: left 0.3s ease;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,154 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import xPopup from '@/components/x-popup/index.vue'
|
|
||||||
import {goodStore} from "@/stores/goods/index.js";
|
|
||||||
import xImage from '@/components/x-image/index.vue'
|
|
||||||
import DetailPopup from '@/pages/home/components/DetailPopup/index.vue'
|
|
||||||
import {liveStore} from "~/stores/live/index.js";
|
|
||||||
import {ref} from "vue";
|
|
||||||
const {pageRef,itemList,getArtworkList, loading: storeLoading,} = goodStore();
|
|
||||||
const {auctionData} = liveStore()
|
|
||||||
const showDetail=ref(false)
|
|
||||||
const localState = ref({
|
|
||||||
finished: false,
|
|
||||||
refreshing: false,
|
|
||||||
showDetail: false,
|
|
||||||
showHeight: ''
|
|
||||||
})
|
|
||||||
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 props = defineProps({
|
|
||||||
show: Boolean,
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const scrollToCurrentItem = () => {
|
|
||||||
if (!itemList.value?.length) return
|
|
||||||
const currentIndex = itemList.value.findIndex(
|
|
||||||
item => auctionData.value.artwork.index === item?.index
|
|
||||||
)
|
|
||||||
if (currentIndex > -1) {
|
|
||||||
const container = document.querySelector('.list-container')
|
|
||||||
const targetElement = document.querySelectorAll('.item-wrapper')[currentIndex]
|
|
||||||
if (targetElement && container) {
|
|
||||||
const containerTop = container.getBoundingClientRect().top
|
|
||||||
const elementTop = targetElement.getBoundingClientRect().top
|
|
||||||
const scrollTop = elementTop - containerTop + container.scrollTop
|
|
||||||
container.scrollTo({
|
|
||||||
top: scrollTop,
|
|
||||||
behavior: 'smooth'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const emit = defineEmits(['update:show'])
|
|
||||||
const showDetailInfo=ref(null)
|
|
||||||
const close = () => emit('update:show', false);
|
|
||||||
const openShow=(item)=>{
|
|
||||||
showDetailInfo.value=item
|
|
||||||
showDetail.value=true
|
|
||||||
|
|
||||||
}
|
|
||||||
const loadMore = async () => {
|
|
||||||
pageRef.value.page++
|
|
||||||
const { finished } = await getArtworkList()
|
|
||||||
localState.value.finished = finished
|
|
||||||
}
|
|
||||||
watch(()=>{
|
|
||||||
return auctionData.value?.artwork?.index
|
|
||||||
},(newValue)=>{
|
|
||||||
})
|
|
||||||
watch(()=>props.show,(newValue)=>{
|
|
||||||
if (newValue){
|
|
||||||
nextTick(()=>{
|
|
||||||
scrollToCurrentItem()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<x-popup :show="show" @update:show="close">
|
|
||||||
<template #title>
|
|
||||||
<div class="text-#000 text-16px">{{ $t('home.tab1')}}</div>
|
|
||||||
<div class="text-#939393 text-16px ml-14px">{{ $t('live_room.total') }}{{ pageRef.itemCount }}{{ $t('live_room.lots_num') }}</div>
|
|
||||||
</template>
|
|
||||||
<div>
|
|
||||||
<van-pull-refresh
|
|
||||||
v-model="localState.refreshing"
|
|
||||||
:success-text="$t('home.refresh_show')"
|
|
||||||
: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
|
|
||||||
v-for="(item,index) of itemList"
|
|
||||||
:key="item.uuid"
|
|
||||||
class="flex mb-21px item-wrapper"
|
|
||||||
@click="openShow(item)"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="mr-10px flex-shrink-0 rounded-4px overflow-hidden cursor-pointer relative"
|
|
||||||
>
|
|
||||||
<xImage
|
|
||||||
:preview="false"
|
|
||||||
class="w-80px h-80px"
|
|
||||||
:src="item.artwork?.hdPic"
|
|
||||||
:alt="item?.artworkTitle"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
<div class="w-45px h-17px bg-#2B53AC text-12px line-height-none flex justify-center items-center absolute top-2px left-2px text-#fff">LOT{{item.index}}</div>
|
|
||||||
<div v-show="auctionData?.artwork?.index===item?.index" class="w-80px h-20px bg-#B58047 flex line-height-none justify-center items-center text-#fff text-12px bottom-0 absolute blink">{{ $t('live_room.cast') }}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
|
||||||
{{ item.artworkTitle }}
|
|
||||||
</div>
|
|
||||||
<div class="text-14px text-#575757">{{ $t('home.start_price') }}:{{item?.startPriceCurrency}} {{item?.startPrice}}</div>
|
|
||||||
<div class="text-14px text-#B58047" v-if="item.soldPrice">{{ $t('home.close_price') }}:{{item.soldPrice}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-list>
|
|
||||||
</van-pull-refresh>
|
|
||||||
</div>
|
|
||||||
</x-popup>
|
|
||||||
<DetailPopup v-model:show="showDetail" :detail-info="showDetailInfo"></DetailPopup>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.ellipsis {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
.blink {
|
|
||||||
animation: fade 1s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade {
|
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.5; }
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,218 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {ref, onMounted, onBeforeUnmount, watch} from 'vue'
|
|
||||||
import AliyunPlayer from 'aliyun-aliplayer'
|
|
||||||
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
|
|
||||||
import sideButton from '@/pages/liveRoom/components/SideButton/index.vue'
|
|
||||||
import broadcast from '@/pages/liveRoom/components/Broadcast/index.vue'
|
|
||||||
import {liveStore} from "@/stores/live/index.js"
|
|
||||||
import liveLoading from '@/components/liveLoading/index.vue'
|
|
||||||
import paymentResults from '@/pages/liveRoom/components/PaymentResults/index.vue'
|
|
||||||
import paymentInput from '@/pages/liveRoom/components/PaymentInput/index.vue'
|
|
||||||
import {goodStore} from "@/stores/goods/index.js"
|
|
||||||
import {message} from "~/components/x-message/useMessage.js"
|
|
||||||
import {showConfirmDialog} from 'vant';
|
|
||||||
import {artworkBuy} from "@/api/goods/index.js"
|
|
||||||
import {useI18n} from 'vue-i18n'
|
|
||||||
const { t } = useI18n()
|
|
||||||
const { auctionDetail,getAuctionDetail} = goodStore();
|
|
||||||
const player = ref(null)
|
|
||||||
const {quoteStatus, show, playerId, show1, auctionData, getSocketData, getLiveLink, fullLive} = liveStore()
|
|
||||||
const pullLink = ref('')
|
|
||||||
const handlePlayerError = (error) => {
|
|
||||||
showConfirmDialog({
|
|
||||||
message: t('live_room.error_mess'),
|
|
||||||
showCancelButton: true
|
|
||||||
}).then(() => {
|
|
||||||
initializePlayer()
|
|
||||||
}).catch(() => {
|
|
||||||
})
|
|
||||||
// player.value?.play()
|
|
||||||
}
|
|
||||||
const loading1=ref(false)
|
|
||||||
const initializePlayer = async () => {
|
|
||||||
try {
|
|
||||||
if (player.value) {
|
|
||||||
player.value.dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否是微信浏览器
|
|
||||||
const isWechat = /MicroMessenger/i.test(navigator.userAgent)
|
|
||||||
|
|
||||||
const playerConfig = {
|
|
||||||
id: playerId.value,
|
|
||||||
source: pullLink.value,
|
|
||||||
isLive: true,
|
|
||||||
preload: true,
|
|
||||||
autoplay: true, // 改为 true
|
|
||||||
muted: true, // 默认静音
|
|
||||||
diagnosisButtonVisible:false,
|
|
||||||
// vodRetry:10,
|
|
||||||
// liveRetry:10,
|
|
||||||
autoplayPolicy: {
|
|
||||||
fallbackToMute: true
|
|
||||||
},
|
|
||||||
width: '100%', //容器的大小
|
|
||||||
height: '100%', //容器的大小
|
|
||||||
skinLayout: false,
|
|
||||||
controlBarVisibility: 'never',
|
|
||||||
license: {
|
|
||||||
domain: "szjixun.cn",
|
|
||||||
key: "OProxmWaOZ2XVHXLtf4030126521c43429403194970aa8af9"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player.value = new AliyunPlayer(playerConfig, (playerInstance) => {
|
|
||||||
// 在微信环境下,需要用户手动触发播放
|
|
||||||
if (isWechat) {
|
|
||||||
const startPlay = () => {
|
|
||||||
playerInstance?.play()
|
|
||||||
document.removeEventListener('WeixinJSBridgeReady', startPlay)
|
|
||||||
document.removeEventListener('touchstart', startPlay)
|
|
||||||
}
|
|
||||||
document.addEventListener('WeixinJSBridgeReady', startPlay)
|
|
||||||
document.addEventListener('touchstart', startPlay)
|
|
||||||
}
|
|
||||||
loading1.value = true
|
|
||||||
playerInstance?.play()
|
|
||||||
})
|
|
||||||
player.value.on('playing', () => {
|
|
||||||
loading1.value = false
|
|
||||||
|
|
||||||
})
|
|
||||||
player.value.on('loading', () => {
|
|
||||||
})
|
|
||||||
player.value.on('error', handlePlayerError)
|
|
||||||
} catch (error) {
|
|
||||||
showConfirmDialog({
|
|
||||||
message: t('live_room.error_mess'),
|
|
||||||
showCancelButton: true
|
|
||||||
}).then(() => {
|
|
||||||
initializePlayer()
|
|
||||||
}).catch(() => {
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
await getAuctionDetail()
|
|
||||||
pullLink.value = await getLiveLink()
|
|
||||||
if (auctionDetail.value.isLiving===1){
|
|
||||||
initializePlayer()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
player.value?.dispose()
|
|
||||||
player.value = null
|
|
||||||
})
|
|
||||||
watch(() => fullLive.value, async (newVal) => {
|
|
||||||
if (!newVal) return
|
|
||||||
|
|
||||||
await getSocketData()
|
|
||||||
|
|
||||||
})
|
|
||||||
const goBuy = async () => {
|
|
||||||
const res = await artworkBuy({
|
|
||||||
auctionArtworkUuid: auctionData.value?.artwork?.uuid,
|
|
||||||
buyMoney: String(auctionData?.value.nowAuctionPrice?.nowPrice??0)
|
|
||||||
})
|
|
||||||
if (res.status === 0) {
|
|
||||||
message.success(t('live_room.success_mess'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tipOpen = () => {
|
|
||||||
message.warning(t('live_room.warn_mess'))
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="relative h-full">
|
|
||||||
<div :id="playerId" class="w-full h-full"></div>
|
|
||||||
<div v-if="loading1" class="absolute left-1/2 transform translate-x--1/2 top-1/2 translate-y--1/2">
|
|
||||||
<van-loading type="spinner" >直播加载中...</van-loading>
|
|
||||||
</div>
|
|
||||||
<transition name="fade">
|
|
||||||
<div v-if="fullLive">
|
|
||||||
<sideButton class="absolute top-196px right-0 z-999"></sideButton>
|
|
||||||
<div class="absolute left-1/2 transform -translate-x-1/2 flex flex-col items-center"
|
|
||||||
style="bottom:calc(var(--safe-area-inset-bottom) + 26px)">
|
|
||||||
<div class="text-16px text-#FFB25F font-600 flex">
|
|
||||||
<div class="mr-5px">{{ t('live_room.now_price') }}:{{ auctionData?.nowAuctionPrice?.currency }}</div>
|
|
||||||
<div class="min-w-50px">{{auctionData?.nowAuctionPrice?.nowPrice}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-16px text-#fff font-600 flex">
|
|
||||||
<div class="mr-5px">{{ t('live_room.lower_price') }}:{{ auctionData?.nowAuctionPrice?.currency }}</div>
|
|
||||||
<div class="min-w-50px">{{auctionData?.nowAuctionPrice?.nextPrice}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="quoteStatus&&auctionData?.nowAuctionPrice?.nowPrice&&auctionData?.nowAuctionPrice?.nowPrice!=='0'" class="mt-10px mb-10px">
|
|
||||||
<van-button @click.stop="goBuy" color="#FFB25F" class="w-344px !h-[40px]">
|
|
||||||
<div>{{
|
|
||||||
`${t('live_room.confirm')} ${auctionData?.nowAuctionPrice?.currency} ${auctionData?.nowAuctionPrice?.nowPrice ?? 0}`
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
<div v-else class="mt-10px mb-10px">
|
|
||||||
<van-button @click="tipOpen" color="#D6D6D8" class="w-344px !h-[40px]" >
|
|
||||||
<div class="text-#7D7D7F text-14px">{{ t('live_room.button') }}</div>
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<broadcast></broadcast>
|
|
||||||
</div>
|
|
||||||
<paymentInput v-model:show="show"/>
|
|
||||||
<div>
|
|
||||||
</div>
|
|
||||||
<paymentResults v-model:show="show1" type="error"/>
|
|
||||||
<div v-if="auctionData?.wsType==='newArtwork'"
|
|
||||||
class="w-344px h-31px rounded-4px absolute top-9px bg-[#151824]/45 backdrop-blur-[10px] backdrop-saturate-[180%] left-1/2 transform translate-x--1/2 flex text-#fff text-14px items-center px-12px line-height-none">
|
|
||||||
<div class="mr-11px whitespace-nowrap">LOT{{ auctionData.artwork.index }}</div>
|
|
||||||
<div class="mr-10px truncate">{{ auctionData.artwork.name }}</div>
|
|
||||||
<div class="whitespace-nowrap">{{ t('live_room.start') }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
/* 定义过渡动画 */
|
|
||||||
.fade-enter-active {
|
|
||||||
transition: opacity 1s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-leave-active {
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 定义进入和离开的状态 */
|
|
||||||
.fade-enter-from,
|
|
||||||
.fade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-enter-to,
|
|
||||||
.fade-leave-from {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-rolling-text {
|
|
||||||
--van-rolling-text-item-width: 10px;
|
|
||||||
--van-rolling-text-font-size: 16px;
|
|
||||||
--van-rolling-text-color: #FFB25F;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-rolling-text1 {
|
|
||||||
--van-rolling-text-item-width: 10px;
|
|
||||||
--van-rolling-text-font-size: 16px;
|
|
||||||
--van-rolling-text-color: #FFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.prism-license-watermark) {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,248 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
import countryCode from '../countryRegion/data/index.js'
|
|
||||||
import {senCode, userLogin} from "@/api/auth/index.js";
|
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
|
||||||
import {message} from '@/components/x-message/useMessage.js'
|
|
||||||
import {fddCheck} from "~/api/goods/index.js";
|
|
||||||
const {userInfo,token,selectedZone}= authStore()
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const { locale } = useI18n()
|
|
||||||
definePageMeta({
|
|
||||||
keepalive: true,
|
|
||||||
i18n: 'login.title'
|
|
||||||
})
|
|
||||||
const loadingRef=ref({
|
|
||||||
loading1:false,
|
|
||||||
loading2:false,
|
|
||||||
})
|
|
||||||
const isExist=ref(false)//帐号是否存在 true存在
|
|
||||||
const isReal=ref(false) //isReal 是否实名过
|
|
||||||
const codeInput=ref(null)
|
|
||||||
function goToPage() {
|
|
||||||
router.push('/countryRegion');
|
|
||||||
}
|
|
||||||
const interval=ref(null)
|
|
||||||
const startCountdown=()=> {
|
|
||||||
if (interval.value){
|
|
||||||
clearInterval(interval.value);
|
|
||||||
}
|
|
||||||
countdown.value = 60;
|
|
||||||
interval.value = setInterval(() => {
|
|
||||||
if (countdown.value > 0) {
|
|
||||||
countdown.value--;
|
|
||||||
} else {
|
|
||||||
clearInterval(interval.value);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
const countdown = ref(0);
|
|
||||||
const phoneNum = ref('')
|
|
||||||
const code = ref('')
|
|
||||||
const pane = ref(0)
|
|
||||||
// 根据语言获取默认国家
|
|
||||||
const getDefaultCountry = () => {
|
|
||||||
let defaultCode = 'CN' // 默认中国大陆
|
|
||||||
switch (locale.value) {
|
|
||||||
case 'zh-CN':
|
|
||||||
defaultCode = 'CN'
|
|
||||||
break
|
|
||||||
case 'zh-TW':
|
|
||||||
defaultCode = 'TW'
|
|
||||||
break
|
|
||||||
case 'ja-JP':
|
|
||||||
defaultCode = 'JP'
|
|
||||||
break
|
|
||||||
case 'en-US':
|
|
||||||
defaultCode = 'US'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
const country = countryCode.find(c => c.code === defaultCode)
|
|
||||||
return {
|
|
||||||
zone: country.zone,
|
|
||||||
name: locale.value === 'zh-CN' ? country.cn :
|
|
||||||
locale.value === 'zh-TW' ? country.tw :
|
|
||||||
locale.value === 'ja-JP' ? country.ja :
|
|
||||||
country.en
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultCountry = getDefaultCountry()
|
|
||||||
|
|
||||||
|
|
||||||
const selectedCountry = ref(route.query.countryName || defaultCountry.name)
|
|
||||||
onMounted(()=>{
|
|
||||||
selectedZone.value=route.query.zone || defaultCountry.zone
|
|
||||||
})
|
|
||||||
// 监听语言变化,更新默认国家
|
|
||||||
watch(locale, () => {
|
|
||||||
if (!route.query.zone) {
|
|
||||||
const newDefault = getDefaultCountry()
|
|
||||||
selectedZone.value = newDefault.zone
|
|
||||||
selectedCountry.value = newDefault.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const vanSwipeRef=ref(null)
|
|
||||||
const getCode =async () => {
|
|
||||||
loadingRef.value.loading1=true
|
|
||||||
const res=await senCode({
|
|
||||||
telNum:phoneNum.value,
|
|
||||||
zone:selectedZone.value
|
|
||||||
})
|
|
||||||
loadingRef.value.loading1=false
|
|
||||||
if (res.status===0){
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
pane.value = 1
|
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
|
||||||
|
|
||||||
startCountdown();
|
|
||||||
}
|
|
||||||
const goBack = () => {
|
|
||||||
code.value = ''
|
|
||||||
pane.value = 0
|
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
|
||||||
}
|
|
||||||
const goLogin =async () => {
|
|
||||||
loadingRef.value.loading2=true
|
|
||||||
const res=await userLogin({
|
|
||||||
telNum:phoneNum.value,
|
|
||||||
zone:selectedZone.value,
|
|
||||||
code:code.value
|
|
||||||
})
|
|
||||||
if (res.status===0){
|
|
||||||
userInfo.value=res.data.accountInfo
|
|
||||||
token.value=res.data.token
|
|
||||||
|
|
||||||
if (res.data?.accountInfo?.userExtend?.isReal===0){
|
|
||||||
await router.push({
|
|
||||||
path: '/realAuth',
|
|
||||||
query:{
|
|
||||||
statusCode:0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else if (res.data.isJumpFdd){
|
|
||||||
const res1=await fddCheck()
|
|
||||||
if (res1.status===0){
|
|
||||||
window.location.href=res1.data.h5Url
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
await router.push('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadingRef.value.loading2=false
|
|
||||||
}
|
|
||||||
const isKeyboardVisible = ref(false)
|
|
||||||
const windowHeight = ref(window.innerHeight)
|
|
||||||
const isFocused = ref(false)
|
|
||||||
onMounted(() => {
|
|
||||||
// 记录初始窗口高度
|
|
||||||
windowHeight.value = window.innerHeight
|
|
||||||
|
|
||||||
// 监听窗口大小变化
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
// 如果当前高度明显小于初始高度,认为键盘已打开
|
|
||||||
isKeyboardVisible.value = window.innerHeight < windowHeight.value * 0.8
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.removeEventListener('resize', () => {})
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-bottom bg-cover grow-1 px-[31px] pt-[86px]">
|
|
||||||
<div class="w-full flex justify-center mb-[100px]">
|
|
||||||
<img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt="">
|
|
||||||
</div>
|
|
||||||
<van-swipe ref="vanSwipeRef" :show-indicators="false" :touchable="false" :lazy-render="true" :loop="false">
|
|
||||||
<van-swipe-item >
|
|
||||||
<div v-if="pane===0">
|
|
||||||
<div class="">
|
|
||||||
<div class="w-full flex justify-between" @click="goToPage">
|
|
||||||
<div class="text-[16px] text-[#000]">
|
|
||||||
{{ selectedCountry }}
|
|
||||||
</div>
|
|
||||||
<div><van-icon color="#777" name="arrow" size="14" /></div>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="phoneNum" clearable :placeholder="$t('login.phonePlaceholder')">
|
|
||||||
<template #label>
|
|
||||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
|
||||||
+{{ selectedZone }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[55px]">
|
|
||||||
<van-button :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('login.getCode')" color="#2B53AC" block style="height: 48px" @click="getCode">{{ $t('login.getCode') }}</van-button>
|
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode') }}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-swipe-item>
|
|
||||||
<van-swipe-item>
|
|
||||||
<div v-if="pane===1">
|
|
||||||
<div class="flex mb-[16px]">
|
|
||||||
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('login.hasSendTo') }}</div>
|
|
||||||
<div class="text-[16px] text-[#000]">+{{ selectedZone }} {{ phoneNum }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="relative">
|
|
||||||
<van-password-input
|
|
||||||
:value="code"
|
|
||||||
:gutter="10"
|
|
||||||
:mask="false"
|
|
||||||
:focused="isFocused"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
v-model="code"
|
|
||||||
type="tel"
|
|
||||||
maxlength="6"
|
|
||||||
ref="codeInput"
|
|
||||||
class="opacity-0 absolute top-0 left-0 h-full w-full"
|
|
||||||
@input="code = $event.target.value.replace(/\D/g, '').slice(0, 6)"
|
|
||||||
@focus="isFocused = true"
|
|
||||||
@blur="isFocused = false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-between">
|
|
||||||
<div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'} text-14px`">
|
|
||||||
{{ $t('login.reSend') }}<span v-if="countdown>0">({{countdown}})</span>
|
|
||||||
</div>
|
|
||||||
<div @click="goBack" class="text-#2B53AC text-14px">
|
|
||||||
{{ $t('login.back') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mt-[17px]">
|
|
||||||
<van-button v-if="code.length === 6" type="primary" block :loading="loadingRef.loading2" :loading-text="$t('login.login')" style="height: 48px" @click="goLogin">{{ $t('login.login') }}</van-button>
|
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.login') }}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-swipe-item>
|
|
||||||
</van-swipe>
|
|
||||||
<div v-if="!isKeyboardVisible" class="text-center text-14px absolute left-1/2 transform translate-x--1/2 bottom-20px">
|
|
||||||
{{ $t('login.agreement') }}<span class="text-#3454AF " @click="$router.push('/privacyPolicy')">{{ $t('login.privacyPolicy') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
:deep(.van-cell.van-field) {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-password-input) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-password-input__item) {
|
|
||||||
border: 1px solid #E5E5E5;
|
|
||||||
width: 41px;
|
|
||||||
height: 41px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,97 +1,118 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {liveStore} from "~/stores/live/index.js";
|
import { liveStore } from "~/stores/live/index.js";
|
||||||
import {createBuyOrder} from "~/api/goods/index.js";
|
import { createBuyOrder } from "~/api/goods/index.js";
|
||||||
import {goodStore} from "~/stores/goods/index.js";
|
import { goodStore } from "~/stores/goods/index.js";
|
||||||
import { showLoadingToast ,closeToast} from 'vant';
|
import { showLoadingToast, closeToast } from "vant";
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
import { authStore } from "~/stores/auth/index.js";
|
||||||
|
|
||||||
import {message} from "~/components/x-message/useMessage.js";
|
import { message } from "~/components/x-message/useMessage.js";
|
||||||
const {checkoutSessionUrl,payment,payUid}= authStore()
|
const { checkoutSessionUrl, payment, payUid } = authStore();
|
||||||
const payStatus=ref(0)
|
const payStatus = ref(0);
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
i18n: 'payment.title'
|
i18n: "payment.title",
|
||||||
})
|
});
|
||||||
const {t}=useI18n()
|
const { t } = useI18n();
|
||||||
const router=useRouter()
|
const router = useRouter();
|
||||||
const changePayStatus=()=>{
|
const changePayStatus = () => {
|
||||||
payStatus.value=payStatus.value===0?1:0
|
payStatus.value = payStatus.value === 0 ? 1 : 0;
|
||||||
}
|
};
|
||||||
const { auctionData} = liveStore()
|
const { auctionData } = liveStore();
|
||||||
const amount=ref('')
|
const amount = ref("");
|
||||||
const confirmPay=async ()=>{
|
const confirmPay = async () => {
|
||||||
if (payStatus.value===1&&!amount.value){
|
if (payStatus.value === 1 && !amount.value) {
|
||||||
message.warning(t('payment.amountRequired'))
|
message.warning(t("payment.amountRequired"));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (Number(payment.value.leftPrice)<Number(amount.value)){
|
if (Number(payment.value.leftPrice) < Number(amount.value)) {
|
||||||
message.warning(t('payment.exceedAmount'))
|
message.warning(t("payment.exceedAmount"));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
showLoadingToast({
|
showLoadingToast({
|
||||||
message: t('payment.loading'),
|
message: t("payment.loading"),
|
||||||
forbidClick: true,
|
forbidClick: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res=await createBuyOrder({
|
const res = await createBuyOrder({
|
||||||
buyUid:payment.value.buyUid,
|
buyUid: payment.value.buyUid,
|
||||||
price:payStatus.value===0?payment.value.leftPrice:amount.value,
|
price: payStatus.value === 0 ? payment.value.leftPrice : amount.value,
|
||||||
currency:payment.value.leftCurrency,
|
currency: payment.value.leftCurrency,
|
||||||
testReturnHost:window.location.origin,
|
testReturnHost: window.location.origin,
|
||||||
testReturnEndPoint:'/payment/result'
|
testReturnEndPoint: "/payment/result",
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status===0){
|
if (res.status === 0) {
|
||||||
checkoutSessionUrl.value=res.data.checkoutSessionUrl
|
checkoutSessionUrl.value = res.data.checkoutSessionUrl;
|
||||||
payUid.value=res.data.payUid
|
payUid.value = res.data.payUid;
|
||||||
router.push({
|
router.push({
|
||||||
path:'/checkoutPage',
|
path: "/checkoutPage",
|
||||||
query:{
|
query: {
|
||||||
payUid:res.data.payUid,
|
payUid: res.data.payUid,
|
||||||
returnUrl:'/payment/result',
|
returnUrl: "/payment/result",
|
||||||
stripeKey:res.data.checkoutSessionUrl
|
stripeKey: res.data.checkoutSessionUrl,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const handleInput = (e) => {
|
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) {
|
if (newValue.indexOf(".") > 0) {
|
||||||
newValue = newValue.slice(0, newValue.indexOf('.') + 3)
|
newValue = newValue.slice(0, newValue.indexOf(".") + 3);
|
||||||
}
|
}
|
||||||
// 禁止输入以0开头的多位整数
|
// 禁止输入以0开头的多位整数
|
||||||
newValue = newValue.replace(/^0+(\d)/, '$1')
|
newValue = newValue.replace(/^0+(\d)/, "$1");
|
||||||
|
|
||||||
amount.value = newValue
|
amount.value = newValue;
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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">
|
<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>
|
||||||
<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>
|
<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>
|
||||||
<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">
|
<div class="w-full mt-auto mb-40px">
|
||||||
<van-button type="primary" block @click="confirmPay">
|
<van-button type="primary" block @click="confirmPay">
|
||||||
{{ t('payment.confirm') }}
|
{{ t("payment.confirm") }}
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
@ -1,94 +1,102 @@
|
|||||||
<script setup>
|
<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({
|
definePageMeta({
|
||||||
i18n: 'payment.text1',
|
i18n: "payment.text1",
|
||||||
})
|
});
|
||||||
|
const router = useRouter();
|
||||||
const router = useRouter()
|
const { t } = useI18n();
|
||||||
const {t} = useI18n();
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const resData = ref({})
|
const resData = ref({});
|
||||||
let timer = null
|
let timer = null;
|
||||||
let startTime = Date.now()
|
let startTime = Date.now();
|
||||||
|
|
||||||
const queryOrder = async () => {
|
const queryOrder = async () => {
|
||||||
// 首先检查是否已经超过5秒
|
// 首先检查是否已经超过5秒
|
||||||
if (Date.now() - startTime > 5000) {
|
if (Date.now() - startTime > 5000) {
|
||||||
clearInterval(timer)
|
clearInterval(timer);
|
||||||
closeToast()
|
closeToast();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showLoadingToast({
|
showLoadingToast({
|
||||||
message: '加载中...',
|
message: "加载中...",
|
||||||
forbidClick: true,
|
forbidClick: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await orderQuery({
|
const res = await orderQuery({
|
||||||
orderNo: route.query.orderNo
|
orderNo: route.query.orderNo,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
resData.value = res.data
|
resData.value = res.data;
|
||||||
|
|
||||||
// 只在支付成功时停止轮询
|
// 只在支付成功时停止轮询
|
||||||
if (resData.value.status === 1) {
|
if (resData.value.status === 1) {
|
||||||
clearInterval(timer)
|
clearInterval(timer);
|
||||||
closeToast()
|
closeToast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clearInterval(timer)
|
clearInterval(timer);
|
||||||
closeToast()
|
closeToast();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 立即执行一次
|
// 立即执行一次
|
||||||
await queryOrder()
|
await queryOrder();
|
||||||
|
|
||||||
// 开始轮询
|
// 开始轮询
|
||||||
timer = setInterval(async () => {
|
timer = setInterval(async () => {
|
||||||
await queryOrder()
|
await queryOrder();
|
||||||
}, 1000)
|
}, 1000);
|
||||||
|
|
||||||
// 组件卸载时清除定时器
|
// 组件卸载时清除定时器
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (timer) {
|
if (timer) {
|
||||||
clearInterval(timer)
|
clearInterval(timer);
|
||||||
closeToast()
|
closeToast();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const statusLabel = {
|
const statusLabel = {
|
||||||
1: t('payment.text2'),
|
1: t("payment.text2"),
|
||||||
2: t('payment.text3'),
|
2: t("payment.text3"),
|
||||||
3: t('payment.text4'),
|
3: t("payment.text4"),
|
||||||
4: t('payment.text5'),
|
4: t("payment.text5"),
|
||||||
}
|
};
|
||||||
|
|
||||||
const goHome = () => {
|
const goHome = () => {
|
||||||
router.push('/')
|
router.push("/");
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<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">
|
<div class="flex flex-col items-center mt-150px">
|
||||||
<img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt="">
|
<img
|
||||||
<div class="text-#000 text-16px mb-25px">{{ statusLabel[resData.status] }}!</div>
|
class="w-119px h-120px mb-36px"
|
||||||
<div class="text-#999 text-16px">{{ resData.currency }}{{ resData.money }}</div>
|
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>
|
||||||
<div class="w-full mt-auto mb-40px">
|
<div class="w-full mt-auto mb-40px">
|
||||||
<van-button type="primary" block @click="goHome">
|
<van-button type="primary" block @click="goHome">
|
||||||
{{ t('payment.result.backToHome') }}
|
{{ t("payment.result.backToHome") }}
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
</style>
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
i18n: 'login.privacyPolicy'
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="px-10px pt-20px pb-60px"><iframe class="w-full h-100vh" src="/privacyPolicy.html"></iframe></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,172 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { userArtworks } from "@/api/goods/index.js"
|
|
||||||
import { authStore } from "@/stores/auth/index.js"
|
|
||||||
import xImage from '@/components/x-image/index.vue'
|
|
||||||
import { ref } from "vue"
|
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
layout: 'default',
|
|
||||||
i18n: 'menu.profile',
|
|
||||||
})
|
|
||||||
const {t}=useI18n();
|
|
||||||
const router = useRouter()
|
|
||||||
const { userInfo,payment } = authStore()
|
|
||||||
const showMyList = ref([])
|
|
||||||
const localState = ref({
|
|
||||||
finished: true,
|
|
||||||
refreshing: false
|
|
||||||
})
|
|
||||||
|
|
||||||
const groupByDate = (data) => {
|
|
||||||
if (!Array.isArray(data)) return []
|
|
||||||
|
|
||||||
return Object.values(data.reduce((acc, curr) => {
|
|
||||||
const date = curr.userCreatedAt
|
|
||||||
if (!acc[date]) {
|
|
||||||
acc[date] = { userCreatedAt: date, list: [] }
|
|
||||||
}
|
|
||||||
acc[date].list.push(curr)
|
|
||||||
return acc
|
|
||||||
}, {})).sort((a, b) => new Date(b.userCreatedAt) - new Date(a.userCreatedAt))
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetchData = async () => {
|
|
||||||
try {
|
|
||||||
const res = await userArtworks({})
|
|
||||||
if (res.status === 0) {
|
|
||||||
showMyList.value = groupByDate(res.data.data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onRefresh = async () => {
|
|
||||||
localState.value.refreshing = true
|
|
||||||
await fetchData()
|
|
||||||
localState.value.refreshing = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const goPay = (item) => {
|
|
||||||
payment.value.leftPrice=item.leftPrice
|
|
||||||
payment.value.leftCurrency=item.leftCurrency
|
|
||||||
payment.value.buyUid=item.uuid
|
|
||||||
payment.value.auctionArtworkUuid=item?.auctionArtworkUuid
|
|
||||||
if (item.status===1){
|
|
||||||
router.push('/signature/protocol')
|
|
||||||
}else if (item.status===4){
|
|
||||||
router.push('/payment')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const goDetail = (item) => router.push({ path: '/artDetail', query: { uuid: item.uuid } })
|
|
||||||
const statusLabel={
|
|
||||||
1:t('payment.text4'),
|
|
||||||
2:t('payment.text2'),
|
|
||||||
4:t('payment.text6'),
|
|
||||||
}
|
|
||||||
fetchData()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="w-[100vw] bg-[url('@/static/images/3532@2x.png')] bg-cover pt-43px flex-grow-1 flex flex-col">
|
|
||||||
<!-- 用户信息 -->
|
|
||||||
<div class="flex items-center px-16px mb-43px">
|
|
||||||
<img class="w-57px h-57px mr-23px" src="@/static/images/5514@2x.png" alt="">
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<div class="text-18px text-#181818">{{ userInfo.realName }}</div>
|
|
||||||
<div class="text-#575757 text-14px">{{ userInfo.telNum }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 设置选项 -->
|
|
||||||
<div class="px-16px mb-20px">
|
|
||||||
<van-cell-group inset>
|
|
||||||
<!-- 移除语言设置入口 -->
|
|
||||||
</van-cell-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 列表内容 -->
|
|
||||||
<div class="grow-1 flex flex-col">
|
|
||||||
<div class="border-b-1px border-b-#D3D3D3 px-16px">
|
|
||||||
<div class="text-#000 text-16px border-b-3 border-b-#2B53AC w-80px h-36px">{{ $t('home.my_lots') }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<van-pull-refresh
|
|
||||||
v-model="localState.refreshing"
|
|
||||||
:success-duration="700"
|
|
||||||
class="h-full grow-1"
|
|
||||||
@refresh="onRefresh"
|
|
||||||
>
|
|
||||||
<template #success>
|
|
||||||
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
|
||||||
</template>
|
|
||||||
<van-list :finished="localState.finished" :finished-text="$t('home.finished_text')" class="h-full">
|
|
||||||
<!-- 空状态 -->
|
|
||||||
<div v-if="showMyList?.length < 1" class="flex flex-col items-center pt-100px">
|
|
||||||
<img class="w-103px h-88px mb-19px" src="@/static/images/zu5512@2x.png" alt="">
|
|
||||||
<div class="text-14px text-#575757">{{$t('profile.text1')}}</div>
|
|
||||||
<div class="text-14px text-#575757">{{$t('profile.text2')}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 列表内容 -->
|
|
||||||
<template v-else>
|
|
||||||
<div v-for="group in showMyList" :key="group.userCreatedAt" class="px-16px pt-14px">
|
|
||||||
<div class="text-#575757 text-14px mb-3px">{{ group.userCreatedAt }}</div>
|
|
||||||
<div
|
|
||||||
v-for="item in group.list"
|
|
||||||
:key="item.uuid"
|
|
||||||
class="flex mb-22px"
|
|
||||||
@click="goDetail(item)"
|
|
||||||
>
|
|
||||||
<x-image
|
|
||||||
class="w-80px h-80px flex-shrink-0 mr-10px rounded-4px overflow-hidden"
|
|
||||||
:src="item?.auctionArtworkInfo?.artwork?.hdPic"
|
|
||||||
:preview="false"
|
|
||||||
/>
|
|
||||||
<div class="flex flex-col justify-between grow-1">
|
|
||||||
<div class="flex justify-between">
|
|
||||||
<div class="text-#000 text-16px ellipsis line-height-21px">
|
|
||||||
{{ item?.auctionArtworkInfo?.artworkTitle }}
|
|
||||||
</div>
|
|
||||||
<div class="text-14px text-right text-#3C55B2 ">
|
|
||||||
{{statusLabel[item.status]}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="flex justify-between">
|
|
||||||
<div>
|
|
||||||
<div class="text-#575757 text-14px line-height-none mb-5px">
|
|
||||||
{{ $t('home.start_price') }}:{{item.auctionArtworkInfo?.startPriceCurrency}} {{item.auctionArtworkInfo?.startPrice}}
|
|
||||||
</div>
|
|
||||||
<div class="text-#B58047 text-14px line-height-none">
|
|
||||||
{{ $t('home.close_price') }}:{{item.baseCurrency}} {{item.baseMoney}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<van-button
|
|
||||||
v-if="[1,3,4].includes(item.status)"
|
|
||||||
class="w-73px !h-30px"
|
|
||||||
type="primary"
|
|
||||||
@click.stop="goPay(item)"
|
|
||||||
>
|
|
||||||
<span class="text-12px">{{ $t('art_detail_page.button') }}</span>
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-list>
|
|
||||||
</van-pull-refresh>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.ellipsis {
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,79 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
|
||||||
import {useI18n} from 'vue-i18n'
|
|
||||||
const {t} = useI18n()
|
|
||||||
const props = defineProps({
|
|
||||||
type: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const columns1 = ref([
|
|
||||||
{text: t('realAuth.idCard'), value: '1'},
|
|
||||||
{text: t('realAuth.passport'), value: '2'},
|
|
||||||
{text: t('realAuth.other'), value: '3'},
|
|
||||||
])
|
|
||||||
const {userInfo}= authStore()
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="text-#1A1A1A text-16px">
|
|
||||||
<template v-if="type===0">
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.name')}}:</div>
|
|
||||||
<div>{{userInfo.realName}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.gender')}}:</div>
|
|
||||||
<div>{{userInfo.sex===1?$t('realAuth.male'):$t('realAuth.female')}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.birthday')}}:</div>
|
|
||||||
<div>{{userInfo.birthDate}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.idCard')}}:</div>
|
|
||||||
<div>{{userInfo.idNum}}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-if="type===1">
|
|
||||||
<div class="flex mb-20px" >
|
|
||||||
<div class="mr-10px">{{$t('realAuth.name')}}:</div>
|
|
||||||
<div>{{userInfo.realName||userInfo.userExtend.realName||''}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.gender')}}:</div>
|
|
||||||
<div>{{userInfo.sex===1?$t('realAuth.male'):$t('realAuth.female')}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.birthday')}}:</div>
|
|
||||||
<div>{{userInfo.birthDate}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.adress')}}:</div>
|
|
||||||
<div>{{userInfo.userExtend.address}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.bank')}}:</div>
|
|
||||||
<div>{{userInfo.userExtend.bankName}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.bankCard')}}:</div>
|
|
||||||
<div>{{userInfo.userExtend.bankNo}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.idTye')}}:</div>
|
|
||||||
<div>{{columns1.find(x=>x.value===userInfo.userExtend.idType)?.text}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex mb-20px">
|
|
||||||
<div class="mr-10px">{{$t('realAuth.idNumber')}}:</div>
|
|
||||||
<div>{{userInfo.userExtend.idNo}}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,172 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
import {userUpdate} from "@/api/auth/index.js";
|
|
||||||
import {message} from '@/components/x-message/useMessage.js'
|
|
||||||
import detail from './components/detail.vue'
|
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
|
||||||
import XVanDate from '@/components/x-van-date/index.vue'
|
|
||||||
import XVanSelect from '@/components/x-van-select/index.vue'
|
|
||||||
import {fddCheck} from "~/api/goods/index.js";
|
|
||||||
definePageMeta({
|
|
||||||
i18n: 'realAuth.title',
|
|
||||||
})
|
|
||||||
const router = useRouter();
|
|
||||||
const route = useRoute();
|
|
||||||
const { locale } = useI18n()
|
|
||||||
const {userInfo,selectedZone}= authStore()
|
|
||||||
const active=ref(locale.value==='zh-CN'?0:1)
|
|
||||||
const { t } = useI18n()
|
|
||||||
const columns1 = ref([
|
|
||||||
{text: t('realAuth.passport'), value: '2'},
|
|
||||||
{text: t('realAuth.other'), value: '3'},
|
|
||||||
])
|
|
||||||
const form=ref({
|
|
||||||
realName: "",
|
|
||||||
sex:'',
|
|
||||||
birthDate:'',
|
|
||||||
userExtend: {
|
|
||||||
address: "",
|
|
||||||
bankName: "",
|
|
||||||
bankNo: ""
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const form1=ref({
|
|
||||||
idNum:'',
|
|
||||||
realName:'',
|
|
||||||
userExtend:{}
|
|
||||||
})
|
|
||||||
const columns=ref([
|
|
||||||
{ text: t('realAuth.male'), value: 1 },
|
|
||||||
{ text: t('realAuth.female'), value: 2 },
|
|
||||||
])
|
|
||||||
function isFormComplete(obj) {
|
|
||||||
for (const key in obj) {
|
|
||||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
|
||||||
if (!isFormComplete(obj[key])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (obj[key] === "") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusCode=ref(Number(route.query.statusCode))
|
|
||||||
const confirm=async ()=>{
|
|
||||||
const thatForm=active.value===0?form1.value:form.value
|
|
||||||
thatForm.userExtend.isMainland=active.value===0?1:0
|
|
||||||
if (isFormComplete(thatForm)){
|
|
||||||
const res=await userUpdate(thatForm)
|
|
||||||
if (res.status===0){
|
|
||||||
userInfo.value=res.data
|
|
||||||
message.success(t('realAuth.success_mess'))
|
|
||||||
//实名认证,选择的是大陆,并且手机区号选择的也是大陆就走法大大验证
|
|
||||||
if (active.value===0){
|
|
||||||
const res1=await fddCheck()
|
|
||||||
if (res1.status===0){
|
|
||||||
if (res1.data.isNeedJump){
|
|
||||||
window.location.href=res1.data.h5Url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
statusCode.value=1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
message.error(t('realAuth.cnTabDesc'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const goHome=()=>{
|
|
||||||
router.push('/')
|
|
||||||
}
|
|
||||||
const goLogin=()=>{
|
|
||||||
router.back()
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="px-[31px] bg-[url('@/static/images/asdfsdd.png')] bg-cover w-100vw flex-grow-1 pt-[46px] relative flex flex-col">
|
|
||||||
<van-tabs v-if="statusCode===0" v-model:active="active" animated swipeable>
|
|
||||||
<van-tab :title="$t('realAuth.cnTab')" class="pt-[80px]">
|
|
||||||
<template v-if="statusCode===0">
|
|
||||||
<div class="text-[#BDBDBD] text-[16px] mb-[34px]">{{ $t('realAuth.cnTabDesc') }}</div>
|
|
||||||
<div class="mb-[100px]">
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="form1.idNum" :label="$t('realAuth.idCard')" clearable
|
|
||||||
:placeholder="$t('realAuth.idCardPlaceholder')"></van-field>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="form1.realName" :label="$t('realAuth.name')" clearable :placeholder="$t('realAuth.namePlaceholder')"></van-field>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-tab>
|
|
||||||
<van-tab :title="$t('realAuth.otherTab')" class="pt-[80px]">
|
|
||||||
<div class="text-[#BDBDBD] text-[16px] mb-[34px]">{{ $t('realAuth.otherTabDesc') }}</div>
|
|
||||||
<div class="mb-[100px]">
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="form.realName" :label="$t('realAuth.name')" clearable :placeholder="$t('realAuth.namePlaceholder')"></van-field>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<x-van-select v-model="form.sex" :placeholder="$t('realAuth.text1')" :label="$t('realAuth.gender')" :columns="columns"/>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<x-van-date v-model="form.birthDate" :label="$t('realAuth.birthday')" :placeholder="$t('realAuth.birthdayPlaceholder')"/>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="form.userExtend.address" :label="$t('realAuth.adress')" clearable
|
|
||||||
:placeholder="$t('realAuth.adressPlaceholder')"></van-field>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="form.userExtend.bankName" :label="$t('realAuth.bank')" clearable :placeholder="$t('realAuth.bankPlaceholder')"></van-field>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field v-model="form.userExtend.bankNo" :label="$t('realAuth.bankCard')" clearable
|
|
||||||
:placeholder="$t('realAuth.bankCardPlaceholder')"></van-field>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<x-van-select v-model="form.userExtend.idType" :label="$t('realAuth.idTye')" :columns="columns1"/>
|
|
||||||
</div>
|
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
|
||||||
<van-field :label="$t('realAuth.idNumber')" v-model="form.userExtend.idNo" class="mb-10px" :placeholder="$t('realAuth.idNumberPlaceholder')"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</van-tab>
|
|
||||||
</van-tabs>
|
|
||||||
<van-tabs v-else-if="statusCode===1" v-model:active="active" animated swipeable>
|
|
||||||
<van-tab :title="$t('realAuth.cnTab')" class="pt-[80px]">
|
|
||||||
<detail :type="active"></detail>
|
|
||||||
</van-tab>
|
|
||||||
<van-tab :title="$t('realAuth.otherTab')" class="pt-[80px]">
|
|
||||||
<detail :type="active"></detail>
|
|
||||||
</van-tab>
|
|
||||||
</van-tabs>
|
|
||||||
<div class="flex justify-between shrink-0 mb-20px" v-if="statusCode===0">
|
|
||||||
<van-button style="width: 151px;height: 48px" color="#E9F1F8" @click="goLogin">
|
|
||||||
<div class="text-#2B53AC text-16px">{{ $t('realAuth.cancel') }}</div>
|
|
||||||
</van-button>
|
|
||||||
<van-button @click="confirm" style="width: 151px;height: 48px" color="#2B53AC">
|
|
||||||
<div class="text-#FFFFFF text-16px">{{ $t('realAuth.confirm') }}</div>
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
<div v-else class="mt-auto pb-94px">
|
|
||||||
<van-button color="#E9F1F8" @click="goHome" style="color: #2B53AC;font-weight: 600" block>{{ $t('home.go_home')}}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
:deep(.van-tabs__line) {
|
|
||||||
height: 2px;
|
|
||||||
width: 107px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-cell) {
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,118 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import {showToast,showLoadingToast } from 'vant';
|
|
||||||
import {onMounted, onUnmounted, ref} from 'vue';
|
|
||||||
import {signOffline, signOnline} from "~/api/goods/index.js";
|
|
||||||
import {VueSignaturePad} from "vue-signature-pad";
|
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
|
||||||
import {useI18n} from "vue-i18n";
|
|
||||||
const router = useRouter();
|
|
||||||
const {t:$t} = useI18n()
|
|
||||||
definePageMeta({
|
|
||||||
layout: ''
|
|
||||||
})
|
|
||||||
const { payment} = authStore()
|
|
||||||
const signaturePad = ref(null);
|
|
||||||
const imgUrl = ref('')
|
|
||||||
const clearSignature = () => {
|
|
||||||
signaturePad.value?.clearSignature();
|
|
||||||
};
|
|
||||||
const toast=ref(false)
|
|
||||||
const submitSignature = () => {
|
|
||||||
if (signaturePad.value?.isEmpty()) {
|
|
||||||
showToast($t('collectCode.signature.pleaseSign'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toast.value=showLoadingToast({
|
|
||||||
message: '加载中...',
|
|
||||||
forbidClick: true,
|
|
||||||
});
|
|
||||||
const { data } = signaturePad.value?.saveSignature(); // 返回 base64 格式的图片数据
|
|
||||||
imgUrl.value = data;
|
|
||||||
confirm()
|
|
||||||
|
|
||||||
};
|
|
||||||
const confirm = async () => {
|
|
||||||
const res = await signOnline({
|
|
||||||
auctionArtworkUuid:payment.value.auctionArtworkUuid,
|
|
||||||
signImgFileData: imgUrl.value
|
|
||||||
})
|
|
||||||
if (res.status===0){
|
|
||||||
await router.push('/payment')
|
|
||||||
toast.value?.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const goBack = () => {
|
|
||||||
router.back()
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="signature-container">
|
|
||||||
<div class="flex flex-col h-100vh px-20px py-20px bg-gray w-100vw">
|
|
||||||
<client-only>
|
|
||||||
<VueSignaturePad
|
|
||||||
width="100%"
|
|
||||||
height="93%"
|
|
||||||
class="signature bg-#fff rounded-10px mb-10px"
|
|
||||||
ref="signaturePad"
|
|
||||||
/>
|
|
||||||
</client-only>
|
|
||||||
<div class="flex justify-evenly">
|
|
||||||
<van-button class="!h-40px mr-15px" type="primary" @click="goBack">
|
|
||||||
{{ $t('collectCode.signature.back') }}
|
|
||||||
</van-button>
|
|
||||||
<van-button class="!h-40px" type="warning" @click="clearSignature">
|
|
||||||
{{ $t('collectCode.signature.clear') }}
|
|
||||||
</van-button>
|
|
||||||
<van-button class="!h-40px" type="primary" @click="submitSignature">
|
|
||||||
{{ $t('collectCode.signature.confirm') }}
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.signature-container {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-button--mini+.van-button--mini) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.van-dialog__content) {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-content {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.control-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 0 10px 0;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.control-button {
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.orientation-hint {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-color: #fff;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,64 +0,0 @@
|
|||||||
<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'
|
|
||||||
definePageMeta({
|
|
||||||
name: 'personal-info',
|
|
||||||
})
|
|
||||||
const {t} = useI18n()
|
|
||||||
const {t:$t} = useI18n()
|
|
||||||
const showPicker = ref(false)
|
|
||||||
const showPicker1 = ref(false)
|
|
||||||
const onConfirm = () => {
|
|
||||||
|
|
||||||
}
|
|
||||||
const router = useRouter()
|
|
||||||
const columns = ref([
|
|
||||||
{text: t('realAuth.male'), value: 1},
|
|
||||||
{text: t('realAuth.female'), value: 2},
|
|
||||||
])
|
|
||||||
const goCountryRegion=()=>{
|
|
||||||
router.push({
|
|
||||||
path:'/countryRegion'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const adress=ref('')
|
|
||||||
</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 ">
|
|
||||||
<div class="text-16px text-#191919 font-bold mb-40px px-34px">
|
|
||||||
{{$t('personal.title')}}
|
|
||||||
</div>
|
|
||||||
<div class="grow-1 px-34px">
|
|
||||||
<van-field type="tel" :label-width="161" :label="$t('personal.text')" class="mb-10px" :placeholder="$t('login.phonePlaceholder')">
|
|
||||||
<template #label>
|
|
||||||
<div class="flex">
|
|
||||||
<div class="mr-41px whitespace-nowrap">{{$t('profile.phone')}}</div>
|
|
||||||
<div @click="goCountryRegion">
|
|
||||||
<span class="mr-13px">+ 86</span>
|
|
||||||
<van-icon name="arrow-down" class="text-#777777"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
<van-field :label="$t('profile.name')" class="mb-10px" :placeholder="$t('realAuth.namePlaceholder')"/>
|
|
||||||
<x-van-select :label="$t('realAuth.gender')" :columns="columns"/>
|
|
||||||
<x-van-date :label="$t('realAuth.birthday')"/>
|
|
||||||
<van-field v-model="adress" :label="$t('realAuth.adress')" class="mb-10px" :placeholder="$t('realAuth.adressPlaceholder')"/>
|
|
||||||
<van-field :label="$t('realAuth.bank')" class="mb-10px" :placeholder="$t('realAuth.bankPlaceholder')"/>
|
|
||||||
<van-field :label="$t('realAuth.bankCard')" class="mb-10px" :placeholder="$t('realAuth.bankCardPlaceholder')"/>
|
|
||||||
</div>
|
|
||||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
|
||||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">{{$t('personal.next')}}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
:deep(.van-cell.van-field){
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,109 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import pdfView from './pdfView'
|
|
||||||
import { contractView } from "~/api/goods/index.js"
|
|
||||||
import { signOnline } from "~/api/goods/index.js"
|
|
||||||
import { authStore } from "~/stores/auth/index.js"
|
|
||||||
import {useI18n} from "vue-i18n";
|
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
layout: 'default',
|
|
||||||
i18n: 'signature.protocol.title'
|
|
||||||
})
|
|
||||||
|
|
||||||
const { userInfo, payment } = authStore()
|
|
||||||
const $t=useI18n().t
|
|
||||||
const activeNames = ref([])
|
|
||||||
const router = useRouter()
|
|
||||||
const pmblUrl = ref('') // 存储拍卖笔录的URL
|
|
||||||
|
|
||||||
// 协议列表数据
|
|
||||||
const protocolList = computed(() => [
|
|
||||||
{ id: '1', title: $t('signature.agreement.notice'), pdfName: 'pmgg', type: 'local' },
|
|
||||||
{ id: '2', title: $t('signature.agreement.rules'), pdfName: 'pmgz', type: 'local' },
|
|
||||||
{ id: '3', title: $t('signature.agreement.buyerGuide'), pdfName: 'jmxz', type: 'local' },
|
|
||||||
{ id: '4', title: $t('signature.agreement.buyerAgreement'), pdfName: 'jmxy', type: 'local' },
|
|
||||||
{ id: '5', title: $t('signature.agreement.record'), pdfName: pmblUrl.value, type: 'remote' },
|
|
||||||
{ id: '6', title: $t('signature.agreement.transfer'), pdfName: 'pmyjqrs', type: 'local' }
|
|
||||||
])
|
|
||||||
|
|
||||||
// 获取拍卖笔录PDF
|
|
||||||
const fetchPmblPdf = async () => {
|
|
||||||
try {
|
|
||||||
const res = await contractView({
|
|
||||||
auctionArtworkUuid: payment.value.auctionArtworkUuid,
|
|
||||||
})
|
|
||||||
pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听折叠面板变化
|
|
||||||
const handleCollapseChange = (name) => {
|
|
||||||
activeNames.value = name
|
|
||||||
// 当打开拍卖笔录时获取PDF
|
|
||||||
if (name === '5' && !pmblUrl.value) {
|
|
||||||
fetchPmblPdf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const goSignature = async () => {
|
|
||||||
const res = await signOnline({
|
|
||||||
auctionArtworkUuid:payment.value.auctionArtworkUuid
|
|
||||||
})
|
|
||||||
if (res.status===0){
|
|
||||||
if(res.data.signType==='fdd'){
|
|
||||||
window.location.href = res.data.fddVerifyUrl
|
|
||||||
}else{
|
|
||||||
router.push({
|
|
||||||
path: '/signature/panel'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
console.log('goSignature')
|
|
||||||
// router.push({
|
|
||||||
// path: '/signature/panel'
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="bg-#EBEBEB h-screen-nav flex flex-col">
|
|
||||||
<div class="h-50px text-14px text-#191919 bg-#fff flex items-center px-21px mb-6px shrink-0">
|
|
||||||
{{ $t('signature.tips.prePayment') }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<van-collapse
|
|
||||||
accordion
|
|
||||||
v-model="activeNames"
|
|
||||||
class="grow-1"
|
|
||||||
@change="handleCollapseChange"
|
|
||||||
>
|
|
||||||
<van-collapse-item
|
|
||||||
v-for="item in protocolList"
|
|
||||||
:key="item.id"
|
|
||||||
:name="item.id"
|
|
||||||
class="mb-6px"
|
|
||||||
>
|
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">{{ item.title }}</div>
|
|
||||||
</template>
|
|
||||||
<pdfView
|
|
||||||
:pdf-name="item.pdfName"
|
|
||||||
:type="item.type"
|
|
||||||
:is-active="activeNames === item.id"
|
|
||||||
/>
|
|
||||||
</van-collapse-item>
|
|
||||||
</van-collapse>
|
|
||||||
|
|
||||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
|
||||||
<van-button
|
|
||||||
color="#2B53AC"
|
|
||||||
class="w-213px van-btn-h-38px"
|
|
||||||
@click="goSignature"
|
|
||||||
>
|
|
||||||
{{ $t('signature.button.agreeAndSign') }}
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,68 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="pdf-container">
|
|
||||||
<client-only>
|
|
||||||
<div v-if="loading" class="loading-container">
|
|
||||||
<van-loading type="spinner" size="24px">{{ $t('common.loading') }}</van-loading>
|
|
||||||
</div>
|
|
||||||
<VuePdfEmbed
|
|
||||||
v-if="pdfUrl"
|
|
||||||
:source="pdfUrl"
|
|
||||||
@rendered="handleRendered"
|
|
||||||
/>
|
|
||||||
</client-only>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import VuePdfEmbed from 'vue-pdf-embed'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
pdfName: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: 'local', // 'local' 或 'remote'
|
|
||||||
},
|
|
||||||
isActive: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const loading = ref(true)
|
|
||||||
const pdfUrl = computed(() => {
|
|
||||||
if (!props.pdfName) return ''
|
|
||||||
return props.type === 'local' ? `/pdfs/${props.pdfName}.pdf` : props.pdfName
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(() => props.isActive, (newVal) => {
|
|
||||||
if (newVal) {
|
|
||||||
loading.value = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleRendered = () => {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.pdf-container {
|
|
||||||
position: relative;
|
|
||||||
min-height: 200px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-container {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(embed) {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
1
env/.env.prod
vendored
1
env/.env.prod
vendored
@ -3,3 +3,4 @@ NUXT_PUBLIC_API_BASE=https://auction.szjixun.cn
|
|||||||
NUXT_PUBLIC_SOCKET_URL=wss://auction.szjixun.cn
|
NUXT_PUBLIC_SOCKET_URL=wss://auction.szjixun.cn
|
||||||
NUXT_API_SECRET=prod-secret
|
NUXT_API_SECRET=prod-secret
|
||||||
NUXT_PUBLIC_PKEY=pk_live_51QfbSAAB1Vm8VfJqEVY2uFHPn9N4sDbOaCzht8IVKoylYBrYvdUsmsnCzGxIoN9skBCvI5PsxLJcf4PlytXIr1aX00mFJBXSB8
|
NUXT_PUBLIC_PKEY=pk_live_51QfbSAAB1Vm8VfJqEVY2uFHPn9N4sDbOaCzht8IVKoylYBrYvdUsmsnCzGxIoN9skBCvI5PsxLJcf4PlytXIr1aX00mFJBXSB8
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user