跳转支付

This commit is contained in:
张 元山 2025-03-04 20:25:44 +08:00
parent 80f7297467
commit 18e6fd43f5
22 changed files with 52 additions and 3838 deletions

View File

@ -53,11 +53,11 @@ export async function offlineQrcode(data) {
data
})
}
export async function createOrder(data) {
return await request( {
url:'/api/v1/offlineQrcode/createOrder/V2',
export async function createOrder (data) {
return await request({
url: '/api/v1/offlineQrcode/createOrder',
method: 'POST',
data
})
}
}

View File

@ -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>

View File

@ -5,31 +5,45 @@ import { goodStore } from "~/stores/goods/index.js";
import { showLoadingToast, closeToast } from "vant";
import { authStore } from "~/stores/auth/index.js";
import { message } from "~/components/x-message/useMessage.js";
import { createOrder } from "~/api-collect-code/goods/index.js";
import { createOrder, offlineQrcode } from "~/api-collect-code/goods/index.js";
import { codeAuthStore } from "~/stores-collect-code/auth/index.js";
import { useI18n } from "vue-i18n";
const amount = ref("");
const router = useRouter();
const route = useRoute();
const { t } = useI18n();
const { checkoutSessionUrl, qrUid, qrData, codePKey, codePayUid } =
codeAuthStore();
const payStatus = ref(0);
const state = reactive({
pageRequest: false,
});
definePageMeta({
i18n: "payment.title",
});
const changePayStatus = () => {
payStatus.value = payStatus.value === 0 ? 1 : 0;
};
const amount = ref("");
const router = useRouter();
const confirmPay = async () => {
showLoadingToast({
message: t("common.loading"),
forbidClick: true,
const getData = async () => {
state.pageRequest = true;
const res = await offlineQrcode({
qrUid: route.query.qrUid,
});
if (res.status === 0) {
qrData.value = res.data;
payStatus.value = res.data.payStatus;
if (qrData.value.payStatus === 2) {
state.pageRequest = false;
} else {
confirmPay();
}
}
};
//
getData();
const confirmPay = async () => {
const res = await createOrder({
price: payStatus.value === 0 ? qrData.value.leftPrice : amount.value,
price: qrData.value.price,
currency: qrData.value.currency,
qrUid: qrUid.value,
qrUid: route.query.qrUid,
testReturnHost: window.location.origin,
testReturnEndPoint: "/collectCode/payment/result",
});
@ -46,64 +60,41 @@ const confirmPay = async () => {
});
}
};
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>
<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="mb-30px">
<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 v-if="!state.pageRequest" class="mb-30px">
<img class="w-126px h-126px" src="@/static/images/dddf34@2x.png" alt="" />
</div>
<div class="text-#1A1A1A text-16px mb-25px font-bold">
{{
payStatus === 0
? $t("collectCode.payment.fullPayment")
: $t("collectCode.payment.partialPayment")
}}
<div
v-if="!state.pageRequest"
class="text-#999999 text-16px mb-24px font-bold"
>
{{ qrData.price + " " + qrData.currency }}
</div>
<div
class="text-#999999 text-16px mb-24px font-bold"
v-if="payStatus === 0"
v-if="!state.pageRequest"
class="text-#1A1A1A text-16px mb-25px font-bold"
>
{{ qrData.currency }}
{{ qrData?.leftPrice }}
你已完成全部支付
</div>
<div class="mb-12px" v-else>
<input
v-model="amount"
class="w-272px h-48px bg-#F3F3F3 px-11px text-16px"
type="text"
:placeholder="`${$t('collectCode.payment.maxAmount')} ${
qrData.currency
} ${qrData?.leftPrice}`"
@input="handleInput"
/>
</div>
<div class="w-full mt-auto mb-40px">
<!-- <div class="w-full mt-auto mb-40px">
<van-button type="primary" block @click="confirmPay">
{{ $t("collectCode.payment.confirmPayment") }}
</van-button>
</div>
</div> -->
</div>
</template>

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -1,18 +0,0 @@
<script setup>
import CheckoutPage from "@/components/stripe/CheckoutPage.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>

View File

@ -1,10 +1,10 @@
<script setup>
import Payment from "./payment/index.vue";
import CollectCodePayment from "./collectCode/payment/index.vue";
definePageMeta({
layout: "default",
i18n: "menu.payment",
});
</script>
<template>
<Payment />
<CollectCodePayment />
</template>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -1,186 +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 { 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>
</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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 URLdata
} 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>

View File

@ -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>