Compare commits
11 Commits
016623b6a4
...
5fe9645cfb
Author | SHA1 | Date | |
---|---|---|---|
|
5fe9645cfb | ||
|
9402c8b719 | ||
|
3b60502ae3 | ||
|
ff90f4a3a1 | ||
|
f01d711d55 | ||
|
e57f758804 | ||
|
a378a45b19 | ||
|
ecf14e5eeb | ||
|
80efe786e0 | ||
|
b005d33dca | ||
|
ffafe1358d |
@ -1,7 +1,7 @@
|
||||
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { ref, reactive, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
//i18n
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const {t} =useI18n()
|
||||
@ -40,7 +40,15 @@
|
||||
maxMoveX.value = img.width - blockSize
|
||||
loaded.value = true
|
||||
}
|
||||
|
||||
watch(()=>{
|
||||
return props.loading
|
||||
},(newVal)=>{
|
||||
if(!newVal){
|
||||
verifyStatus.show = false
|
||||
verifyStatus.message = ''
|
||||
moveX.value = 0
|
||||
}
|
||||
})
|
||||
const onImageError = () => {
|
||||
console.error('Image failed to load')
|
||||
maxMoveX.value = 270
|
||||
@ -84,11 +92,7 @@
|
||||
verifyStatus.type = success ? 'success' : 'error'
|
||||
verifyStatus.message = success ? t('components.form.verifySuccess') : t('components.form.verifyFailed')
|
||||
isVerifying.value = false
|
||||
setTimeout(() => {
|
||||
verifyStatus.show = false
|
||||
verifyStatus.message = ''
|
||||
moveX.value = 0
|
||||
}, 1500)
|
||||
|
||||
}
|
||||
|
||||
// 事件监听
|
||||
|
@ -26,6 +26,11 @@ const columns1 = ref([
|
||||
{text: t('realAuth.passport'), value: 2},
|
||||
{text: t('realAuth.other'), value: 3},
|
||||
])
|
||||
|
||||
/**
|
||||
* 根据当前语言获取默认国家/地区信息
|
||||
* @returns {{zone: string, name: string}} 返回国家区号和名称
|
||||
*/
|
||||
const getDefaultCountry = () => {
|
||||
let defaultCode = 'CN' // 默认中国大陆
|
||||
switch (locale.value) {
|
||||
@ -53,11 +58,20 @@ const getDefaultCountry = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const goCountryRegion=()=>{
|
||||
/**
|
||||
* 跳转到国家/地区选择页面
|
||||
*/
|
||||
const goCountryRegion = () => {
|
||||
router.push({
|
||||
path:'/countryRegion'
|
||||
path: '/countryRegion'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查表单是否完整填写
|
||||
* @param {Object} obj - 要检查的表单对象
|
||||
* @returns {boolean} 是否完整
|
||||
*/
|
||||
function isFormComplete(obj) {
|
||||
for (const key in obj) {
|
||||
if (typeof obj[key] === 'object' && obj[key] !== null) {
|
||||
@ -71,15 +85,25 @@ function isFormComplete(obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const getData=async ()=>{
|
||||
const res=await offlineQrcode({
|
||||
qrUid:qrUid.value
|
||||
})
|
||||
if (res.status===0){
|
||||
qrData.value=res.data
|
||||
/**
|
||||
* 获取线下二维码支付状态
|
||||
*/
|
||||
const getData = async () => {
|
||||
const res = await offlineQrcode({
|
||||
qrUid: qrUid.value
|
||||
})
|
||||
if (res.status === 0) {
|
||||
qrData.value = res.data
|
||||
}
|
||||
}
|
||||
const initData= async ()=>{
|
||||
|
||||
/**
|
||||
* 初始化页面数据
|
||||
* 1. 处理URL参数
|
||||
* 2. 检查支付状态(扫付款码场景)
|
||||
* 3. 设置默认国家/地区信息
|
||||
*/
|
||||
const initData = async () => {
|
||||
if (route.query.number){
|
||||
number.value=Number(route.query.number)
|
||||
}
|
||||
@ -90,7 +114,7 @@ const initData= async ()=>{
|
||||
if (number.value==2){
|
||||
await getData()
|
||||
if (qrData.value.payStatus===4){
|
||||
router.replace('/collectCode/payment')
|
||||
router.push('/collectCode/payment')
|
||||
}
|
||||
}
|
||||
if(!formData.value.countryCode){
|
||||
@ -101,7 +125,18 @@ const initData= async ()=>{
|
||||
formData.value.countryCode=route.query.zone
|
||||
}
|
||||
}
|
||||
const nextClick=async ()=>{
|
||||
|
||||
/**
|
||||
* 处理下一步按钮点击
|
||||
* 场景1(number=1): 扫号牌进入
|
||||
* - 验证表单完整性
|
||||
* - 检查用户号牌是否存在
|
||||
* - 根据国家区号判断签署方式(国内用法大大,国外直接签字)
|
||||
*
|
||||
* 场景2(number=2): 扫付款码进入
|
||||
* - 验证必填信息(手机、区号、用户名)
|
||||
*/
|
||||
const nextClick = async () => {
|
||||
//扫号牌
|
||||
if (number.value==1){
|
||||
if (!isFormComplete(formData.value)){
|
||||
|
@ -1,86 +1,139 @@
|
||||
<script setup>
|
||||
import pdfView from './pdfView/index.vue'
|
||||
import { contractView } from "~/api/goods/index.js"
|
||||
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
||||
import {signOffline} from "~/api/goods/index.js";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import { contractView, signOffline } from "~/api/goods/index.js"
|
||||
import { codeAuthStore } from "~/stores-collect-code/auth/index.js"
|
||||
import { useI18n } from "vue-i18n"
|
||||
import { fddInfo } from "@/api-collect-code/goods/index.js"
|
||||
import { showLoadingToast } from 'vant';
|
||||
definePageMeta({
|
||||
i18n: 'signature.protocol.title'
|
||||
})
|
||||
|
||||
const {t} =useI18n()
|
||||
const {formData,number,qrData}=codeAuthStore()
|
||||
const activeNames = ref([])
|
||||
const { t } = useI18n()
|
||||
const { formData, number, qrData } = codeAuthStore()
|
||||
const activeNames = ref('')
|
||||
const router = useRouter()
|
||||
const pmblUrl = ref('') // 存储拍卖笔录的URL
|
||||
const pmblUrl = ref('')
|
||||
|
||||
// 协议列表数据
|
||||
/**
|
||||
* 根据签署顺序(number)返回不同的协议列表
|
||||
* number = 1: 买家签署阶段,展示竞买协议、竞买须知、拍卖公告、拍卖规则
|
||||
* number = 2: 卖家签署阶段,展示拍卖成交确认书、拍卖笔录
|
||||
*/
|
||||
const protocolList = computed(() => {
|
||||
if(number.value==1){
|
||||
if (number.value === 1) {
|
||||
return [
|
||||
{ id: '4', title: t('signature.agreement.buyerAgreement'), pdfName: 'jmxy', type: 'local' },
|
||||
{ id: '3', title: t('signature.agreement.buyerGuide'), pdfName: 'jmxz', type: 'local' },
|
||||
{ id: '1', title: t('signature.agreement.notice'), pdfName: 'pmgg', type: 'local' },
|
||||
{ id: '2', title: t('signature.agreement.rules'), pdfName: 'pmgz', type: 'local' },
|
||||
]
|
||||
}else if(number.value==2) {
|
||||
} else if (number.value === 2) {
|
||||
return [
|
||||
{ id: '6', title: t('signature.agreement.transfer'), pdfName: 'pmyjqrs', type: 'local' },
|
||||
{ id: '5', title: t('signature.agreement.record'), pdfName: pmblUrl.value, type: 'remote' }
|
||||
]
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
// 获取拍卖笔录PDF
|
||||
/**
|
||||
* 获取拍卖笔录PDF
|
||||
* 通过拍品UUID获取拍卖笔录的查看地址
|
||||
*/
|
||||
const fetchPmblPdf = async () => {
|
||||
try {
|
||||
const res = await contractView({
|
||||
auctionArtworkUuid: qrData.value.auctionArtworkUuid,
|
||||
})
|
||||
pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中
|
||||
pmblUrl.value = res.data?.viewUrl
|
||||
} catch (error) {
|
||||
console.error('获取拍卖笔录失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 监听折叠面板变化
|
||||
/**
|
||||
* 折叠面板变化处理
|
||||
* 当打开拍卖笔录面板时,获取PDF地址
|
||||
*/
|
||||
const handleCollapseChange = (name) => {
|
||||
activeNames.value = name
|
||||
// 当打开拍卖笔录时获取PDF
|
||||
if (name === '5' && !pmblUrl.value) {
|
||||
fetchPmblPdf()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认签署处理
|
||||
* 1. 获取用户法大大认证信息
|
||||
* 2. 根据用户类型和地区判断签署流程:
|
||||
* - 特殊用户且isMainland=1: 走大陆签署流程
|
||||
* - 特殊用户且isMainland=0: 走非大陆签署流程
|
||||
* - 普通用户:
|
||||
* - 大陆用户(countryCode=86且身份证): 走大陆签署流程
|
||||
* - 其他用户: 走非大陆签署流程
|
||||
*/
|
||||
const confirm = async () => {
|
||||
const toast= showLoadingToast({
|
||||
message: '加载中...',
|
||||
forbidClick: true,
|
||||
});
|
||||
|
||||
try {
|
||||
const fddResponse = await fddInfo({ phone: formData.value.phone })
|
||||
|
||||
if (fddResponse.status === 0) {
|
||||
const { userId, isMainland } = fddResponse.data
|
||||
|
||||
const confirm=async ()=>{
|
||||
if (formData.value.countryCode==='86'&&formData.value.cardType===1){
|
||||
const res=await signOffline({
|
||||
userInfo:formData.value,
|
||||
auctionArtworkUuid:qrData.value.auctionArtworkUuid,
|
||||
signOrder:Number(number.value),
|
||||
})
|
||||
if (res.status===0){
|
||||
window.location.href=res.data.fddVerifyUrl
|
||||
}
|
||||
}else {
|
||||
// 特殊用户处理逻辑
|
||||
if (userId) {
|
||||
if (isMainland === 1) {
|
||||
await handleMainlandSign()
|
||||
} else {
|
||||
router.push('/collectCode/signature/panel')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 普通用户处理逻辑
|
||||
const isMainlandUser = formData.value.countryCode === '86' && formData.value.cardType === 1
|
||||
if (isMainlandUser) {
|
||||
await handleMainlandSign()
|
||||
} else {
|
||||
router.push('/collectCode/signature/panel')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('签署确认失败:', error)
|
||||
}finally{
|
||||
toast.close();
|
||||
}
|
||||
}
|
||||
const goSignature = () => {
|
||||
router.push({
|
||||
path: '/signature/panel'
|
||||
|
||||
/**
|
||||
* 处理大陆用户签署流程
|
||||
*/
|
||||
const handleMainlandSign = async () => {
|
||||
const res = await signOffline({
|
||||
userInfo: formData.value,
|
||||
auctionArtworkUuid: qrData.value.auctionArtworkUuid,
|
||||
signOrder: Number(number.value),
|
||||
})
|
||||
|
||||
if (res.status === 0) {
|
||||
window.location.href = res.data.fddVerifyUrl
|
||||
}
|
||||
}
|
||||
</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"
|
||||
@ -104,6 +157,7 @@ const goSignature = () => {
|
||||
</van-collapse-item>
|
||||
</van-collapse>
|
||||
|
||||
<!-- 底部确认按钮 -->
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
||||
<van-button
|
||||
color="#2B53AC"
|
||||
|
@ -21,7 +21,7 @@ await getAuctionDetail()
|
||||
<template>
|
||||
<div class="grow-1 flex flex-col">
|
||||
<client-only>
|
||||
<div class="relative" @click="changeLive">
|
||||
<div class="relative bg-#000" @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>
|
||||
|
@ -183,7 +183,7 @@ const tipOpen = () => {
|
||||
<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{{ Number(auctionData.artwork.index+25000) }}</div>
|
||||
<div class="mr-11px whitespace-nowrap">Lot{{ Number(auctionData.artwork.index+25000) }}</div>
|
||||
<div class="mr-10px truncate">{{ auctionData.artwork.name }}</div>
|
||||
<div class="whitespace-nowrap">{{ t('live_room.start') }}</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,5 @@
|
||||
<script setup>
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import Vcode from "vue3-puzzle-vcode";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import countryCode from '../countryRegion/data/index.js'
|
||||
import {senCode, userLogin,userCaptcha,userCaptchaValidate,} from "@/api/auth/index.js";
|
||||
@ -103,7 +102,13 @@ blockY:0
|
||||
const getCode =async () => {
|
||||
isShow.value=true
|
||||
loadingRef.value.loading1=true
|
||||
const res=await userCaptcha(captcha.value)
|
||||
const res=await userCaptcha({
|
||||
canvasWidth:captcha.value.canvasWidth,
|
||||
canvasHeight:captcha.value.canvasHeight,
|
||||
blockWidth:captcha.value.blockWidth,
|
||||
blockHeight:captcha.value.blockHeight,
|
||||
place:captcha.value.place
|
||||
})
|
||||
if (res.status===0){
|
||||
captcha.value.canvasSrc=`data:image/png;base64,${res.data.canvasSrc}`
|
||||
captcha.value.blockSrc=`data:image/png;base64,${res.data.blockSrc}`
|
||||
|
@ -2,6 +2,7 @@
|
||||
import {publicStore} from "@/stores/public/index.js";
|
||||
import {useI18n} from 'vue-i18n'
|
||||
import {outBuyList} from "@/api-public/public/index.js";
|
||||
import { onUnmounted } from 'vue'
|
||||
|
||||
const {auctionData} = publicStore()
|
||||
function formatThousands(num) {
|
||||
@ -26,12 +27,29 @@ const headList=[
|
||||
}
|
||||
]
|
||||
const buyList=ref([])
|
||||
const timer = ref(null)
|
||||
|
||||
const headItem=(statusCode)=>{
|
||||
return headList.find(x=>x.value===statusCode)
|
||||
}
|
||||
|
||||
const fetchBuyList = async () => {
|
||||
const res = await outBuyList({uuid: auctionData.value.uuid})
|
||||
buyList.value = res.data.buys
|
||||
}
|
||||
|
||||
onMounted(async()=>{
|
||||
const res=await outBuyList({uuid:auctionData.value.uuid})
|
||||
buyList.value=res.data.buys
|
||||
await fetchBuyList()
|
||||
timer.value = setInterval(async () => {
|
||||
await fetchBuyList()
|
||||
}, 10000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (timer.value) {
|
||||
clearInterval(timer.value)
|
||||
timer.value = null
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -44,17 +62,16 @@ onMounted(async()=>{
|
||||
|
||||
<template v-if="buyList?.length>0">
|
||||
<div v-for="(item, index) in buyList" :key="index" class="flex flex-shrink-0">
|
||||
<!-- 将每列宽度改为相等(约86px),添加文本溢出处理 -->
|
||||
<div class="text-start shrink-0 w-1/4 truncate" :style="`color: ${headItem(item.statusCode).color}`">
|
||||
<div class="text-start shrink-0 w-1/6 break-words" :style="`color: ${headItem(item.statusCode).color}`">
|
||||
{{ headItem(item.statusCode).label }}
|
||||
</div>
|
||||
<div class="text-start shrink-0 w-1/4 truncate">
|
||||
<div class="text-start shrink-0 w-[28%] break-words">
|
||||
{{ item.auctionType==='local'? $t('live_room.spot'):$t('live_room.network') }}
|
||||
</div>
|
||||
<div class="text-start shrink-0 w-1/4 truncate">
|
||||
<div class="text-start shrink-0 w-[28%] break-words">
|
||||
{{ item.createdAt }}
|
||||
</div>
|
||||
<div class="text-start shrink-0 w-1/4 truncate">
|
||||
<div class="text-start shrink-0 w-[28%] break-words">
|
||||
{{item.baseCurrency}}{{ formatThousands(item.baseMoney) }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -49,6 +49,7 @@ const initializePlayer = async () => {
|
||||
height: '100%', //容器的大小
|
||||
skinLayout: false,
|
||||
controlBarVisibility: 'never',
|
||||
env: 'SEA' ,
|
||||
license: {
|
||||
domain: "szjixun.cn",
|
||||
key: "OProxmWaOZ2XVHXLtf4030126521c43429403194970aa8af9"
|
||||
@ -119,5 +120,7 @@ onMounted(async () => {
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
:deep(.prism-license-watermark) {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
@ -27,6 +27,7 @@ export const goodStore = createGlobalState(() => {
|
||||
|
||||
// 获取拍卖详情
|
||||
const getAuctionDetail = async () => {
|
||||
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await defaultDetail({})
|
||||
|
@ -493,7 +493,7 @@
|
||||
"detail": "Lot Details",
|
||||
"description": "Lot Description"
|
||||
},
|
||||
"lotDetail": "LOT Details",
|
||||
"lotDetail": "Lot Details",
|
||||
"refresh": {
|
||||
"success": "Refresh successful",
|
||||
"noMore": "No more data"
|
||||
|
@ -1,5 +1,6 @@
|
||||
import dotenv from 'dotenv'
|
||||
import process from 'node:process'
|
||||
import imagemin from 'vite-plugin-imagemin'
|
||||
import { currentLocales } from './i18n/i18n'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
@ -29,13 +30,8 @@ export default defineNuxtConfig({
|
||||
modules: [
|
||||
'@vant/nuxt',
|
||||
'@unocss/nuxt',
|
||||
'@nuxtjs/i18n',
|
||||
'@nuxtjs/i18n'
|
||||
],
|
||||
image: {
|
||||
provider: 'ipx',
|
||||
format: ['webp'],
|
||||
quality: 80,
|
||||
},
|
||||
runtimeConfig: {
|
||||
// 私有配置,只有在服务端可用
|
||||
apiSecret: process.env.NUXT_API_SECRET,
|
||||
@ -115,6 +111,13 @@ export default defineNuxtConfig({
|
||||
vite: {
|
||||
build: {
|
||||
target: 'esnext',
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true, // 移除 console
|
||||
drop_debugger: true, // 移除 debugger
|
||||
}
|
||||
}
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
@ -123,6 +126,35 @@ export default defineNuxtConfig({
|
||||
'is-https',
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
imagemin({
|
||||
gifsicle: {
|
||||
optimizationLevel: 7,
|
||||
interlaced: false
|
||||
},
|
||||
optipng: {
|
||||
optimizationLevel: 7
|
||||
},
|
||||
mozjpeg: {
|
||||
quality: 70
|
||||
},
|
||||
pngquant: {
|
||||
quality: [0.8, 0.9],
|
||||
speed: 4
|
||||
},
|
||||
svgo: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'removeViewBox'
|
||||
},
|
||||
{
|
||||
name: 'removeEmptyAttrs',
|
||||
active: false
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
experimental: {
|
||||
|
@ -53,7 +53,8 @@
|
||||
"sass-loader": "^16.0.4",
|
||||
"sharp": "^0.33.5",
|
||||
"typescript": "~5.7.2",
|
||||
"vant": "^4.9.15"
|
||||
"vant": "^4.9.15",
|
||||
"vite-plugin-imagemin": "^0.6.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"peerDependencyRules": {
|
||||
|
2161
pnpm-lock.yaml
2161
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user