Merge branch 'main' into dev
This commit is contained in:
commit
85fb2c3dc4
@ -29,3 +29,35 @@ export async function userArtworks(data) {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
export async function fddInfo(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/contract/fdd-info',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function sessionUserNoCreate(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/auction/sessionUserNo/create',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function offlineQrcode(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/offlineQrcode/info',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function createOrder(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/offlineQrcode/createOrder',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
@ -6,25 +6,26 @@ import {codeAuthStore} from "@/stores-collect-code/auth/index.js"
|
|||||||
let httpStatusErrorHandler
|
let httpStatusErrorHandler
|
||||||
let http
|
let http
|
||||||
|
|
||||||
// HTTP 状态码映射
|
// HTTP 状态码映射 - 使用i18n国际化
|
||||||
const HTTP_STATUS_MAP = {
|
|
||||||
400: '请求参数错误',
|
|
||||||
401: '未授权或登录过期',
|
|
||||||
403: '访问被禁止',
|
|
||||||
404: '请求的资源不存在',
|
|
||||||
500: '服务器内部错误',
|
|
||||||
502: '网关错误',
|
|
||||||
503: '服务暂时不可用',
|
|
||||||
504: '网关超时'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupHttp() {
|
export function setupHttp() {
|
||||||
if (http) return http
|
if (http) return http
|
||||||
const {token}= codeAuthStore()
|
const {token}= codeAuthStore()
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const baseURL = config.public.NUXT_PUBLIC_API_COLLECT_CODE
|
const baseURL = config.public.NUXT_PUBLIC_API_COLLECT_CODE
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const i18n = useNuxtApp().$i18n
|
||||||
|
|
||||||
|
// 国际化的HTTP状态码映射
|
||||||
|
const HTTP_STATUS_MAP = {
|
||||||
|
400: i18n.t('http.error.badRequest'),
|
||||||
|
401: i18n.t('http.error.unauthorized'),
|
||||||
|
403: i18n.t('http.error.forbidden'),
|
||||||
|
404: i18n.t('http.error.notFound'),
|
||||||
|
500: i18n.t('http.error.serverError'),
|
||||||
|
502: i18n.t('http.error.badGateway'),
|
||||||
|
503: i18n.t('http.error.serviceUnavailable'),
|
||||||
|
504: i18n.t('http.error.gatewayTimeout')
|
||||||
|
}
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
baseURL,
|
baseURL,
|
||||||
@ -42,7 +43,8 @@ export function setupHttp() {
|
|||||||
// 添加 token
|
// 添加 token
|
||||||
options.headers = {
|
options.headers = {
|
||||||
...options.headers,
|
...options.headers,
|
||||||
Authorization: token.value
|
Authorization: token.value,
|
||||||
|
'accept-language': i18n.locale.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET 请求添加时间戳防止缓存
|
// GET 请求添加时间戳防止缓存
|
||||||
@ -60,12 +62,12 @@ export function setupHttp() {
|
|||||||
|
|
||||||
// 处理业务错误
|
// 处理业务错误
|
||||||
if (data.status === 1) {
|
if (data.status === 1) {
|
||||||
message.error(data.msg || '操作失败')
|
message.error(data.msg || i18n.t('http.error.operationFailed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理登录失效
|
// 处理登录失效
|
||||||
if (data.status === 401) {
|
if (data.status === 401) {
|
||||||
message.error('登录已过期,请重新登录')
|
message.error(i18n.t('http.error.loginExpired'))
|
||||||
token.value = '' // 清除 token
|
token.value = '' // 清除 token
|
||||||
router.replace('/collectCode/login')
|
router.replace('/collectCode/login')
|
||||||
}
|
}
|
||||||
@ -77,14 +79,14 @@ export function setupHttp() {
|
|||||||
async onResponseError({ response, request }) {
|
async onResponseError({ response, request }) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
if (!response) {
|
if (!response) {
|
||||||
message.error('网络连接失败,请检查网络设置')
|
message.error(i18n.t('http.error.networkError'))
|
||||||
return Promise.reject(new Error('网络错误'))
|
return Promise.reject(new Error(i18n.t('http.error.networkError')))
|
||||||
}
|
}
|
||||||
const status = response.status
|
const status = response.status
|
||||||
const data = response._data
|
const data = response._data
|
||||||
|
|
||||||
// 处理 HTTP 状态错误
|
// 处理 HTTP 状态错误
|
||||||
const errorMessage = data.msg || HTTP_STATUS_MAP[status] || '请求失败'
|
const errorMessage = data.msg || HTTP_STATUS_MAP[status] || i18n.t('http.error.requestFailed')
|
||||||
|
|
||||||
if (Array.isArray(data.msg)) {
|
if (Array.isArray(data.msg)) {
|
||||||
data.msg.forEach(item => {
|
data.msg.forEach(item => {
|
||||||
@ -112,7 +114,7 @@ export function injectHttpStatusErrorHandler(handler) {
|
|||||||
|
|
||||||
export function getHttp() {
|
export function getHttp() {
|
||||||
if (!http) {
|
if (!http) {
|
||||||
throw new Error('HTTP client not initialized. Call setupHttp first.')
|
throw new Error(useNuxtApp().$i18n.t('http.error.httpNotInitialized'))
|
||||||
}
|
}
|
||||||
return http
|
return http
|
||||||
}
|
}
|
||||||
|
@ -54,3 +54,51 @@ export async function logSendlog(data) {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
export async function signOnline(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/contract/sign-online',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function signOffline(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/contract/sign-offline',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function fddCheck(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/m/user/fdd/check',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function createBuyOrder(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/m/auction/createBuyOrder',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function orderQuery(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/payment/order/query',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function contractView(data) {
|
||||||
|
|
||||||
|
return await request( {
|
||||||
|
url:'/api/v1/contract/contract-view',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
@ -6,25 +6,26 @@ import {authStore} from "@/stores/auth/index.js"
|
|||||||
let httpStatusErrorHandler
|
let httpStatusErrorHandler
|
||||||
let http
|
let http
|
||||||
|
|
||||||
// HTTP 状态码映射
|
// HTTP 状态码映射 - 使用i18n国际化
|
||||||
const HTTP_STATUS_MAP = {
|
|
||||||
400: '请求参数错误',
|
|
||||||
401: '未授权或登录过期',
|
|
||||||
403: '访问被禁止',
|
|
||||||
404: '请求的资源不存在',
|
|
||||||
500: '服务器内部错误',
|
|
||||||
502: '网关错误',
|
|
||||||
503: '服务暂时不可用',
|
|
||||||
504: '网关超时'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setupHttp() {
|
export function setupHttp() {
|
||||||
if (http) return http
|
if (http) return http
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const baseURL = config.public.NUXT_PUBLIC_API_BASE
|
const baseURL = config.public.NUXT_PUBLIC_API_BASE
|
||||||
const { token } = authStore()
|
const { token } = authStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const i18n = useNuxtApp().$i18n
|
||||||
|
|
||||||
|
// 国际化的HTTP状态码映射
|
||||||
|
const HTTP_STATUS_MAP = {
|
||||||
|
400: i18n.t('http.error.badRequest'),
|
||||||
|
401: i18n.t('http.error.unauthorized'),
|
||||||
|
403: i18n.t('http.error.forbidden'),
|
||||||
|
404: i18n.t('http.error.notFound'),
|
||||||
|
500: i18n.t('http.error.serverError'),
|
||||||
|
502: i18n.t('http.error.badGateway'),
|
||||||
|
503: i18n.t('http.error.serviceUnavailable'),
|
||||||
|
504: i18n.t('http.error.gatewayTimeout')
|
||||||
|
}
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
baseURL,
|
baseURL,
|
||||||
@ -33,7 +34,6 @@ export function setupHttp() {
|
|||||||
retry: 3,
|
retry: 3,
|
||||||
retryDelay: 1000,
|
retryDelay: 1000,
|
||||||
}
|
}
|
||||||
|
|
||||||
http = ofetch.create({
|
http = ofetch.create({
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
|
|
||||||
@ -42,8 +42,10 @@ export function setupHttp() {
|
|||||||
// 添加 token
|
// 添加 token
|
||||||
options.headers = {
|
options.headers = {
|
||||||
...options.headers,
|
...options.headers,
|
||||||
Authorization: token.value
|
Authorization: token.value,
|
||||||
}
|
'accept-language':i18n.locale.value
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// GET 请求添加时间戳防止缓存
|
// GET 请求添加时间戳防止缓存
|
||||||
if (request.toLowerCase().includes('get')) {
|
if (request.toLowerCase().includes('get')) {
|
||||||
@ -60,12 +62,12 @@ export function setupHttp() {
|
|||||||
|
|
||||||
// 处理业务错误
|
// 处理业务错误
|
||||||
if (data.status === 1) {
|
if (data.status === 1) {
|
||||||
message.error(data.msg || '操作失败')
|
message.error(data.msg || i18n.t('http.error.operationFailed'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理登录失效
|
// 处理登录失效
|
||||||
if (data.status === 401) {
|
if (data.status === 401) {
|
||||||
message.error('登录已过期,请重新登录')
|
message.error(i18n.t('http.error.loginExpired'))
|
||||||
token.value = '' // 清除 token
|
token.value = '' // 清除 token
|
||||||
router.replace('/login')
|
router.replace('/login')
|
||||||
}
|
}
|
||||||
@ -77,14 +79,14 @@ export function setupHttp() {
|
|||||||
async onResponseError({ response, request }) {
|
async onResponseError({ response, request }) {
|
||||||
// 网络错误
|
// 网络错误
|
||||||
if (!response) {
|
if (!response) {
|
||||||
message.error('网络连接失败,请检查网络设置')
|
message.error(i18n.t('http.error.networkError'))
|
||||||
return Promise.reject(new Error('网络错误'))
|
return Promise.reject(new Error(i18n.t('http.error.networkError')))
|
||||||
}
|
}
|
||||||
const status = response.status
|
const status = response.status
|
||||||
const data = response._data
|
const data = response._data
|
||||||
|
|
||||||
// 处理 HTTP 状态错误
|
// 处理 HTTP 状态错误
|
||||||
const errorMessage = data.msg || HTTP_STATUS_MAP[status] || '请求失败'
|
const errorMessage = data.msg || HTTP_STATUS_MAP[status] || i18n.t('http.error.requestFailed')
|
||||||
|
|
||||||
if (Array.isArray(data.msg)) {
|
if (Array.isArray(data.msg)) {
|
||||||
data.msg.forEach(item => {
|
data.msg.forEach(item => {
|
||||||
@ -112,7 +114,7 @@ export function injectHttpStatusErrorHandler(handler) {
|
|||||||
|
|
||||||
export function getHttp() {
|
export function getHttp() {
|
||||||
if (!http) {
|
if (!http) {
|
||||||
throw new Error('HTTP client not initialized. Call setupHttp first.')
|
throw new Error(useNuxtApp().$i18n.t('http.error.httpNotInitialized'))
|
||||||
}
|
}
|
||||||
return http
|
return http
|
||||||
}
|
}
|
||||||
|
28
app/app.vue
28
app/app.vue
@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {useI18n} from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import {message} from '@/components/x-message/useMessage.js'
|
import {message} from '@/components/x-message/useMessage.js'
|
||||||
|
import {hideMinWindow1} from "@/components/floatingBubble/floating.js";
|
||||||
// message.success('success')
|
// message.success('success')
|
||||||
useHead({
|
useHead({
|
||||||
title: useI18n().t('appSetting.appName'),
|
title: useI18n().t('appSetting.appName'),
|
||||||
@ -15,14 +16,17 @@ useHead({
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const slideDirection = ref('slide-left')
|
const slideDirection = ref('slide-left')
|
||||||
|
const { locale } = useI18n()
|
||||||
|
// locale.value = 'en-US'
|
||||||
// 记录路由历史
|
// 记录路由历史
|
||||||
const routeHistory = ref([])
|
const routeHistory = ref([])
|
||||||
|
|
||||||
router.beforeEach((to, from) => {
|
router.beforeEach((to, from) => {
|
||||||
// 记录路由历史
|
// 记录路由历史
|
||||||
routeHistory.value.push(from.path)
|
routeHistory.value.push(from.path)
|
||||||
|
if (to.path==='/'){
|
||||||
|
hideMinWindow1()
|
||||||
|
}
|
||||||
// 如果是返回操作(在历史记录中找到目标路由)
|
// 如果是返回操作(在历史记录中找到目标路由)
|
||||||
if (routeHistory.value.includes(to.path)) {
|
if (routeHistory.value.includes(to.path)) {
|
||||||
slideDirection.value = 'slide-right'
|
slideDirection.value = 'slide-right'
|
||||||
@ -39,15 +43,17 @@ provide('slideDirection', slideDirection)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VanConfigProvider>
|
<client-only>
|
||||||
<NuxtLoadingIndicator
|
<VanConfigProvider>
|
||||||
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)"/>
|
<NuxtLoadingIndicator
|
||||||
<NuxtLayout>
|
color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)"/>
|
||||||
<NuxtPage :transition="{
|
<NuxtLayout>
|
||||||
|
<NuxtPage :transition="{
|
||||||
name: slideDirection
|
name: slideDirection
|
||||||
}"/>
|
}"/>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</VanConfigProvider>
|
</VanConfigProvider>
|
||||||
|
</client-only>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -82,5 +88,7 @@ provide('slideDirection', slideDirection)
|
|||||||
:root {
|
:root {
|
||||||
--safe-area-inset-bottom: env(safe-area-inset-bottom);
|
--safe-area-inset-bottom: env(safe-area-inset-bottom);
|
||||||
}
|
}
|
||||||
|
.van-cell.van-field .van-cell__title, .van-cell__value{
|
||||||
|
flex: initial;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,11 +1,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useAppHeaderRouteNames as routeWhiteList } from '@/config'
|
import { useAppHeaderRouteNames as routeWhiteList } from '@/config'
|
||||||
import { liveStore } from "@/stores/live/index.js";
|
import { liveStore } from "@/stores/live/index.js";
|
||||||
|
import {goodStore} from "~/stores/goods/index.js";
|
||||||
const { fullLive } = liveStore()
|
const { fullLive } = liveStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const {auctionDetail} = goodStore();
|
||||||
function onBack() {
|
function onBack() {
|
||||||
if (fullLive.value){
|
if (fullLive.value&&route.name==='index'){
|
||||||
fullLive.value=false
|
fullLive.value=false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -29,7 +31,7 @@ const subTitle = computed(() => {
|
|||||||
return route.meta.subTitle ? t(route.meta.subTitle) : ''
|
return route.meta.subTitle ? t(route.meta.subTitle) : ''
|
||||||
})
|
})
|
||||||
const showLeftArrow = computed(() => route.name && routeWhiteList.includes(route.name))
|
const showLeftArrow = computed(() => route.name && routeWhiteList.includes(route.name))
|
||||||
|
console.log('route.name',route.name)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -40,11 +42,9 @@ const showLeftArrow = computed(() => route.name && routeWhiteList.includes(route
|
|||||||
placeholder clickable fixed
|
placeholder clickable fixed
|
||||||
@click-left="onBack"
|
@click-left="onBack"
|
||||||
>
|
>
|
||||||
<template #title v-if="route.meta.i18n==='menu.goods'">
|
<template #title v-if="route.meta.i18n==='menu.home'">
|
||||||
|
|
||||||
<div class="flex flex-col items-center justify-center">
|
<div class="flex flex-col items-center justify-center">
|
||||||
<div class="text-#000000 text-17px mb-5px font-600">{{ title }}</div>
|
<div class="text-#000000 text-17px mb-5px font-600">{{ auctionDetail.title }}</div>
|
||||||
<div class="text-#939393 text-10px line-height-none font-100">{{subTitle}}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VanNavBar>
|
</VanNavBar>
|
||||||
|
@ -1,181 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="signature-pad-container">
|
|
||||||
<canvas
|
|
||||||
ref="canvasRef"
|
|
||||||
class="signature-pad"
|
|
||||||
:style="{
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
border: '1px solid #e5e5e5',
|
|
||||||
borderRadius: '4px'
|
|
||||||
}"
|
|
||||||
@touchstart="handleStart"
|
|
||||||
@touchmove="handleMove"
|
|
||||||
@touchend="handleEnd"
|
|
||||||
@mousedown="handleStart"
|
|
||||||
@mousemove="handleMove"
|
|
||||||
@mouseup="handleEnd"
|
|
||||||
@mouseleave="handleEnd"
|
|
||||||
></canvas>
|
|
||||||
<div class="signature-controls">
|
|
||||||
<van-button
|
|
||||||
type="default"
|
|
||||||
size="small"
|
|
||||||
@click="clearCanvas"
|
|
||||||
>清除</van-button>
|
|
||||||
<van-button
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
@click="handleConfirm"
|
|
||||||
>确认</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'change'])
|
|
||||||
|
|
||||||
const canvasRef = ref(null)
|
|
||||||
const ctx = ref(null)
|
|
||||||
const isDrawing = ref(false)
|
|
||||||
const lastX = ref(0)
|
|
||||||
const lastY = ref(0)
|
|
||||||
const LINE_WIDTH = 2 // 固定画笔粗细
|
|
||||||
|
|
||||||
// 初始化画布
|
|
||||||
const initCanvas = () => {
|
|
||||||
const canvas = canvasRef.value
|
|
||||||
const dpr = window.devicePixelRatio || 1
|
|
||||||
const rect = canvas.getBoundingClientRect()
|
|
||||||
|
|
||||||
// 设置画布的实际大小
|
|
||||||
canvas.width = rect.width * dpr
|
|
||||||
canvas.height = rect.height * dpr
|
|
||||||
|
|
||||||
ctx.value = canvas.getContext('2d')
|
|
||||||
|
|
||||||
// 缩放画布以匹配设备像素比
|
|
||||||
ctx.value.scale(dpr, dpr)
|
|
||||||
ctx.value.lineCap = 'round'
|
|
||||||
ctx.value.lineJoin = 'round'
|
|
||||||
ctx.value.strokeStyle = '#000'
|
|
||||||
ctx.value.lineWidth = LINE_WIDTH
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始绘制
|
|
||||||
const handleStart = (e) => {
|
|
||||||
e.preventDefault() // 防止页面滚动
|
|
||||||
isDrawing.value = true
|
|
||||||
const point = getPoint(e)
|
|
||||||
lastX.value = point.x
|
|
||||||
lastY.value = point.y
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绘制中
|
|
||||||
const handleMove = (e) => {
|
|
||||||
if (!isDrawing.value) return
|
|
||||||
e.preventDefault() // 防止页面滚动
|
|
||||||
|
|
||||||
const point = getPoint(e)
|
|
||||||
ctx.value.beginPath()
|
|
||||||
ctx.value.moveTo(lastX.value, lastY.value)
|
|
||||||
ctx.value.lineTo(point.x, point.y)
|
|
||||||
ctx.value.stroke()
|
|
||||||
|
|
||||||
lastX.value = point.x
|
|
||||||
lastY.value = point.y
|
|
||||||
}
|
|
||||||
|
|
||||||
// 结束绘制
|
|
||||||
const handleEnd = () => {
|
|
||||||
isDrawing.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取触点坐标
|
|
||||||
const getPoint = (e) => {
|
|
||||||
const canvas = canvasRef.value
|
|
||||||
const rect = canvas.getBoundingClientRect()
|
|
||||||
const dpr = window.devicePixelRatio || 1
|
|
||||||
const event = e.touches ? e.touches[0] : e
|
|
||||||
|
|
||||||
// 计算实际的触点位置
|
|
||||||
const x = (event.clientX - rect.left)
|
|
||||||
const y = (event.clientY - rect.top)
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: x,
|
|
||||||
y: y
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清除画布
|
|
||||||
const clearCanvas = () => {
|
|
||||||
const canvas = canvasRef.value
|
|
||||||
ctx.value.clearRect(0, 0, canvas.width, canvas.height)
|
|
||||||
emit('update:modelValue', '')
|
|
||||||
emit('change', '')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确认并生成图片
|
|
||||||
const handleConfirm = () => {
|
|
||||||
const canvas = canvasRef.value
|
|
||||||
const imageData = canvas.toDataURL('image/png')
|
|
||||||
emit('update:modelValue', imageData)
|
|
||||||
emit('change', imageData)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听屏幕旋转
|
|
||||||
const handleResize = () => {
|
|
||||||
const canvas = canvasRef.value
|
|
||||||
const imageData = canvas.toDataURL('image/png')
|
|
||||||
initCanvas()
|
|
||||||
// 恢复之前的内容
|
|
||||||
const img = new Image()
|
|
||||||
img.onload = () => {
|
|
||||||
ctx.value.drawImage(img, 0, 0, canvas.width, canvas.height)
|
|
||||||
}
|
|
||||||
img.src = imageData
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
initCanvas()
|
|
||||||
window.addEventListener('resize', handleResize)
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
window.removeEventListener('resize', handleResize)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.signature-pad-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-pad {
|
|
||||||
flex: 1;
|
|
||||||
touch-action: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.signature-controls {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 16px;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
</style>
|
|
87
app/components/floatingBubble/floating.js
Normal file
87
app/components/floatingBubble/floating.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
* 浮动气泡窗口管理模块
|
||||||
|
* 提供创建和销毁浮动气泡窗口的功能
|
||||||
|
*/
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
import MinWindow from '@/components/floatingBubble/index.vue'
|
||||||
|
|
||||||
|
// 全局单例状态管理
|
||||||
|
let minWindowInstance = null // 组件实例引用
|
||||||
|
let minWindowApp = null // Vue应用实例
|
||||||
|
let container = null // DOM容器元素
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建并显示浮动气泡窗口
|
||||||
|
* @param {Object} props - 传递给浮动气泡组件的属性
|
||||||
|
* @returns {Object|null} 返回组件实例或null(服务端渲染时)
|
||||||
|
*/
|
||||||
|
export const showMinWindow1 = (props = {}) => {
|
||||||
|
// 服务端渲染时直接返回
|
||||||
|
console.log('!process.client',!process.client)
|
||||||
|
if (!process.client) return null
|
||||||
|
|
||||||
|
// 如果实例已存在,避免重复创建
|
||||||
|
if (minWindowInstance) {
|
||||||
|
return minWindowInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 清理可能存在的残留容器
|
||||||
|
const existingContainer = document.querySelector('.floating-bubble-container')
|
||||||
|
if (existingContainer) {
|
||||||
|
document.body.removeChild(existingContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的容器元素
|
||||||
|
container = document.createElement('div')
|
||||||
|
container.className = 'floating-bubble-container'
|
||||||
|
document.body.appendChild(container)
|
||||||
|
|
||||||
|
// 创建Vue应用实例
|
||||||
|
const app = createApp(MinWindow, props)
|
||||||
|
minWindowApp = app
|
||||||
|
minWindowInstance = app.mount(container)
|
||||||
|
|
||||||
|
return minWindowInstance
|
||||||
|
} catch (error) {
|
||||||
|
console.error('创建浮动气泡时发生错误:', error)
|
||||||
|
// 发生错误时确保清理资源
|
||||||
|
hideMinWindow1()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁浮动气泡窗口
|
||||||
|
* 清理所有相关资源和DOM元素
|
||||||
|
*/
|
||||||
|
export const hideMinWindow1 = () => {
|
||||||
|
console.log('!minWindowApp && !container', !minWindowApp && !container);
|
||||||
|
|
||||||
|
if (!minWindowApp && !container) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 卸载Vue应用
|
||||||
|
if (minWindowApp) {
|
||||||
|
minWindowApp.unmount()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除DOM容器
|
||||||
|
if (container && document.body.contains(container)) {
|
||||||
|
document.body.removeChild(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理可能残留的其他容器
|
||||||
|
const existingContainer = document.querySelector('.floating-bubble-container')
|
||||||
|
if (existingContainer) {
|
||||||
|
document.body.removeChild(existingContainer)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清理浮动气泡时发生错误:', error)
|
||||||
|
} finally {
|
||||||
|
// 重置所有状态
|
||||||
|
minWindowApp = null
|
||||||
|
minWindowInstance = null
|
||||||
|
container = null
|
||||||
|
}
|
||||||
|
}
|
52
app/components/floatingBubble/index.vue
Normal file
52
app/components/floatingBubble/index.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<!--
|
||||||
|
浮动气泡组件
|
||||||
|
提供一个可拖拽的浮动按钮,支持自定义点击事件和自动销毁功能
|
||||||
|
-->
|
||||||
|
<script setup>
|
||||||
|
import { watch, onUnmounted } from 'vue'
|
||||||
|
import { hideMinWindow1 } from './floating'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 组件属性定义
|
||||||
|
const props = defineProps({
|
||||||
|
/** 点击气泡时的回调函数 */
|
||||||
|
onClick: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
/** 气泡文本内容(可选,默认使用国际化文本) */
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
// 路由变化监听器:当用户返回首页时自动销毁气泡
|
||||||
|
|
||||||
|
// 组件卸载时自动清理资源
|
||||||
|
onUnmounted(() => {
|
||||||
|
hideMinWindow1()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<van-floating-bubble
|
||||||
|
axis="xy"
|
||||||
|
magnetic="x"
|
||||||
|
:offset="{ x: 300, y: 50 }"
|
||||||
|
@click="onClick"
|
||||||
|
>
|
||||||
|
{{ text || t('floatingBubble.backToLive') }}
|
||||||
|
</van-floating-bubble>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.van-floating-bubble {
|
||||||
|
width: 70px;
|
||||||
|
height: 70px;
|
||||||
|
border-radius: 5px!important;
|
||||||
|
}
|
||||||
|
</style>
|
@ -8,7 +8,20 @@ const props = defineProps({
|
|||||||
default: null
|
default: null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const filteredPriceRules = computed(() => {
|
||||||
|
if (!props.detailInfo?.priceRules) return []
|
||||||
|
|
||||||
|
// 找到第一个price为空的索引
|
||||||
|
const emptyIndex = props.detailInfo.priceRules.findIndex(item => !item.price)
|
||||||
|
|
||||||
|
if (emptyIndex === -1) {
|
||||||
|
// 如果没有空价格,返回全部
|
||||||
|
return props.detailInfo.priceRules
|
||||||
|
} else {
|
||||||
|
// 如果有空价格,只返回到空价格之前的数据
|
||||||
|
return props.detailInfo.priceRules.slice(0, emptyIndex)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -20,32 +33,47 @@ const props = defineProps({
|
|||||||
<div class="text-[#000] text-[16px] mb-[12px]">{{detailInfo?.artworkTitle}}</div>
|
<div class="text-[#000] text-[16px] mb-[12px]">{{detailInfo?.artworkTitle}}</div>
|
||||||
<div class="text-#575757 text-[14px] pb-8px">
|
<div class="text-#575757 text-[14px] pb-8px">
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px]">作者:</div>
|
<div class="w-[70px]">{{$t('detail.text1')}}:</div>
|
||||||
<div>{{detailInfo?.artwork?.artistName??'-'}}</div>
|
<div>{{detailInfo?.artwork?.artistName??'-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px] flex-shrink-0">总平尺数:</div>
|
<div class="w-[70px] flex-shrink-0">{{$t('detail.text2')}}:</div>
|
||||||
<div>{{detailInfo?.artwork?.ruler??'-'}}</div>
|
<div>{{detailInfo?.artwork?.ruler??'-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px] flex-shrink-0">长*宽:</div>
|
<div class="w-[70px] flex-shrink-0">{{$t('detail.text3')}}*{{$t('detail.text4')}}:</div>
|
||||||
<div>{{detailInfo?.artwork?.length}}*{{detailInfo?.artwork?.width}}cm</div>
|
<div>{{detailInfo?.artwork?.length}}*{{detailInfo?.artwork?.width}}cm</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-[4px]">
|
<div class="flex mb-[4px]">
|
||||||
<div class="w-[70px] flex-shrink-0">画作简介:</div>
|
<div class="w-[70px] flex-shrink-0">{{$t('detail.text5')}}:</div>
|
||||||
<div>{{detailInfo?.artwork?.abstract??'-'}}</div>
|
<div>{{detailInfo?.artwork?.abstract??'-'}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex px-[16px] bg-#fff h-[36px] items-center mb-6px">
|
<div class="flex px-[16px] bg-#fff h-[36px] items-center mb-6px">
|
||||||
<div class="text-[#575757] text-[14px]">起拍价:</div>
|
<div class="text-[#575757] text-[14px]">{{$t('detail.text6')}}:</div>
|
||||||
<div class="text-#575757 text-14px font-bold">RMB 1,000</div>
|
<div class="text-#575757 text-14px font-bold">{{detailInfo?.startPriceCurrency}} {{detailInfo?.startPrice}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex px-[16px] bg-#fff h-[36px] items-center mb-6px" v-if="detailInfo?.soldPrice">
|
||||||
|
<div class="text-[#B58047] text-[14px]">成交价:</div>
|
||||||
|
<div class="text-#B58047 text-14px font-bold">{{detailInfo?.soldPriceCurrency}} {{detailInfo?.soldPrice}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-[16px] bg-#fff pt-12px pb-18px">
|
<div class="px-[16px] bg-#fff pt-12px pb-18px">
|
||||||
<div class="text-[#575757] text-[14px] mb-4px">竞价表:</div>
|
<div class="text-[#575757] text-[14px] mb-4px">{{$t('detail.text7')}}:</div>
|
||||||
<div v-if="detailInfo?.priceRuleType!=='diy'">
|
<div v-if="detailInfo?.priceRuleType!=='diy'">
|
||||||
<xImage :src="detailInfo?.priceRuleImage" alt=""/>
|
<xImage :src="detailInfo?.priceRuleImage" alt=""/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="mt-20px">
|
||||||
|
<div class="flex text-#575757 text-12px">
|
||||||
|
<div class="grow-1 text-center">序号</div>
|
||||||
|
<div class="grow-1 text-center">叫价金额</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="(item,index) of filteredPriceRules" :key="item.index" class="flex text-#575757 text-12px mt-10px">
|
||||||
|
<div class="grow-1 text-center">{{item.index}}</div>
|
||||||
|
<div class="grow-1 text-center">{{item.price}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
106
app/components/liveLoading/index.vue
Normal file
106
app/components/liveLoading/index.vue
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<template>
|
||||||
|
<div class="custom-loading-container" v-if="loading">
|
||||||
|
<div class="loadingio-spinner-pulse-2by998twmg8">
|
||||||
|
<div class="ldio-yzaezf3dcmj">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.custom-loading-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
color: #fff;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loading 动画样式 */
|
||||||
|
@keyframes ldio-yzaezf3dcmj-1 {
|
||||||
|
0% { top: 36px; height: 128px }
|
||||||
|
50% { top: 60px; height: 80px }
|
||||||
|
100% { top: 60px; height: 80px }
|
||||||
|
}
|
||||||
|
@keyframes ldio-yzaezf3dcmj-2 {
|
||||||
|
0% { top: 41.99999999999999px; height: 116.00000000000001px }
|
||||||
|
50% { top: 60px; height: 80px }
|
||||||
|
100% { top: 60px; height: 80px }
|
||||||
|
}
|
||||||
|
@keyframes ldio-yzaezf3dcmj-3 {
|
||||||
|
0% { top: 48px; height: 104px }
|
||||||
|
50% { top: 60px; height: 80px }
|
||||||
|
100% { top: 60px; height: 80px }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldio-yzaezf3dcmj div {
|
||||||
|
position: absolute;
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldio-yzaezf3dcmj div:nth-child(1) {
|
||||||
|
left: 35px;
|
||||||
|
background: #e15b64;
|
||||||
|
animation: ldio-yzaezf3dcmj-1 1s cubic-bezier(0,0.5,0.5,1) infinite;
|
||||||
|
animation-delay: -0.2s
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldio-yzaezf3dcmj div:nth-child(2) {
|
||||||
|
left: 85px;
|
||||||
|
background: #f8b26a;
|
||||||
|
animation: ldio-yzaezf3dcmj-2 1s cubic-bezier(0,0.5,0.5,1) infinite;
|
||||||
|
animation-delay: -0.1s
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldio-yzaezf3dcmj div:nth-child(3) {
|
||||||
|
left: 135px;
|
||||||
|
background: #abbd81;
|
||||||
|
animation: ldio-yzaezf3dcmj-3 1s cubic-bezier(0,0.5,0.5,1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loadingio-spinner-pulse-2by998twmg8 {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldio-yzaezf3dcmj {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
transform: translateZ(0) scale(1);
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ldio-yzaezf3dcmj div {
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
</style>
|
56
app/components/liveMinWindow/createMinWindow.js
Normal file
56
app/components/liveMinWindow/createMinWindow.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { createApp } from 'vue'
|
||||||
|
import MinWindow from '@/components/liveMinWindow/index.vue'
|
||||||
|
|
||||||
|
let minWindowInstance = null
|
||||||
|
|
||||||
|
// 创建悬浮窗
|
||||||
|
export const showMinWindow = (snapshot, props = {}) => {
|
||||||
|
if (minWindowInstance) {
|
||||||
|
hideMinWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = document.createElement('div')
|
||||||
|
container.id = 'live-min-window-container'
|
||||||
|
document.body.appendChild(container)
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
snapshot,
|
||||||
|
onClose: () => hideMinWindow(),
|
||||||
|
initialPosition: {
|
||||||
|
top: '80px',
|
||||||
|
right: '16px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = createApp(MinWindow, {
|
||||||
|
...defaultProps,
|
||||||
|
...props
|
||||||
|
})
|
||||||
|
|
||||||
|
app.config.errorHandler = (err) => {
|
||||||
|
console.error('MinWindow Error:', err)
|
||||||
|
hideMinWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
minWindowInstance = app.mount(container)
|
||||||
|
return minWindowInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hideMinWindow = () => {
|
||||||
|
if (!minWindowInstance) return
|
||||||
|
|
||||||
|
const el = minWindowInstance.$el
|
||||||
|
el.style.transform = 'translateY(100%)'
|
||||||
|
el.style.opacity = '0'
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
el.parentNode?.remove()
|
||||||
|
minWindowInstance = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.startViewTransition) {
|
||||||
|
document.startViewTransition(() => cleanup())
|
||||||
|
} else {
|
||||||
|
setTimeout(cleanup, 300)
|
||||||
|
}
|
||||||
|
}
|
72
app/components/waterfallFlow/index.vue
Normal file
72
app/components/waterfallFlow/index.vue
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<template>
|
||||||
|
<div class="waterfall-container" ref="container">
|
||||||
|
<div
|
||||||
|
v-for="(column, columnIndex) in columns"
|
||||||
|
:key="columnIndex"
|
||||||
|
class="waterfall-column"
|
||||||
|
:style="{ width: `${100 / columnCount}%` }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="item in column"
|
||||||
|
:key="item.id"
|
||||||
|
class="waterfall-item"
|
||||||
|
>
|
||||||
|
<slot :item="item">
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
columnCount: {
|
||||||
|
type: Number,
|
||||||
|
default: 2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = ref([])
|
||||||
|
|
||||||
|
const calculateColumns = () => {
|
||||||
|
const cols = Array.from({ length: props.columnCount }, () => [])
|
||||||
|
props.items.forEach((item, index) => {
|
||||||
|
const columnIndex = index % props.columnCount
|
||||||
|
cols[columnIndex].push(item)
|
||||||
|
})
|
||||||
|
|
||||||
|
columns.value = cols
|
||||||
|
}
|
||||||
|
watch(() => props.items, () => {
|
||||||
|
calculateColumns()
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
calculateColumns()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.waterfall-container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.waterfall-column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.waterfall-item {
|
||||||
|
break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -9,21 +9,7 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
// 用于控制图片尺寸
|
|
||||||
sizes: {
|
|
||||||
type: Array,
|
|
||||||
default: () => [320, 640, 768, 1024]
|
|
||||||
},
|
|
||||||
// 用于控制图片格式
|
|
||||||
format: {
|
|
||||||
type: String,
|
|
||||||
default: 'webp'
|
|
||||||
},
|
|
||||||
// 用于控制图片质量
|
|
||||||
quality: {
|
|
||||||
type: Number,
|
|
||||||
default: 80
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const showImage = () => {
|
const showImage = () => {
|
||||||
@ -35,9 +21,9 @@ const showImage = () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<nuxt-img
|
<img
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
v-bind="{ ...props, ...$attrs }"
|
v-bind="{ ...$props, ...$attrs }"
|
||||||
style="object-fit: cover"
|
style="object-fit: cover"
|
||||||
@click="showImage"
|
@click="showImage"
|
||||||
:src="src"
|
:src="src"
|
||||||
@ -45,8 +31,4 @@ const showImage = () => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
:deep(img) {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
@ -1,11 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import {ref, computed} from 'vue'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: [Date, String, Number],
|
type: [Date, String, Number]
|
||||||
default: () => new Date() // 默认当前日期
|
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -25,11 +23,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
minDate: {
|
minDate: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: () => new Date(1900, 0, 1)
|
default: () => dayjs('1900-01-01').toDate()
|
||||||
},
|
},
|
||||||
maxDate: {
|
maxDate: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: () => new Date(2100, 11, 31)
|
default: () => dayjs('2100-12-31').toDate()
|
||||||
},
|
},
|
||||||
format: {
|
format: {
|
||||||
type: String,
|
type: String,
|
||||||
@ -40,48 +38,52 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['update:modelValue', 'change'])
|
const emit = defineEmits(['update:modelValue', 'change'])
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
|
|
||||||
// 显示文本
|
|
||||||
const displayText = computed(() => {
|
|
||||||
return dayjs(props.modelValue).format(props.format)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 默认值
|
|
||||||
const defaultValue = computed(() => {
|
const defaultValue = computed(() => {
|
||||||
const date = props.modelValue || new Date()
|
let date
|
||||||
|
if (props.modelValue) {
|
||||||
|
date = dayjs(props.modelValue)
|
||||||
|
} else {
|
||||||
|
date = dayjs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!date.isValid()) {
|
||||||
|
date = dayjs()
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
date.getFullYear(),
|
date.year(),
|
||||||
date.getMonth() + 1,
|
date.month() + 1,
|
||||||
date.getDate()
|
date.date()
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
// 确认选择
|
const formatDate = (dateArr) => {
|
||||||
const onConfirm = ({ selectedValues }) => {
|
const [year, month, day] = dateArr
|
||||||
show.value = false
|
return dayjs(`${year}-${month}-${day}`).format(props.format)
|
||||||
const date = new Date(selectedValues[0], selectedValues[1] - 1, selectedValues[2])
|
}
|
||||||
emit('update:modelValue', date)
|
|
||||||
emit('change', date)
|
const displayValue = computed(() => {
|
||||||
|
if (!props.modelValue) return ''
|
||||||
|
const date = dayjs(props.modelValue)
|
||||||
|
return date.isValid() ? date.format(props.format) : ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const onConfirm = ({selectedValues}) => {
|
||||||
|
show.value = false
|
||||||
|
const formattedDate = formatDate(selectedValues)
|
||||||
|
emit('update:modelValue', formattedDate)
|
||||||
|
emit('change', formattedDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消选择
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
show.value = false
|
show.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置为当前日期
|
|
||||||
const reset = () => {
|
|
||||||
emit('update:modelValue', new Date())
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
reset
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<van-field
|
<van-field
|
||||||
:model-value="displayText"
|
:model-value="displayValue"
|
||||||
@click="show = true"
|
@click="show = true"
|
||||||
readonly
|
readonly
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@ -95,6 +97,9 @@ defineExpose({
|
|||||||
<van-popup
|
<van-popup
|
||||||
v-model:show="show"
|
v-model:show="show"
|
||||||
position="bottom"
|
position="bottom"
|
||||||
|
teleport="#__nuxt"
|
||||||
|
destroy-on-close
|
||||||
|
safe-area-inset-bottom
|
||||||
>
|
>
|
||||||
<van-date-picker
|
<van-date-picker
|
||||||
:min-date="minDate"
|
:min-date="minDate"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: {
|
modelValue: {
|
||||||
type: [Number, String]
|
type: [Number, String]
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
@ -30,35 +30,30 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:value', 'change'])
|
const emit = defineEmits(['update:modelValue', 'change'])
|
||||||
|
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
|
|
||||||
const onConfirm = (value) => {
|
const onConfirm = (value) => {
|
||||||
show.value = false
|
show.value = false
|
||||||
emit('update:value', value.value)
|
emit('update:modelValue', value.selectedValues?.[0])
|
||||||
emit('change', value)
|
emit('change', value.selectedValues?.[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
const displayText = computed(() => {
|
const displayText = computed(() => {
|
||||||
const selected = props.columns.find(x => x.value === props.value)
|
const selected = props.columns.find(x => x.value === props.modelValue)
|
||||||
return selected?.text || ''
|
return selected?.text || ''
|
||||||
})
|
})
|
||||||
|
const openPopup=()=>{
|
||||||
const reset = () => {
|
show.value=true
|
||||||
emit('update:value', undefined)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
reset
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<van-field
|
<van-field
|
||||||
:model-value="displayText"
|
:model-value="displayText"
|
||||||
@click="show = true"
|
@click="openPopup"
|
||||||
readonly
|
readonly
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:required="required"
|
:required="required"
|
||||||
@ -72,13 +67,14 @@ defineExpose({
|
|||||||
v-model:show="show"
|
v-model:show="show"
|
||||||
destroy-on-close
|
destroy-on-close
|
||||||
position="bottom"
|
position="bottom"
|
||||||
|
teleport="body"
|
||||||
safe-area-inset-bottom
|
safe-area-inset-bottom
|
||||||
>
|
>
|
||||||
<van-picker
|
<van-picker
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
@confirm="onConfirm"
|
@confirm="onConfirm"
|
||||||
@cancel="show = false"
|
@cancel="show = false"
|
||||||
:default-index="columns.findIndex(x => x.value === value)"
|
:default-index="columns.findIndex(x => x.value === modelValue)"
|
||||||
title="请选择"
|
title="请选择"
|
||||||
confirm-button-text="确定"
|
confirm-button-text="确定"
|
||||||
cancel-button-text="取消"
|
cancel-button-text="取消"
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
|
export const useAppFooterRouteNames = ['index', 'profile']
|
||||||
export const useAppFooterRouteNames= ['index', 'profile']
|
export const useAppHeaderRouteNames = ['index', 'profile', 'login', 'collectCode-login', 'collectCode-mine', 'payment-result', 'collectCode-signature-personal-Info', 'collectCode-signature-result','collectCode-payment-result']
|
||||||
export const useAppHeaderRouteNames= ['index', 'profile','login','collectCode-login','collectCode-mine']
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
# Layouts
|
|
||||||
|
|
||||||
Vue components in this dir are used as layouts.
|
|
||||||
|
|
||||||
By default, `default.vue` will be used unless an alternative is specified in the route meta.
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<script setup lang="ts">
|
|
||||||
definePageMeta({
|
|
||||||
layout: 'goods',
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
Learn more on <https://nuxt.com/docs/guide/directory-structure/layouts>
|
|
@ -1,7 +1,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import itemDetail from '@/components/itemDetail/index.vue'
|
import itemDetail from '@/components/itemDetail/index.vue'
|
||||||
import {userArtwork} from "~/api/goods/index.js";
|
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 route = useRoute()
|
||||||
const detail = ref({})
|
const detail = ref({})
|
||||||
const uuid = route.query.uuid
|
const uuid = route.query.uuid
|
||||||
@ -10,9 +15,11 @@ const initData = async () => {
|
|||||||
const res = await userArtwork({uuid})
|
const res = await userArtwork({uuid})
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
detail.value = res.data
|
detail.value = res.data
|
||||||
|
console.log('detail',detail.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const position = ref({x: window?.innerWidth - 120 || 0, y: 240}) // 设置初始位置在右侧
|
const router = useRouter();
|
||||||
|
const position = ref({x: window?.innerWidth - 120 || 0, y: 240})
|
||||||
const startPosition = ref({x: 0, y: 0})
|
const startPosition = ref({x: 0, y: 0})
|
||||||
const isDragging = ref(false)
|
const isDragging = ref(false)
|
||||||
|
|
||||||
@ -31,47 +38,55 @@ const onDrag = (e) => {
|
|||||||
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
const clientX = e.touches ? e.touches[0].clientX : e.clientX
|
||||||
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
const clientY = e.touches ? e.touches[0].clientY : e.clientY
|
||||||
|
|
||||||
// 获取窗口尺寸
|
const maxX = window.innerWidth - 108
|
||||||
const maxX = window.innerWidth - 108 // 减去元素宽度
|
const maxY = window.innerHeight - 137
|
||||||
const maxY = window.innerHeight - 137 // 减去元素高度
|
|
||||||
|
|
||||||
// 限制范围
|
|
||||||
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
const x = Math.min(Math.max(0, clientX - startPosition.value.x), maxX)
|
||||||
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
const y = Math.min(Math.max(0, clientY - startPosition.value.y), maxY)
|
||||||
|
|
||||||
position.value = {x, y}
|
position.value = {x, y}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stopDrag = () => {
|
const stopDrag = () => {
|
||||||
isDragging.value = false
|
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')
|
||||||
|
}
|
||||||
|
console.log('detail',detail.value)
|
||||||
|
//router.push('/payment')
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 鼠标事件
|
|
||||||
document.addEventListener('mousemove', onDrag)
|
document.addEventListener('mousemove', onDrag)
|
||||||
document.addEventListener('mouseup', stopDrag)
|
document.addEventListener('mouseup', stopDrag)
|
||||||
// 触摸事件
|
|
||||||
document.addEventListener('touchmove', onDrag)
|
document.addEventListener('touchmove', onDrag)
|
||||||
document.addEventListener('touchend', stopDrag)
|
document.addEventListener('touchend', stopDrag)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
document.removeEventListener('mousemove', onDrag)
|
document.removeEventListener('mousemove', onDrag)
|
||||||
document.removeEventListener('mouseup', stopDrag)
|
document.removeEventListener('mouseup', stopDrag)
|
||||||
document.removeEventListener('touchmove', onDrag)
|
document.removeEventListener('touchmove', onDrag)
|
||||||
document.removeEventListener('touchend', stopDrag)
|
document.removeEventListener('touchend', stopDrag)
|
||||||
})
|
})
|
||||||
|
function formatThousands(num) {
|
||||||
|
|
||||||
|
return Number(num).toLocaleString();
|
||||||
|
}
|
||||||
initData()
|
initData()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative h-screen-nav flex flex-col">
|
<div class="relative h-screen-nav flex flex-col">
|
||||||
<itemDetail class="grow-1" :detail-info="detail.auctionArtworkInfo"/>
|
<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">
|
<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">
|
<van-button class="w-213px !h-38px" type="primary" @click="goPay">
|
||||||
<span class="text-#fff text-14px">去支付 RMB10,000</span>
|
<span class="text-#fff text-14px">{{ $t('art_detail_page.button') }} {{detail.leftCurrency}}{{formatThousands(detail.leftPrice)}}</span>
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -85,9 +100,9 @@ initData()
|
|||||||
>
|
>
|
||||||
<img src="@/static/images/zd5530@2x.png" class="w-full h-full" alt="">
|
<img src="@/static/images/zd5530@2x.png" class="w-full h-full" alt="">
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center absolute bottom-25px text-14px text-#B58047 left-1/2 transform translate-x--1/2 whitespace-nowrap">
|
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>恭喜您</div>
|
<div>{{ $t('art_detail_page.prompt_title')}}</div>
|
||||||
<div>竞拍成功</div>
|
<div>{{ $t('art_detail_page.prompt_desc')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import {useRouter, useRoute} from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n'
|
import {useI18n} from 'vue-i18n'
|
||||||
import { senCode, userLogin } from "@/api/auth/index.js";
|
import {senCode, userLogin} from "@/api/auth/index.js";
|
||||||
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 FingerprintJS from '@fingerprintjs/fingerprintjs'
|
import FingerprintJS from '@fingerprintjs/fingerprintjs'
|
||||||
import {checkPhone, mobileLogin, userSend} from "@/api-collect-code/auth/index.js";
|
import {checkPhone, mobileLogin, userSend} from "@/api-collect-code/auth/index.js";
|
||||||
const { userInfo, token,fingerprint } = codeAuthStore()
|
|
||||||
|
const {userInfo, token, fingerprint} = codeAuthStore()
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { locale } = useI18n()
|
const {locale} = useI18n()
|
||||||
const loadingRef = ref({
|
const loadingRef = ref({
|
||||||
loading1: false,
|
loading1: false,
|
||||||
loading2: false,
|
loading2: false,
|
||||||
@ -57,23 +58,23 @@ const getCode = async () => {
|
|||||||
tel: phoneNum.value,
|
tel: phoneNum.value,
|
||||||
})
|
})
|
||||||
loadingRef.value.loading1 = false
|
loadingRef.value.loading1 = false
|
||||||
if (res.status === 0){
|
if (res.status === 0) {
|
||||||
const res=await userSend({telNum:phoneNum.value,zone:'+86'})
|
const res = await userSend({telNum: phoneNum.value, zone: '+86'})
|
||||||
if (res.status === 0){
|
if (res.status === 0) {
|
||||||
pane.value = 1
|
pane.value = 1
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
vanSwipeRef.value?.swipeTo(pane.value)
|
||||||
showKeyboard.value = true
|
showKeyboard.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* loadingRef.value.loading1 = false
|
/* loadingRef.value.loading1 = false
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
pane.value = 1
|
pane.value = 1
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
vanSwipeRef.value?.swipeTo(pane.value)
|
||||||
showKeyboard.value = true
|
showKeyboard.value = true
|
||||||
startCountdown();*/
|
startCountdown();*/
|
||||||
/* pane.value = 1
|
/* pane.value = 1
|
||||||
vanSwipeRef.value?.swipeTo(pane.value)
|
vanSwipeRef.value?.swipeTo(pane.value)
|
||||||
showKeyboard.value=true
|
showKeyboard.value=true
|
||||||
@ -92,8 +93,8 @@ const goLogin = async () => {
|
|||||||
loadingRef.value.loading2 = true
|
loadingRef.value.loading2 = true
|
||||||
const res = await mobileLogin({
|
const res = await mobileLogin({
|
||||||
TelNum: phoneNum.value,
|
TelNum: phoneNum.value,
|
||||||
Password:loginType.value===1?password.value:'',
|
Password: loginType.value === 1 ? password.value : '',
|
||||||
Code: loginType.value===0?code.value:''
|
Code: loginType.value === 0 ? code.value : ''
|
||||||
})
|
})
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
userInfo.value = res.data.accountInfo
|
userInfo.value = res.data.accountInfo
|
||||||
@ -105,7 +106,11 @@ const goLogin = async () => {
|
|||||||
}
|
}
|
||||||
loadingRef.value.loading2 = false
|
loadingRef.value.loading2 = false
|
||||||
}
|
}
|
||||||
|
const showPassword = ref(false)
|
||||||
|
|
||||||
|
const togglePasswordVisibility = () => {
|
||||||
|
showPassword.value = !showPassword.value
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -119,42 +124,56 @@ const goLogin = async () => {
|
|||||||
<div v-show="pane === 0">
|
<div v-show="pane === 0">
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
<div class="border-b-[1.7px] mt-[8px]">
|
||||||
<van-field v-model="phoneNum" clearable placeholder="请输入手机号">
|
<van-field v-model="phoneNum" clearable :placeholder="$t('collectCode.login.phoneNumberPlaceholder')">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
||||||
手机号
|
{{ $t('collectCode.login.phoneNumber') }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b-[1.7px] mt-[8px]" v-show="loginType === 1">
|
<div class="border-b-[1.7px] mt-[8px]" v-show="loginType === 1">
|
||||||
<van-field v-model="password" clearable placeholder="请输入密码">
|
<van-field
|
||||||
|
v-model="password"
|
||||||
|
:type="showPassword ? 'text' : 'password'"
|
||||||
|
clearable
|
||||||
|
:placeholder="$t('collectCode.login.passwordPlaceholder')"
|
||||||
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
<div class="text-[16px] text-[#1A1A1A] flex align-center justify-start">
|
||||||
密码
|
{{ $t('collectCode.login.password') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #button>
|
||||||
|
<div class="flex justify-center items-center">
|
||||||
|
<van-icon
|
||||||
|
size="20"
|
||||||
|
:name="showPassword ? 'eye-o' : 'closed-eye'"
|
||||||
|
@click="togglePasswordVisibility"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end mt-[10px]" @click="changeToPwd">
|
<div class="flex justify-end mt-[10px]">
|
||||||
<div class="text-[14px] text-[#2B53AC]">
|
<div class="text-[14px] text-[#2B53AC]" @click="changeToPwd">
|
||||||
{{ loginType === 0 ? '密码登录' : '验证码登录' }}
|
{{ loginType === 0 ? $t('collectCode.login.passwordLogin') : $t('collectCode.login.codeLogin') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div />
|
<div/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[55px]">
|
<div class="mt-[55px]">
|
||||||
<div v-if="loginType === 0">
|
<div v-if="loginType === 0">
|
||||||
<van-button :loading="loadingRef.loading1" v-if="phoneNum" loading-text="获取验证码"
|
<van-button :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('collectCode.login.getCode')"
|
||||||
type="primary" block style="height: 48px" @click="getCode">获取验证码</van-button>
|
type="primary" block style="height: 48px" @click="getCode">{{ $t('collectCode.login.getCode') }}
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">获取验证码</van-button>
|
</van-button>
|
||||||
|
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('collectCode.login.getCode') }}</van-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<van-button type="primary" v-if="password" block :loading="loadingRef.loading2" loading-text="登录"
|
<van-button type="primary" v-if="password" block :loading="loadingRef.loading2" :loading-text="$t('collectCode.login.login')"
|
||||||
style="height: 48px;margin-top:10px" @click="goLogin">登录</van-button>
|
style="height: 48px;margin-top:10px" @click="goLogin">{{ $t('collectCode.login.login') }}
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">登录</van-button>
|
</van-button>
|
||||||
|
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('collectCode.login.login') }}</van-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -162,32 +181,31 @@ const goLogin = async () => {
|
|||||||
<van-swipe-item>
|
<van-swipe-item>
|
||||||
<div v-show="pane === 1">
|
<div v-show="pane === 1">
|
||||||
<div class="flex mb-[16px]">
|
<div class="flex mb-[16px]">
|
||||||
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('login.hasSendTo') }}</div>
|
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('collectCode.login.hasSendTo') }}</div>
|
||||||
<div class="text-[16px] text-[#000]">+86 {{ phoneNum }}</div>
|
<div class="text-[16px] text-[#000]">+86 {{ phoneNum }}</div>
|
||||||
</div>
|
</div>
|
||||||
<van-password-input :value="code" :gutter="10" :mask="false" focused @focus="showKeyboard = true" />
|
<van-password-input :value="code" :gutter="10" :mask="false" focused @focus="showKeyboard = true"/>
|
||||||
<div :class="`${countdown > 0 ? 'text-#BDBDBD' : 'text-#2B53AC'} text-14px`">
|
<div class="flex justify-between">
|
||||||
{{ $t('login.reSend') }}<span v-if="countdown > 0">({{ countdown }})</span>
|
<div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'} text-14px`">
|
||||||
|
{{ $t('collectCode.login.reSend') }}<span v-if="countdown>0">({{ countdown }})</span>
|
||||||
|
</div>
|
||||||
|
<div @click="goBack" class="text-#2B53AC text-14px">
|
||||||
|
{{ $t('collectCode.login.back') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[17px]">
|
<div class="mt-[17px]">
|
||||||
|
|
||||||
<van-button v-if="code.length === 6" type="primary" block :loading="loadingRef.loading2"
|
<van-button v-if="code.length === 6" type="primary" block :loading="loadingRef.loading2"
|
||||||
:loading-text="$t('login.login')" style="height: 48px" @click="goLogin">{{
|
:loading-text="$t('collectCode.login.login')" style="height: 48px" @click="goLogin">
|
||||||
$t('login.login')
|
{{ $t('collectCode.login.login') }}
|
||||||
}}</van-button>
|
</van-button>
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{
|
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">
|
||||||
$t('login.login')
|
{{ $t('collectCode.login.login') }}
|
||||||
}}</van-button>
|
</van-button>
|
||||||
</div>
|
|
||||||
<div class="mt-[17px]">
|
|
||||||
<van-button type="primary" @click="goBack" block style="height: 48px">{{ $t('login.back')
|
|
||||||
}}</van-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-swipe-item>
|
</van-swipe-item>
|
||||||
</van-swipe>
|
</van-swipe>
|
||||||
<van-number-keyboard v-model="code" :show="showKeyboard" @blur="showKeyboard = false" />
|
<van-number-keyboard v-model="code" :show="showKeyboard" @blur="showKeyboard = false"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -4,10 +4,14 @@ import XImage from "@/components/x-image/index.vue";
|
|||||||
import {useRuntimeConfig} from "#app";
|
import {useRuntimeConfig} from "#app";
|
||||||
import QRCode from 'qrcode'
|
import QRCode from 'qrcode'
|
||||||
import { showImagePreview } from 'vant';
|
import { showImagePreview } from 'vant';
|
||||||
import {offlineQrcodeDelete} from "~/api-collect-code/goods/index.js";
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const t = useI18n();
|
||||||
|
|
||||||
const statusLabel=[
|
const statusLabel=[
|
||||||
{label:'已付款',value:2,color:'#18A058'}, {label:'未付款',value:1,color:'#CF3050'}, {label:'已部分付款',value:4,color:'#F09F1F'}
|
{label: t('collectCode.qrcode.status.paid'), value:2, color:'#18A058'},
|
||||||
|
{label: t('collectCode.qrcode.status.unpaid'), value:1, color:'#CF3050'},
|
||||||
|
{label: t('collectCode.qrcode.status.partialPaid'), value:4, color:'#F09F1F'}
|
||||||
]
|
]
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
@ -20,10 +24,10 @@ const props = defineProps({
|
|||||||
const itemLabel=(data)=>{
|
const itemLabel=(data)=>{
|
||||||
return statusLabel.find(x=>x.value===data.payStatus)
|
return statusLabel.find(x=>x.value===data.payStatus)
|
||||||
}
|
}
|
||||||
const config = useRuntimeConfig()
|
|
||||||
const getQRBase64 = async () => {
|
const getQRBase64 = async () => {
|
||||||
|
const url=`${window.location.origin}/collectCode/signature/personal-Info?number=2&qrUid=${props.data.qrUid}`
|
||||||
try {
|
try {
|
||||||
return await QRCode.toDataURL(`${config.public.NUXT_PUBLIC_API_BASE}/collectCode/payment`, {
|
return await QRCode.toDataURL(url, {
|
||||||
width: 200,
|
width: 200,
|
||||||
margin: 4,
|
margin: 4,
|
||||||
errorCorrectionLevel: 'H'
|
errorCorrectionLevel: 'H'
|
||||||
@ -33,9 +37,13 @@ const getQRBase64 = async () => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const QRUrl=ref('')
|
||||||
|
const show=ref(false)
|
||||||
const openQrCode=async ()=>{
|
const openQrCode=async ()=>{
|
||||||
|
|
||||||
const base64=await getQRBase64()
|
const base64=await getQRBase64()
|
||||||
showImagePreview([base64])
|
QRUrl.value=base64
|
||||||
|
show.value=true
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -51,18 +59,23 @@ const openQrCode=async ()=>{
|
|||||||
<XImage class="w-57px h-56px rounded-4px" :src="data.hdPic"></XImage>
|
<XImage class="w-57px h-56px rounded-4px" :src="data.hdPic"></XImage>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-12px text-#1E1E1E">
|
<div class="text-12px text-#1E1E1E">
|
||||||
<div>Lot:{{ data.lotNo }}</div>
|
<div>{{ $t('collectCode.qrcode.card.lotNo') }}{{ data.lotNo }}</div>
|
||||||
<div>创建人:{{ data.userName }}</div>
|
<div>{{ $t('collectCode.qrcode.card.creator') }}{{ data.userName }}</div>
|
||||||
<div>创建时间:{{data.createdAt}}</div>
|
<div>{{ $t('collectCode.qrcode.card.createTime') }}{{data.createdAt}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col justify-end ml-auto ">
|
<div class="flex flex-col justify-end ml-auto ">
|
||||||
<div class="flex w-55px h-26px bg-#2B53AC rounded-4px justify-center items-center">
|
<div class="flex w-55px h-26px bg-#2B53AC rounded-4px justify-center items-center">
|
||||||
<div @click="openQrCode" class="text-12px text-#fff line-height-none mt-0.5px mr-5px">查看</div>
|
<div @click="openQrCode(data)" class="text-12px text-#fff line-height-none mt-0.5px mr-5px">{{ $t('collectCode.qrcode.card.view') }}</div>
|
||||||
<div >
|
<div>
|
||||||
<img class="w-12px h-12px" src="@/static/images/icon-design-42@3x.png" alt="">
|
<img class="w-12px h-12px" src="@/static/images/icon-design-42@3x.png" alt="">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<van-dialog teleport="body" v-model:show="show">
|
||||||
|
<div class="flex justify-center py-20px">
|
||||||
|
<img :src="QRUrl" />
|
||||||
|
</div>
|
||||||
|
</van-dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -43,17 +43,17 @@ const createForm=ref({
|
|||||||
})
|
})
|
||||||
const confirm=async ()=>{
|
const confirm=async ()=>{
|
||||||
if (!createForm.value.price){
|
if (!createForm.value.price){
|
||||||
message.warning('请输入金额')
|
message.warning(t('collectCode.message.amountRequired'))
|
||||||
return false
|
return false
|
||||||
}else if (!createForm.value.lotNo){
|
}else if (!createForm.value.lotNo){
|
||||||
message.warning('请输入Lot号')
|
message.warning(t('collectCode.message.lotNoRequired'))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const res=await offlineQrcodeCreate({...createForm.value,price:String(createForm.value.price)})
|
const res=await offlineQrcodeCreate({...createForm.value,price:String(createForm.value.price)})
|
||||||
if (res.status===0){
|
if (res.status===0){
|
||||||
show.value=false
|
show.value=false
|
||||||
|
onRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
const onRefresh = async () => {
|
const onRefresh = async () => {
|
||||||
try {
|
try {
|
||||||
@ -89,7 +89,8 @@ const deleteData=async (qrUid)=>{
|
|||||||
})
|
})
|
||||||
if (res.status===0){
|
if (res.status===0){
|
||||||
getOfflineQrcodeList()
|
getOfflineQrcodeList()
|
||||||
message.success('删除成功')
|
message.success(t('collectCode.message.deleteSuccess'))
|
||||||
|
onRefresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initData()
|
initData()
|
||||||
@ -110,17 +111,17 @@ initData()
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b-1px border-b-#D3D3D3 px-16px flex">
|
<div class="border-b-1px border-b-#D3D3D3 px-16px flex">
|
||||||
<div class="text-#000 text-16px border-b-3 border-b-#2B53AC h-36px">线下付款二维码 </div>
|
<div class="text-#000 text-16px border-b-3 border-b-#2B53AC h-36px">{{ $t('collectCode.mine.offlineQrcode') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grow-1 flex flex-col overflow-hidden py-15px">
|
<div class="grow-1 flex flex-col overflow-hidden py-15px">
|
||||||
<div class="overflow-auto">
|
<div class="overflow-auto">
|
||||||
<van-pull-refresh v-model="localState.refreshing"
|
<van-pull-refresh v-model="localState.refreshing"
|
||||||
success-text="刷新成功"
|
:success-text="$t('collectCode.mine.refreshSuccess')"
|
||||||
:success-duration="700"
|
:success-duration="700"
|
||||||
@refresh="onRefresh">
|
@refresh="onRefresh">
|
||||||
<van-list v-model:loading="storeLoading"
|
<van-list v-model:loading="storeLoading"
|
||||||
:finished="localState.finished"
|
:finished="localState.finished"
|
||||||
finished-text="没有更多了"
|
:finished-text="$t('collectCode.mine.noMore')"
|
||||||
@load="loadMore" class="px-14px">
|
@load="loadMore" class="px-14px">
|
||||||
<template v-for="(item,index) of itemList" :key="item.qrUid">
|
<template v-for="(item,index) of itemList" :key="item.qrUid">
|
||||||
<template v-if="item.payStatus===1">
|
<template v-if="item.payStatus===1">
|
||||||
@ -148,39 +149,38 @@ initData()
|
|||||||
</div>
|
</div>
|
||||||
<div class="h-81px w-full flex justify-center shrink-0 pt-10px">
|
<div class="h-81px w-full flex justify-center shrink-0 pt-10px">
|
||||||
<div class="w-213px h-38px bg-#2B53AC text-#fff flex justify-center items-center text-14px rounded-4px" @click="show=true">
|
<div class="w-213px h-38px bg-#2B53AC text-#fff flex justify-center items-center text-14px rounded-4px" @click="show=true">
|
||||||
新增
|
{{ $t('collectCode.mine.add') }}</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<van-dialog v-model:show="show">
|
<van-dialog v-model:show="show">
|
||||||
<div class="pt-18px pb-24px px-24px">
|
<div class="pt-18px pb-24px px-24px">
|
||||||
<div class="text-16px text-#000 font-bold text-center mb-26px">新增收款二维码</div>
|
<div class="text-16px text-#000 font-bold text-center mb-26px">{{ $t('collectCode.mine.addQrcode.title') }}</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="flex mb-6px items-center">
|
<div class="flex mb-6px items-center">
|
||||||
<div class="w-58px">
|
<div class="w-58px">
|
||||||
<div class="text-#1A1A1A text-16px">金额</div>
|
<div class="text-#1A1A1A text-16px">{{ $t('collectCode.mine.addQrcode.amount') }}</div>
|
||||||
<div class="text-#939393 text-12px">RMB</div>
|
<div class="text-#939393 text-12px">{{ $t('collectCode.mine.addQrcode.amountUnit') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input v-model="createForm.price" type="number"
|
<input v-model="createForm.price" type="number"
|
||||||
class="w-214px h-48px bg-#F3F3F3 rounded-4px px-11px text-16px" placeholder="请输入金额">
|
class="w-214px h-48px bg-#F3F3F3 rounded-4px px-11px text-16px" :placeholder="$t('collectCode.mine.addQrcode.amountPlaceholder')">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="w-58px">
|
<div class="w-58px">
|
||||||
<div class="text-#1A1A1A text-16px">Lot号</div>
|
<div class="text-#1A1A1A text-16px">{{ $t('collectCode.mine.addQrcode.lotNo') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="number" v-model="createForm.lotNo" @input="inputLotNo" class="w-214px h-48px bg-#F3F3F3 rounded-4px px-11px text-16px" placeholder="请输入拍品序号">
|
<input type="number" v-model="createForm.lotNo" @input="inputLotNo" class="w-214px h-48px bg-#F3F3F3 rounded-4px px-11px text-16px" :placeholder="$t('collectCode.mine.addQrcode.lotNoPlaceholder')">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center" v-if="abnormal">
|
<div class="flex flex-col items-center" v-if="abnormal">
|
||||||
<div class="text-#CF3050 text-12px mb-8px mt-4px">*该拍品号当前已存在收款二维码,确定要创建吗?</div>
|
<div class="text-#CF3050 text-12px mb-8px mt-4px">{{ $t('collectCode.mine.addQrcode.existingWarning') }}</div>
|
||||||
<div>
|
<div>
|
||||||
<XImage class="w-116px h-116px rounded-4px mb-9px" :src="abnormalRow.hdPic"></XImage>
|
<XImage class="w-116px h-116px rounded-4px mb-9px" :src="abnormalRow.hdPic"></XImage>
|
||||||
<div class="text-12px text-#575757 flex flex-col items-center">
|
<div class="text-12px text-#575757 flex flex-col items-center">
|
||||||
<div>日出而作,日落而息</div>
|
<div>{{ abnormalRow.title }}</div>
|
||||||
<div>张天赐</div>
|
<div>{{ abnormalRow.author }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -188,10 +188,10 @@ initData()
|
|||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="border-t flex">
|
<div class="border-t flex">
|
||||||
<van-button class="w-50% h-56px" style="border: none;border-radius: 0;border-right: 1.5px solid #E7E7E7" @click="show=false">
|
<van-button class="w-50% h-56px" style="border: none;border-radius: 0;border-right: 1.5px solid #E7E7E7" @click="show=false">
|
||||||
<span class="text-#000 text-16px text-center">取消</span>
|
<span class="text-#000 text-16px text-center">{{ $t('collectCode.mine.addQrcode.cancel') }}</span>
|
||||||
</van-button>
|
</van-button>
|
||||||
<van-button class="w-50% h-56px !rounded-0" style="border: none;border-radius: 0" @click="confirm">
|
<van-button class="w-50% h-56px !rounded-0" style="border: none;border-radius: 0" @click="confirm">
|
||||||
<span class="text-#000 text-16px text-center text-#2B53AC">确定</span>
|
<span class="text-#000 text-16px text-center text-#2B53AC">{{ $t('collectCode.mine.addQrcode.confirm') }}</span>
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,41 +1,90 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const payStatus=ref(0)
|
import {liveStore} from "~/stores/live/index.js";
|
||||||
const changePayStatus=()=>{
|
import {createBuyOrder} from "~/api/goods/index.js";
|
||||||
payStatus.value=payStatus.value===0?1:0
|
import {goodStore} from "~/stores/goods/index.js";
|
||||||
|
import {showLoadingToast, closeToast} from 'vant';
|
||||||
|
import {authStore} from "~/stores/auth/index.js";
|
||||||
|
import {message} from "~/components/x-message/useMessage.js";
|
||||||
|
import {createOrder} from "~/api-collect-code/goods/index.js";
|
||||||
|
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
|
||||||
|
const {t} = useI18n();
|
||||||
|
const {checkoutSessionUrl,qrUid,qrData} = codeAuthStore()
|
||||||
|
const payStatus = ref(0)
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'payment.title'
|
||||||
|
})
|
||||||
|
const changePayStatus = () => {
|
||||||
|
payStatus.value = payStatus.value === 0 ? 1 : 0
|
||||||
}
|
}
|
||||||
const validateInput = (e) => {
|
const amount = ref('')
|
||||||
|
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) {
|
||||||
|
window.location.href = res.data.checkoutSessionUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleInput = (e) => {
|
||||||
|
// 只允许数字和小数点,且只保留两位小数
|
||||||
const value = e.target.value
|
const value = e.target.value
|
||||||
const char = String.fromCharCode(e.charCode)
|
// 清除非数字和小数点
|
||||||
|
let newValue = value.replace(/[^\d.]/g, '')
|
||||||
if (!/[\d.]/.test(char)) {
|
// 确保只有一个小数点
|
||||||
e.preventDefault()
|
newValue = newValue.replace(/\.{2,}/g, '.')
|
||||||
return
|
// 只保留第一个小数点
|
||||||
|
newValue = newValue.replace(/^(\d*\.\d*)\./, '$1')
|
||||||
|
// 保留两位小数
|
||||||
|
if (newValue.indexOf('.') > 0) {
|
||||||
|
newValue = newValue.slice(0, newValue.indexOf('.') + 3)
|
||||||
}
|
}
|
||||||
|
// 禁止输入以0开头的多位整数
|
||||||
|
newValue = newValue.replace(/^0+(\d)/, '$1')
|
||||||
|
|
||||||
if (char === '.' && (value.includes('.') || !value)) {
|
amount.value = newValue
|
||||||
e.preventDefault()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.includes('.') && value.split('.')[1]?.length >= 2) {
|
|
||||||
e.preventDefault()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</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">
|
<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>
|
||||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{payStatus===0?'支付全部':'支付部分'}}</div>
|
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{ payStatus === 0 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</div>
|
||||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">RMB 5000</div>
|
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">{{ qrData.currency }}
|
||||||
<div class="mb-12px">
|
{{ qrData?.leftPrice }}
|
||||||
<input class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" placeholder="最多RMB5,000" @keydown="validateInput">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===1?'支付全部':'支付部分'}}</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"
|
||||||
|
:placeholder="$t('collectCode.payment.maxAmount', { currency: qrData.currency, price: qrData?.leftPrice })" @input="handleInput">
|
||||||
|
</div>
|
||||||
|
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{ payStatus === 1 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</div>
|
||||||
|
<div class="w-full mt-auto mb-40px">
|
||||||
|
<van-button type="primary" block @click="confirmPay">
|
||||||
|
{{ $t('collectCode.payment.confirmPayment') }}
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
44
app/pages/collectCode/payment/result/index.vue
Normal file
44
app/pages/collectCode/payment/result/index.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<script setup>
|
||||||
|
import {orderQuery} from "~/api/goods/index.js";
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'payment.text1',
|
||||||
|
})
|
||||||
|
const router = useRouter()
|
||||||
|
const {t}=useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const resData=ref({})
|
||||||
|
const res=await orderQuery({
|
||||||
|
orderNo:route.query.orderNo
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
resData.value=res.data
|
||||||
|
}
|
||||||
|
const statusLabel={
|
||||||
|
1:t('payment.text2'),
|
||||||
|
2:t('payment.text3'),
|
||||||
|
3:t('payment.text4'),
|
||||||
|
4:t('payment.text5'),
|
||||||
|
}
|
||||||
|
const goHome=()=>{
|
||||||
|
router.push('/')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px">
|
||||||
|
<div class="flex flex-col items-center mt-150px">
|
||||||
|
<img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt="">
|
||||||
|
<div class="text-#000 text-16px mb-25px">{{statusLabel[resData.status]}}!</div>
|
||||||
|
<div class="text-#999 text-16px">{{resData.currency}}{{resData.money}}</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="w-full mt-auto mb-40px">
|
||||||
|
<van-button type="primary" block @click="goHome">
|
||||||
|
回到首页
|
||||||
|
</van-button>
|
||||||
|
</div>-->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,18 +1,74 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const image = ref('');
|
import {VueSignaturePad} from 'vue-signature-pad';
|
||||||
import { showToast } from 'vant';
|
import { showToast } from 'vant';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
||||||
|
import {signOffline} from "~/api/goods/index.js";
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const {t} = useI18n();
|
||||||
image.value = data.image;
|
const {formData,number}=codeAuthStore()
|
||||||
|
const signaturePad = ref(null);
|
||||||
|
definePageMeta({
|
||||||
|
layout: ''
|
||||||
|
});
|
||||||
|
const router = useRouter();
|
||||||
|
const imgUrl = ref('');
|
||||||
|
const show = ref(false);
|
||||||
|
const goBack = () => {
|
||||||
|
router.back()
|
||||||
};
|
};
|
||||||
const onClear = () => showToast('clear');
|
|
||||||
|
const submitSignature = () => {
|
||||||
|
if (signaturePad.value?.isEmpty()) {
|
||||||
|
showToast(t('collectCode.signature.pleaseSign'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { data } = signaturePad.value?.saveSignature();
|
||||||
|
imgUrl.value = data;
|
||||||
|
show.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearSignature = () => {
|
||||||
|
signaturePad.value?.clearSignature();
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirm=async ()=>{
|
||||||
|
const res=await signOffline({
|
||||||
|
userInfo:formData.value,
|
||||||
|
signOrder:Number(number.value),
|
||||||
|
signImgFileData:imgUrl.value
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
router.push('/collectCode/signature/result')
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-signature @submit="onSubmit" @clear="onClear" />
|
<div class="signature-container">
|
||||||
<van-image v-if="image" :src="image" />
|
<div class="flex flex-col h-100vh px-20px py-20px bg-gray w-100vw">
|
||||||
|
<client-only>
|
||||||
|
<VueSignaturePad
|
||||||
|
width="100%"
|
||||||
|
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>
|
||||||
|
<van-dialog v-model:show="show" show-cancel-button @confirm="confirm">
|
||||||
|
<img class="w-300px h-200px" :src="imgUrl" />
|
||||||
|
</van-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -2,50 +2,148 @@
|
|||||||
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 {message} from "@/components/x-message/useMessage.js";
|
||||||
|
import {fddInfo, offlineQrcode} from "~/api-collect-code/goods/index.js";
|
||||||
|
import {signOffline} from "~/api/goods/index.js";
|
||||||
|
const {formData,number,auctionArtworkUuid,qrUid,qrData}=codeAuthStore()
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: 'default',
|
||||||
i18n: 'menu.profile',
|
i18n: 'menu.profile',
|
||||||
})
|
})
|
||||||
const {t} = useI18n()
|
|
||||||
const showPicker = ref(false)
|
|
||||||
const showPicker1 = ref(false)
|
|
||||||
const onConfirm = () => {
|
|
||||||
|
|
||||||
}
|
const {t} = useI18n()
|
||||||
|
const router = useRouter()
|
||||||
|
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([
|
||||||
|
{text: t('realAuth.idCard'), value: 1},
|
||||||
|
{text: t('realAuth.passport'), value: 2},
|
||||||
|
{text: t('realAuth.other'), value: 3},
|
||||||
|
])
|
||||||
|
const goCountryRegion=()=>{
|
||||||
|
router.push({
|
||||||
|
path:'/countryRegion'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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 getData=async ()=>{
|
||||||
|
const res=await offlineQrcode({
|
||||||
|
qrUid:qrUid.value
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
qrData.value=res.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const initData= async ()=>{
|
||||||
|
if (route.query.number){
|
||||||
|
number.value=Number(route.query.number)
|
||||||
|
}
|
||||||
|
if (route.query.qrUid){
|
||||||
|
qrUid.value=route.query.qrUid
|
||||||
|
}
|
||||||
|
//扫付款码进来才有的步骤
|
||||||
|
if (number.value==2){
|
||||||
|
await getData()
|
||||||
|
if (qrData.value.payStatus===4){
|
||||||
|
router.replace('/collectCode/payment')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.query.zone){
|
||||||
|
formData.value.countryCode=route.query.zone
|
||||||
|
}else {
|
||||||
|
formData.value.countryCode='86'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const nextClick=async ()=>{
|
||||||
|
console.log('number.value',number.value)
|
||||||
|
//扫号牌
|
||||||
|
if (number.value==1){
|
||||||
|
if (!isFormComplete(formData.value)){
|
||||||
|
message.warning(t('signature.error.incompleteForm'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//国内签署要用法大大
|
||||||
|
if (formData.value.countryCode==='86'&&formData.value.cardType===1){
|
||||||
|
const res=await fddInfo({
|
||||||
|
phone:formData.value.phone
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
if (res.data.status===2){
|
||||||
|
router.push('/collectCode/signature/protocol')
|
||||||
|
}else {
|
||||||
|
const res1=await signOffline({
|
||||||
|
userInfo:formData.value,
|
||||||
|
signOrder:Number(number.value),
|
||||||
|
})
|
||||||
|
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()
|
||||||
</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') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="grow-1 px-34px">
|
<div class="grow-1 px-34px">
|
||||||
<van-field type="tel" :label-width="161" label="文本" class="mb-10px" placeholder="请输入手机号">
|
<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">手机号</div>
|
<div class="mr-41px whitespace-nowrap">{{ $t('profile.phone') }}</div>
|
||||||
<div>
|
<div @click="goCountryRegion">
|
||||||
<span class="mr-13px">+ 86</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="姓名" class="mb-10px" placeholder="请输入姓名"/>
|
<van-field :label="$t('profile.name')" v-model="formData.userName" class="mb-10px" :placeholder="$t('realAuth.namePlaceholder')"/>
|
||||||
<x-van-select label="性别" :columns="columns"/>
|
<template v-if="number===1">
|
||||||
<x-van-date label="出生日期"/>
|
<x-van-select v-model="formData.gender" :label="$t('realAuth.gender')" :columns="columns"/>
|
||||||
<van-field label="家庭住址" class="mb-10px" placeholder="请输入家庭住址"/>
|
<x-van-date :label="$t('realAuth.birthday')" v-model="formData.birthday" />
|
||||||
<van-field label="所属银行" class="mb-10px" placeholder="请输入所属银行"/>
|
<van-field :label="$t('realAuth.adress')" v-model="formData.address" class="mb-10px" :placeholder="$t('realAuth.adressPlaceholder')"/>
|
||||||
<van-field label="银行卡号码" class="mb-10px" placeholder="请输入银行卡号码"/>
|
<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.idCard')" :columns="columns1"/>
|
||||||
|
<van-field :label="$t('realAuth.idCard')" v-model="formData.cardId" class="mb-10px" :placeholder="$t('realAuth.idCardPlaceholder')"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
<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">下一步</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>
|
||||||
|
@ -1,40 +1,116 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const activeNames = ref(['1']);
|
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";
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'signature.protocol.title'
|
||||||
|
})
|
||||||
|
|
||||||
|
const {t} =useI18n()
|
||||||
|
const {formData,number,qrData}=codeAuthStore()
|
||||||
|
const activeNames = ref([])
|
||||||
|
const router = useRouter()
|
||||||
|
const pmblUrl = ref('') // 存储拍卖笔录的URL
|
||||||
|
|
||||||
|
// 协议列表数据
|
||||||
|
const protocolList = computed(() => {
|
||||||
|
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) {
|
||||||
|
return [
|
||||||
|
{ id: '6', title: t('signature.agreement.transfer'), pdfName: 'pmyjqrs', type: 'local' },
|
||||||
|
{ id: '5', title: t('signature.agreement.record'), pdfName: pmblUrl.value, type: 'remote' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取拍卖笔录PDF
|
||||||
|
const fetchPmblPdf = async () => {
|
||||||
|
try {
|
||||||
|
const res = await contractView({
|
||||||
|
auctionArtworkUuid: qrData.value.auctionArtworkUuid,
|
||||||
|
})
|
||||||
|
pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取拍卖笔录失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听折叠面板变化
|
||||||
|
const handleCollapseChange = (name) => {
|
||||||
|
activeNames.value = name
|
||||||
|
// 当打开拍卖笔录时获取PDF
|
||||||
|
if (name === '5' && !pmblUrl.value) {
|
||||||
|
fetchPmblPdf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
router.push('/collectCode/signature/panel')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const goSignature = () => {
|
||||||
|
router.push({
|
||||||
|
path: '/signature/panel'
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-#EBEBEB h-screen-nav flex flex-col">
|
<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">支付前需同意以下内容并签字</div>
|
<div class="h-50px text-14px text-#191919 bg-#fff flex items-center px-21px mb-6px shrink-0">
|
||||||
<van-collapse v-model="activeNames" class="grow-1">
|
{{ t('signature.tips.prePayment') }}
|
||||||
<van-collapse-item name="1" class="mb-6px">
|
</div>
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
|
||||||
</template>
|
|
||||||
代码是写出来给人看的,附带能在机器上运行。
|
|
||||||
</van-collapse-item>
|
|
||||||
<van-collapse-item name="2" class="mb-6px">
|
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
|
||||||
</template>
|
|
||||||
代码是写出来给人看的,附带能在机器上运行。
|
|
||||||
</van-collapse-item>
|
|
||||||
<van-collapse-item name="3" class="mb-6px">
|
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
|
||||||
</template>
|
|
||||||
代码是写出来给人看的,附带能在机器上运行。
|
|
||||||
</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">同意并签字</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
<van-collapse
|
||||||
:deep(.van-cell__right-icon){
|
accordion
|
||||||
color: #ACACAC;
|
v-model="activeNames"
|
||||||
font-size: 12px;
|
class="grow-1"
|
||||||
}
|
@change="handleCollapseChange"
|
||||||
</style>
|
>
|
||||||
|
<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
|
||||||
|
: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="confirm"
|
||||||
|
>
|
||||||
|
{{ t('signature.action.agree') }}
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
68
app/pages/collectCode/signature/protocol/pdfView/index.vue
Normal file
68
app/pages/collectCode/signature/protocol/pdfView/index.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<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>
|
34
app/pages/collectCode/signature/result/index.vue
Normal file
34
app/pages/collectCode/signature/result/index.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<script setup>
|
||||||
|
import {sessionUserNoCreate} from "~/api-collect-code/goods/index.js";
|
||||||
|
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const {formData,number}=codeAuthStore()
|
||||||
|
const auctionUserNo=ref('')
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'collectCode.signature.result.title'
|
||||||
|
})
|
||||||
|
const res=await sessionUserNoCreate({
|
||||||
|
phone:formData.value.phone
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
auctionUserNo.value=res.data.auctionUserNo
|
||||||
|
}
|
||||||
|
</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="flex flex-col items-center pt-18px px-31px">
|
||||||
|
<div class="text-#000 text-16px mb-4px">{{ t('collectCode.signature.result.success') }}</div>
|
||||||
|
<div class="text-#939393 text-12px mb-31px">●   {{ t('collectCode.signature.result.getNumber') }}   ●</div>
|
||||||
|
<div class="relative">
|
||||||
|
<img class="w-258px h-144px" src="@/static/images/zu6020@2x.png" alt="">
|
||||||
|
<div class="absolute text-#FDD68D text-68px bottom-1px left-1/2 transform translate-x--1/2">{{auctionUserNo}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -5,18 +5,23 @@ import countryCode from './data/index.js';
|
|||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: '国家地区',
|
|
||||||
i18n: 'countryRegion.title',
|
i18n: 'countryRegion.title',
|
||||||
})
|
})
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
console.log('router',router)
|
console.log('router',router)
|
||||||
const { t, locale } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
const value = ref('');
|
const value = ref('');
|
||||||
const alphabet = [
|
const alphabet = computed(() => {
|
||||||
'#',
|
if (!groupedCountries.value) return ['#'];
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
||||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
|
// 获取所有实际存在的分组字母
|
||||||
];
|
const letters = Object.keys(groupedCountries.value)
|
||||||
|
.filter(key => key !== '#')
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
// 确保 # 永远在最前
|
||||||
|
return ['#', ...letters];
|
||||||
|
});
|
||||||
|
|
||||||
// 常用国家的代码列表
|
// 常用国家的代码列表
|
||||||
const frequentCountryCodes = ['CN', 'TW', 'JP', 'US'];
|
const frequentCountryCodes = ['CN', 'TW', 'JP', 'US'];
|
||||||
@ -39,6 +44,7 @@ function groupByPinyinInitial(data) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 处理其他国家
|
// 处理其他国家
|
||||||
data.forEach(country => {
|
data.forEach(country => {
|
||||||
if (!frequentCountryCodes.includes(country.code)) {
|
if (!frequentCountryCodes.includes(country.code)) {
|
||||||
@ -47,10 +53,18 @@ function groupByPinyinInitial(data) {
|
|||||||
locale.value === 'ja-JP' ? country.ja :
|
locale.value === 'ja-JP' ? country.ja :
|
||||||
country.en;
|
country.en;
|
||||||
|
|
||||||
const initial = locale.value === 'ja-JP' ? '' :
|
// 根据语言环境决定使用拼音还是英文首字母
|
||||||
locale.value === 'zh-CN' || locale.value === 'zh-TW' ?
|
let initial;
|
||||||
pinyin(countryName, {style: pinyin.STYLE_FIRST_LETTER})[0][0].toUpperCase() :
|
if (locale.value === 'zh-CN' || locale.value === 'zh-TW') {
|
||||||
countryName.charAt(0).toUpperCase();
|
// 中文和繁体使用拼音首字母
|
||||||
|
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]) {
|
if (!grouped[initial]) {
|
||||||
grouped[initial] = [];
|
grouped[initial] = [];
|
||||||
@ -62,12 +76,38 @@ function groupByPinyinInitial(data) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (locale.value === 'ja-JP') {
|
// 对每个分组内的国家按照对应语言排序
|
||||||
// 日文环境下按照片假名排序
|
Object.keys(grouped).forEach(key => {
|
||||||
grouped[''] = grouped[''].sort((a, b) => a.displayName.localeCompare(b.displayName, 'ja-JP'));
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return grouped;
|
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 groupedCountries = ref([])
|
||||||
@ -83,6 +123,7 @@ const searchCountry = computed(() => {
|
|||||||
const countries = groupedCountries.value[initial].filter(country =>
|
const countries = groupedCountries.value[initial].filter(country =>
|
||||||
country.displayName.toLowerCase().includes(value.value.toLowerCase())
|
country.displayName.toLowerCase().includes(value.value.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (countries.length > 0) {
|
if (countries.length > 0) {
|
||||||
filtered[initial] = countries;
|
filtered[initial] = countries;
|
||||||
}
|
}
|
||||||
@ -103,7 +144,7 @@ const handleCountrySelect = (country) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initData()
|
initData()
|
||||||
|
console.log('searchCountry',searchCountry.value)
|
||||||
// 监听语言变化,重新初始化数据
|
// 监听语言变化,重新初始化数据
|
||||||
watch(locale, () => {
|
watch(locale, () => {
|
||||||
initData()
|
initData()
|
||||||
|
@ -10,7 +10,6 @@ const {
|
|||||||
<div class="px-16px pt-14px">
|
<div class="px-16px pt-14px">
|
||||||
<div class="text-#575757 text-14px" v-html="auctionDetail.info">
|
<div class="text-#575757 text-14px" v-html="auctionDetail.info">
|
||||||
</div>
|
</div>
|
||||||
<xImage :src="auctionDetail.image" class="w-343px"></xImage>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ const handleClose = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<xPopup :show="show" title="拍品详情" @update:show="handleClose">
|
<xPopup :show="show" :title="$t('home.lot_detail')" @update:show="handleClose">
|
||||||
<ItemDetail :detailInfo="detailInfo" />
|
<ItemDetail :detailInfo="detailInfo" />
|
||||||
</xPopup>
|
</xPopup>
|
||||||
</template>
|
</template>
|
@ -1,19 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useRect } from "@vant/use"
|
|
||||||
import { goodStore } from "@/stores/goods"
|
import { goodStore } from "@/stores/goods"
|
||||||
import DetailPopup from '../DetailPopup/index.vue'
|
import DetailPopup from '../DetailPopup/index.vue'
|
||||||
import MasonryWall from '@yeger/vue-masonry-wall'
|
import WaterfallFlow from '@/components/waterfallFlow/index.vue'
|
||||||
const {
|
const {
|
||||||
itemList,
|
itemList,
|
||||||
pageRef,
|
pageRef,
|
||||||
auctionDetail,
|
|
||||||
liveRef,
|
|
||||||
artWorkDetail,
|
|
||||||
currentItem,
|
currentItem,
|
||||||
loading: storeLoading,
|
loading: storeLoading,
|
||||||
getArtworkList,
|
getArtworkList,
|
||||||
getArtworkDetail
|
|
||||||
} = goodStore()
|
} = goodStore()
|
||||||
|
|
||||||
const localState = ref({
|
const localState = ref({
|
||||||
@ -44,7 +39,6 @@ const onRefresh = async () => {
|
|||||||
const openShow = async (item) => {
|
const openShow = async (item) => {
|
||||||
localState.value.showDetail = true
|
localState.value.showDetail = true
|
||||||
currentItem.value = item
|
currentItem.value = item
|
||||||
getArtworkDetail(item.uuid)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -52,59 +46,57 @@ const openShow = async (item) => {
|
|||||||
<div class="px-[16px] pt-[16px]">
|
<div class="px-[16px] pt-[16px]">
|
||||||
<van-pull-refresh
|
<van-pull-refresh
|
||||||
v-model="localState.refreshing"
|
v-model="localState.refreshing"
|
||||||
success-text="刷新成功"
|
|
||||||
:success-duration="700"
|
:success-duration="700"
|
||||||
@refresh="onRefresh"
|
@refresh="onRefresh"
|
||||||
>
|
>
|
||||||
<template #success>
|
<template #success>
|
||||||
<van-icon name="success" /> <span>刷新成功</span>
|
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
||||||
</template>
|
</template>
|
||||||
<van-list
|
<van-list
|
||||||
v-model:loading="storeLoading"
|
v-model:loading="storeLoading"
|
||||||
:finished="localState.finished"
|
:finished="localState.finished"
|
||||||
finished-text="没有更多了"
|
:finished-text="$t('home.finished_text')"
|
||||||
@load="loadMore"
|
@load="loadMore"
|
||||||
>
|
>
|
||||||
<div class="w-full flex gap-[16px]">
|
<div class="w-full flex gap-[16px]">
|
||||||
<masonry-wall :items="itemList" :ssr-columns="2" :maxColumns="2" :minColumns="2" :gap="5">
|
<WaterfallFlow :items="itemList" :column-count="2">
|
||||||
<template #default="{ item, index }">
|
<template #default="{ item, index }">
|
||||||
<div
|
<div
|
||||||
@click="openShow(item)"
|
@click="openShow(item)"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
>
|
>
|
||||||
<div class="relative w-full">
|
<div class="relative w-full">
|
||||||
<img
|
<img
|
||||||
:src="item.artwork?.hdPic"
|
:src="item.artwork?.hdPic"
|
||||||
class="w-full object-cover rounded-4px"
|
class="w-full object-cover rounded-4px"
|
||||||
loading="lazy"
|
/>
|
||||||
/>
|
<div
|
||||||
<div
|
class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[45px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
|
||||||
class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[45px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]"
|
>
|
||||||
>
|
LOT{{ item.index }}
|
||||||
LOT{{ 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>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-[8px]">
|
|
||||||
<div class="text-[14px] text-[#000000] leading-[20px]">
|
|
||||||
{{ item.name }}
|
|
||||||
</div>
|
|
||||||
<div class="mt-[4px] text-[12px] text-[#575757]">
|
|
||||||
起拍价:{{ item?.startPrice??0 }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="item.soldPrice"
|
|
||||||
class="mt-[4px] text-[12px] text-[#b58047]"
|
|
||||||
>
|
|
||||||
成交价:{{ item?.startPrice??0 }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</masonry-wall>
|
</WaterfallFlow>
|
||||||
</div>
|
</div>
|
||||||
</van-list>
|
</van-list>
|
||||||
</van-pull-refresh>
|
</van-pull-refresh>
|
||||||
<DetailPopup v-model:show="localState.showDetail" :detailInfo="artWorkDetail"></DetailPopup>
|
<DetailPopup v-model:show="localState.showDetail" :detailInfo="currentItem"></DetailPopup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -5,27 +5,44 @@ import ItemList from './components/ItemList/index.vue'
|
|||||||
import Cescribe from './components/Cescribe/index.vue'
|
import Cescribe from './components/Cescribe/index.vue'
|
||||||
import {message} from '@/components/x-message/useMessage.js'
|
import {message} from '@/components/x-message/useMessage.js'
|
||||||
import {liveStore} from "~/stores/live/index.js";
|
import {liveStore} from "~/stores/live/index.js";
|
||||||
const {getAuctionDetail,auctionDetail} = goodStore();
|
const {getAuctionDetail, auctionDetail,getArtworkList} = goodStore();
|
||||||
const {fullLive}= liveStore()
|
const {fullLive} = liveStore()
|
||||||
const changeLive = () => {
|
const changeLive = () => {
|
||||||
fullLive.value = true;
|
if (!fullLive.value){
|
||||||
};
|
if (auctionDetail.value.isLiving===1){
|
||||||
if (!auctionDetail.value.uuid){
|
fullLive.value = true;
|
||||||
await getAuctionDetail()
|
getArtworkList(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await getAuctionDetail()
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-grow-1">
|
<div class="grow-1">
|
||||||
<client-only>
|
<client-only>
|
||||||
<liveRoom @click="changeLive" :class="['changeLive', fullLive ? 'expanded' : 'collapsed']"/>
|
<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}} {{$t('home.text2')}}</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">本场拍卖会{{auctionDetail.isLiving===2?'未开始':'已结束'}}</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}} {{$t('home.text2')}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</client-only>
|
</client-only>
|
||||||
<div v-if="!fullLive" class="bg-#fff">
|
<div v-if="!fullLive" class="bg-#fff">
|
||||||
<van-tabs sticky animated>
|
<van-tabs sticky animated>
|
||||||
<van-tab title="拍品列表">
|
<van-tab :title="$t('home.tab1')">
|
||||||
<ItemList></ItemList>
|
<ItemList></ItemList>
|
||||||
</van-tab>
|
</van-tab>
|
||||||
<van-tab title="拍卖说明">
|
<van-tab :title="$t('home.tab2')">
|
||||||
<Cescribe></Cescribe>
|
<Cescribe></Cescribe>
|
||||||
</van-tab>
|
</van-tab>
|
||||||
</van-tabs>
|
</van-tabs>
|
||||||
@ -42,6 +59,7 @@ if (!auctionDetail.value.uuid){
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.van-swipe__indicator) {
|
:deep(.van-swipe__indicator) {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
import Home from './home/index.vue'
|
import Home from './home/index.vue'
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: 'default',
|
||||||
title: '主页',
|
|
||||||
i18n: 'menu.home',
|
i18n: 'menu.home',
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="h-[100vh] w-[100vw]">
|
|
||||||
<SignaturePad v-model="signature" @change="handleSignatureChange"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import SignaturePad from '@/components/SignaturePad.vue'
|
|
||||||
|
|
||||||
const signature = ref('')
|
|
||||||
|
|
||||||
const handleSignatureChange = (imageData) => {
|
|
||||||
// imageData 是 base64 格式的图片数据
|
|
||||||
console.log('签名已更新:', imageData)
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,21 +1,26 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {liveStore} from "@/stores/live/index.js";
|
import {liveStore} from "@/stores/live/index.js";
|
||||||
import {authStore} from "~/stores/auth/index.js";
|
import {authStore} from "~/stores/auth/index.js";
|
||||||
|
import {useI18n} from 'vue-i18n'
|
||||||
const {auctionData} = liveStore()
|
const {auctionData} = liveStore()
|
||||||
const {userInfo}= authStore()
|
const {userInfo}= authStore()
|
||||||
|
function formatThousands(num) {
|
||||||
|
|
||||||
|
return Number(num).toLocaleString();
|
||||||
|
}
|
||||||
const headList=[
|
const headList=[
|
||||||
{
|
{
|
||||||
label:'领先',
|
label:useI18n().t('live_room.head'),
|
||||||
color:'#D03050',
|
color:'#D03050',
|
||||||
value:'head'
|
value:'head'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'出局',
|
label:useI18n().t('live_room.out'),
|
||||||
color:'#939393',
|
color:'#939393',
|
||||||
value:'out'
|
value:'out'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label:'成交',
|
label:useI18n().t('live_room.success'),
|
||||||
color:'#34B633',
|
color:'#34B633',
|
||||||
value:'success'
|
value:'success'
|
||||||
}
|
}
|
||||||
@ -32,19 +37,19 @@ const headItem=(statusCode)=>{
|
|||||||
>
|
>
|
||||||
<transition-group name="list" tag="div">
|
<transition-group name="list" tag="div">
|
||||||
<template v-if="auctionData.wsType==='stopArtwork'">
|
<template v-if="auctionData.wsType==='stopArtwork'">
|
||||||
<div class="text-#939393 text-14px">即将开始下一个拍品</div>
|
<div class="text-#939393 text-14px">{{ $t('live_room.next_lot') }}</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="auctionData.auctionPriceList?.buys?.length>0">
|
<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 h-25px">
|
<div v-for="(item, index) in auctionData.auctionPriceList?.buys" :key="index" class="flex flex-shrink-0 h-25px">
|
||||||
<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-60px" :style="`color: ${headItem(item.statusCode).color}`" >{{ headItem(item.statusCode).label }}</div>
|
||||||
<div class="text-start shrink-0 w-80px">{{ item.auctionType==='local'?'现场竞价':'网络竞价' }}</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.createdAt }}</div>
|
||||||
<div class="text-start shrink-0 w-80px">{{item.baseCurrency}}{{ item.baseMoney }}</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?'我':'' }}</div>
|
<div class="text-start text-#2B53AC shrink-0 w-20px">{{ item.userId===userInfo.ID?$t('live_room.me'):'' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="auctionData.wsType==='newArtwork'">
|
<template v-if="auctionData.wsType==='newArtwork'">
|
||||||
<div class="text-#939393 text-14px">开始拍卖</div>
|
<div class="text-#939393 text-14px">{{ $t('live_room.start') }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</transition-group>
|
</transition-group>
|
||||||
|
@ -54,7 +54,6 @@ const handleCapture = () => {
|
|||||||
onClick:()=>{
|
onClick:()=>{
|
||||||
router.replace('/')
|
router.replace('/')
|
||||||
fullLive.value=true
|
fullLive.value=true
|
||||||
console.log('执行')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -66,14 +65,14 @@ const handleCapture = () => {
|
|||||||
<van-dialog :show="show" show-cancel-button @cancel="close" @confirm="confirm">
|
<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">
|
<div class="flex flex-col pt-18px pb-13px justify-between items-center h-144px">
|
||||||
<template v-if="payStatus===0">
|
<template v-if="payStatus===0">
|
||||||
<div class="text-#000 text-16px font-600 ">支付全部</div>
|
<div class="text-#000 text-16px font-600 ">{{ $t('live_room.all_pay') }}</div>
|
||||||
<div class="text-#000 text-16px ">RMB 5,000</div>
|
<div class="text-#000 text-16px ">RMB 5,000</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="payStatus===1">
|
<template v-if="payStatus===1">
|
||||||
<div class="text-#000 text-16px font-600 ">支付部分</div>
|
<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">
|
<input class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" placeholder="最多RMB5,000">
|
||||||
</template>
|
</template>
|
||||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===0 ? '支付部分' : '支付全部'}}</div>
|
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===0 ? $t('live_room.part_pay') : $t('live_room.all_pay')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</van-dialog>
|
</van-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,7 +23,7 @@ const cancel= () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<van-dialog style="overflow: visible" :show="show" show-cancel-button :show-confirm-button="false" cancelButtonText="返回" cancelButtonColor="#2B53AC" @cancel="cancel">
|
<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">
|
<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="">
|
<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 class="mt-94px text-#A9A9A9 text-16px">{{price}}</div>
|
||||||
|
@ -1,48 +1,225 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ref} from "vue";
|
import { ref, computed, onMounted, onBeforeUnmount } from "vue"
|
||||||
import lockClosed from "@/static/images/lockdfd@2x.png";
|
import lockClosed from "@/static/images/lockdfd@2x.png"
|
||||||
import lockOpen from "@/static/images/lock4@2x.png";
|
import lockOpen from "@/static/images/lock4@2x.png"
|
||||||
import {liveStore} from "@/stores/live/index.js";
|
import { liveStore } from "@/stores/live/index.js"
|
||||||
import xButton from '@/components/x-button/index.vue'
|
import xButton from '@/components/x-button/index.vue'
|
||||||
import tangPopup from './tangPopup.vue'
|
import tangPopup from './tangPopup.vue'
|
||||||
import {goodStore} from "@/stores/goods/index.js";
|
import { goodStore } from "@/stores/goods/index.js"
|
||||||
import {authStore} from "~/stores/auth/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} = liveStore();
|
const { quoteStatus, changeStatus, show, auctionData, getSocketData ,lastSnapshot,fullLive} = liveStore()
|
||||||
const {pageRef} = goodStore();
|
const { pageRef } = goodStore()
|
||||||
const {userInfo} = authStore()
|
const { userInfo ,payment} = authStore()
|
||||||
const showTang = ref(false)
|
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) {
|
||||||
|
console.error('未找到视频元素')
|
||||||
|
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) {
|
||||||
|
console.error('获取视频截图失败:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCapture = () => {
|
||||||
|
/* const imageUrl = captureVideoFrame()
|
||||||
|
if (imageUrl) {
|
||||||
|
lastSnapshot.value=imageUrl
|
||||||
|
|
||||||
|
/!* showMinWindow(lastSnapshot.value,{
|
||||||
|
onClick:()=>{
|
||||||
|
router.replace('/')
|
||||||
|
fullLive.value=true
|
||||||
|
console.log('执行')
|
||||||
|
}
|
||||||
|
})*!/
|
||||||
|
}*/
|
||||||
|
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 = () => {
|
const openOne = () => {
|
||||||
showTang.value = true
|
showTang.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const paySide = computed(() => {
|
const paySide = computed(() => {
|
||||||
//当前是否已成交,以及成交人是当前登录用户
|
//当前是否已成交
|
||||||
if (auctionData.value.artwork?.isSoled && auctionData.value.artwork?.buyInfo.userID === userInfo.value.ID) {
|
return auctionData.value.needPayBuys?.length>0
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const goPay = () => {
|
const goPay = () => {
|
||||||
show.value = true
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-white w-60px rounded-l-4px overflow-hidden">
|
<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="openOne" style="border: none;border-radius: 0">
|
<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 class="text-center flex flex-col justify-center items-center text-#7D7D7F text-12px">
|
||||||
<div>拍品</div>
|
<div>{{ $t('live_room.lots') }}</div>
|
||||||
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
<div>({{ auctionData?.artwork?.index }}/{{ pageRef.itemCount ?? 0 }})</div>
|
||||||
</div>
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
<tangPopup v-model:show="showTang"></tangPopup>
|
<tangPopup v-model:show="showTang"></tangPopup>
|
||||||
|
|
||||||
<!-- 出价开关 -->
|
<!-- 出价开关 -->
|
||||||
<van-button class="w-60px !h-60px" @click="changeStatus"
|
<van-button
|
||||||
style="border-right: none;border-left: none;border-radius: 0;padding: 0">
|
class="w-60px !h-60px"
|
||||||
<div class="text-center flex flex-col justify-center items-center">
|
@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">
|
<div class="mb-4px">
|
||||||
<img
|
<img
|
||||||
:src="quoteStatus ? lockClosed : lockOpen"
|
:src="quoteStatus ? lockClosed : lockOpen"
|
||||||
@ -50,19 +227,36 @@ const goPay = () => {
|
|||||||
alt="锁图标"
|
alt="锁图标"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div :class="quoteStatus ? 'text-gray-500' : 'text-blue-600'" class="text-10px transition-colors duration-200">
|
<div
|
||||||
{{ quoteStatus ? '关闭出价' : '开启出价' }}
|
: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>
|
||||||
</div>
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
<!-- 支付 -->
|
<!-- 支付 -->
|
||||||
<van-button v-if="paySide" class="w-60px !h-60px" style="border: none;border-radius: 0" @click="goPay">
|
<van-button
|
||||||
<div class="text-center flex flex-col justify-center items-center text-yellow-600">
|
v-if="paySide"
|
||||||
<div class="text-10px">RMB</div>
|
class="w-60px !h-60px"
|
||||||
<div class="text-12px">5,000</div>
|
style="border: none;border-radius: 0"
|
||||||
<div class="text-10px">去支付</div>
|
@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>
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cursor-move {
|
||||||
|
cursor: move;
|
||||||
|
user-select: none;
|
||||||
|
touch-action: none;
|
||||||
|
transition: left 0.3s ease;
|
||||||
|
}
|
||||||
|
</style>
|
@ -63,6 +63,11 @@ const loadMore = async () => {
|
|||||||
const { finished } = await getArtworkList()
|
const { finished } = await getArtworkList()
|
||||||
localState.value.finished = finished
|
localState.value.finished = finished
|
||||||
}
|
}
|
||||||
|
watch(()=>{
|
||||||
|
return auctionData.value?.artwork?.index
|
||||||
|
},(newValue)=>{
|
||||||
|
console.log('newValue',newValue)
|
||||||
|
})
|
||||||
watch(()=>props.show,(newValue)=>{
|
watch(()=>props.show,(newValue)=>{
|
||||||
if (newValue){
|
if (newValue){
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
@ -76,23 +81,23 @@ watch(()=>props.show,(newValue)=>{
|
|||||||
<div>
|
<div>
|
||||||
<x-popup :show="show" @update:show="close">
|
<x-popup :show="show" @update:show="close">
|
||||||
<template #title>
|
<template #title>
|
||||||
<div class="text-#000 text-16px">拍品列表</div>
|
<div class="text-#000 text-16px">{{ $t('home.tab1')}}</div>
|
||||||
<div class="text-#939393 text-16px ml-14px">共{{ pageRef.itemCount }}个拍品</div>
|
<div class="text-#939393 text-16px ml-14px">{{ $t('live_room.total') }}{{ pageRef.itemCount }}{{ $t('live_room.lots_num') }}</div>
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<van-pull-refresh
|
<van-pull-refresh
|
||||||
v-model="localState.refreshing"
|
v-model="localState.refreshing"
|
||||||
success-text="刷新成功"
|
:success-text="$t('home.refresh_show')"
|
||||||
:success-duration="700"
|
:success-duration="700"
|
||||||
@refresh="onRefresh"
|
@refresh="onRefresh"
|
||||||
>
|
>
|
||||||
<template #success>
|
<template #success>
|
||||||
<van-icon name="success" /> <span>刷新成功</span>
|
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
||||||
</template>
|
</template>
|
||||||
<van-list
|
<van-list
|
||||||
v-model:loading="storeLoading"
|
v-model:loading="storeLoading"
|
||||||
:finished="localState.finished"
|
:finished="localState.finished"
|
||||||
finished-text="没有更多了"
|
:finished-text="$t('home.finished_text')"
|
||||||
@load="loadMore"
|
@load="loadMore"
|
||||||
|
|
||||||
>
|
>
|
||||||
@ -113,14 +118,14 @@ watch(()=>props.show,(newValue)=>{
|
|||||||
loading="lazy"
|
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 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-if="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">投屏中</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>
|
<div>
|
||||||
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
<div class="ellipsis line-height-20px text-16px font-600 min-h-40px">
|
||||||
{{ item.artworkTitle }}
|
{{ item.artworkTitle }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-14px text-#575757">起拍价:RMB 1,000</div>
|
<div class="text-14px text-#575757">{{ $t('home.start_price') }}:{{item?.startPriceCurrency}} {{item?.startPrice}}</div>
|
||||||
<div class="text-14px text-#B58047">成交价:等待更新</div>
|
<div class="text-14px text-#B58047" v-if="item.soldPrice">{{ $t('home.close_price') }}:{{item.soldPrice}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-list>
|
</van-list>
|
||||||
|
@ -1,126 +1,167 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {ref, onMounted, onBeforeUnmount, watch} from 'vue'
|
import {ref, onMounted, onBeforeUnmount, watch} from 'vue'
|
||||||
import Aliplayer from 'aliyun-aliplayer'
|
import AliyunPlayer from 'aliyun-aliplayer'
|
||||||
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
|
import 'aliyun-aliplayer/build/skins/default/aliplayer-min.css'
|
||||||
import sideButton from '@/pages/liveRoom/components/SideButton/index.vue'
|
import sideButton from '@/pages/liveRoom/components/SideButton/index.vue'
|
||||||
import broadcast from '@/pages/liveRoom/components/Broadcast/index.vue'
|
import broadcast from '@/pages/liveRoom/components/Broadcast/index.vue'
|
||||||
import {liveStore} from "@/stores/live/index.js"
|
import {liveStore} from "@/stores/live/index.js"
|
||||||
|
import liveLoading from '@/components/liveLoading/index.vue'
|
||||||
import paymentResults from '@/pages/liveRoom/components/PaymentResults/index.vue'
|
import paymentResults from '@/pages/liveRoom/components/PaymentResults/index.vue'
|
||||||
import paymentInput from '@/pages/liveRoom/components/PaymentInput/index.vue'
|
import paymentInput from '@/pages/liveRoom/components/PaymentInput/index.vue'
|
||||||
import {goodStore} from "@/stores/goods/index.js"
|
import {goodStore} from "@/stores/goods/index.js"
|
||||||
import {message} from "~/components/x-message/useMessage.js"
|
import {message} from "~/components/x-message/useMessage.js"
|
||||||
import { showDialog } from 'vant';
|
import {showConfirmDialog} from 'vant';
|
||||||
import {artworkBuy} from "@/api/goods/index.js"
|
import {artworkBuy} from "@/api/goods/index.js"
|
||||||
|
import {useI18n} from 'vue-i18n'
|
||||||
|
import {CountUp} from 'countup.js'
|
||||||
|
const { t } = useI18n()
|
||||||
|
const countUpRef = ref(null)
|
||||||
|
const nextPriceRef = ref(null)
|
||||||
|
const { auctionDetail} = goodStore();
|
||||||
const player = ref(null)
|
const player = ref(null)
|
||||||
const {quoteStatus, show, playerId, show1, auctionData, getSocketData, getLiveLink,fullLive} = liveStore()
|
const {quoteStatus, show, playerId, show1, auctionData, getSocketData, getLiveLink, fullLive} = liveStore()
|
||||||
const isPlayerReady = ref(false)
|
|
||||||
const pullLink = ref('')
|
const pullLink = ref('')
|
||||||
|
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
title: '主页',
|
|
||||||
i18n: 'login.title',
|
|
||||||
})
|
|
||||||
const handlePlayerError = (error) => {
|
const handlePlayerError = (error) => {
|
||||||
console.error('播放器错误:', error)
|
console.error('播放器错误:', error)
|
||||||
player.value?.play()
|
showConfirmDialog({
|
||||||
|
message: t('live_room.error_mess'),
|
||||||
|
showCancelButton: true
|
||||||
|
}).then(() => {
|
||||||
|
initializePlayer()
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
// player.value?.play()
|
||||||
}
|
}
|
||||||
|
const loading1=ref(false)
|
||||||
const initializePlayer = async () => {
|
const initializePlayer = async () => {
|
||||||
try {
|
try {
|
||||||
if (player.value) {
|
if (player.value) {
|
||||||
player.value.dispose()
|
player.value.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否是微信浏览器
|
||||||
|
const isWechat = /MicroMessenger/i.test(navigator.userAgent)
|
||||||
|
|
||||||
const playerConfig = {
|
const playerConfig = {
|
||||||
id: playerId.value,
|
id: playerId.value,
|
||||||
source: pullLink.value,
|
source: pullLink.value,
|
||||||
isLive: true,
|
isLive: true,
|
||||||
preload: true,
|
preload: true,
|
||||||
autoplayPolicy: {fallbackToMute: true},
|
autoplay: true, // 改为 true
|
||||||
|
muted: true, // 默认静音
|
||||||
|
diagnosisButtonVisible:false,
|
||||||
|
// vodRetry:10,
|
||||||
|
// liveRetry:10,
|
||||||
|
autoplayPolicy: {
|
||||||
|
fallbackToMute: true
|
||||||
|
},
|
||||||
|
width: '100%', //容器的大小
|
||||||
|
height: '100%', //容器的大小
|
||||||
|
skinLayout: false,
|
||||||
controlBarVisibility: 'never',
|
controlBarVisibility: 'never',
|
||||||
|
license: {
|
||||||
|
domain: "szjixun.cn",
|
||||||
|
key: "OProxmWaOZ2XVHXLtf4030126521c43429403194970aa8af9"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.value = new Aliplayer(playerConfig, (playerInstance) => {
|
player.value = new AliyunPlayer(playerConfig, (playerInstance) => {
|
||||||
isPlayerReady.value = true
|
// 在微信环境下,需要用户手动触发播放
|
||||||
|
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()
|
playerInstance?.play()
|
||||||
})
|
})
|
||||||
|
player.value.on('playing', () => {
|
||||||
|
loading1.value = false
|
||||||
|
|
||||||
|
})
|
||||||
|
player.value.on('loading', () => {
|
||||||
|
console.log('loading')
|
||||||
|
})
|
||||||
player.value.on('error', handlePlayerError)
|
player.value.on('error', handlePlayerError)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showDialog({
|
showConfirmDialog({
|
||||||
message: '直播内容获取失败,是否刷新页面重新获取',
|
message: t('live_room.error_mess'),
|
||||||
|
showCancelButton: true
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
location.reload()
|
initializePlayer()
|
||||||
// on close
|
}).catch(() => {
|
||||||
}) .catch(() => {
|
})
|
||||||
// on cancel
|
|
||||||
});;
|
|
||||||
console.error('播放器初始化失败:', error)
|
console.error('播放器初始化失败:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
pullLink.value = await getLiveLink()
|
pullLink.value = await getLiveLink()
|
||||||
initializePlayer()
|
if (auctionDetail.value.isLiving===1){
|
||||||
|
initializePlayer()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
player.value?.dispose()
|
player.value?.dispose()
|
||||||
player.value = null
|
player.value = null
|
||||||
})
|
})
|
||||||
watch(()=>fullLive.value, (newVal) => {
|
watch(() => fullLive.value, async (newVal) => {
|
||||||
if (newVal) {
|
if (!newVal) return
|
||||||
getSocketData()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
await getSocketData()
|
||||||
|
|
||||||
|
})
|
||||||
const goBuy = async () => {
|
const goBuy = async () => {
|
||||||
const res = await artworkBuy({
|
const res = await artworkBuy({
|
||||||
auctionArtworkUuid: auctionData.value?.artwork?.uuid,
|
auctionArtworkUuid: auctionData.value?.artwork?.uuid,
|
||||||
buyMoney: String(auctionData.value?.nowAuctionPrice?.nextPrice ?? 0)
|
buyMoney: String(auctionData?.value.nowAuctionPrice?.nowPrice??0)
|
||||||
})
|
})
|
||||||
if (res.status === 0) {
|
if (res.status === 0) {
|
||||||
message.success('出价成功')
|
message.success(t('live_room.success_mess'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tipOpen = () => {
|
const tipOpen = () => {
|
||||||
message.warning('出价状态未开启')
|
message.warning(t('live_room.warn_mess'))
|
||||||
}
|
|
||||||
const updateShow=()=>{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative h-full">
|
<div class="relative h-full">
|
||||||
<div :id="playerId" class="w-full h-full"></div>
|
<div :id="playerId" class="w-full h-full"></div>
|
||||||
<transition>
|
<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">
|
<div v-if="fullLive">
|
||||||
<sideButton class="absolute top-196px right-0 z-999"></sideButton>
|
<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"
|
<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)">
|
style="bottom:calc(var(--safe-area-inset-bottom) + 26px)">
|
||||||
<div class="text-16px text-#FFB25F font-600">
|
<div class="text-16px text-#FFB25F font-600 flex">
|
||||||
当前价:{{ auctionData?.nowAuctionPrice?.currency }}
|
<div class="mr-5px">{{ t('live_room.now_price') }}:{{ auctionData?.nowAuctionPrice?.currency }}</div>
|
||||||
<van-rolling-text class="my-rolling-text" :start-num="0" :duration="0.5"
|
<div class="min-w-50px">{{auctionData?.nowAuctionPrice?.nowPrice}}</div>
|
||||||
:target-num="auctionData?.nowAuctionPrice?.nowPrice??0" direction="up"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-16px text-#fff font-600">
|
<div class="text-16px text-#fff font-600 flex">
|
||||||
下口价:{{ auctionData?.nowAuctionPrice?.currency }}
|
<div class="mr-5px">{{ t('live_room.lower_price') }}:{{ auctionData?.nowAuctionPrice?.currency }}</div>
|
||||||
<van-rolling-text class="my-rolling-text1" :start-num="0" :duration="0.5"
|
<div class="min-w-50px">{{auctionData?.nowAuctionPrice?.nextPrice}}</div>
|
||||||
:target-num="auctionData?.nowAuctionPrice?.nextPrice??0" direction="up"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-if="quoteStatus" class="mt-10px mb-10px">
|
<div v-if="quoteStatus&&auctionData?.nowAuctionPrice?.nowPrice!=='0'" class="mt-10px mb-10px">
|
||||||
<van-button @click="goBuy" color="#FFB25F" class="w-344px !h-[40px]">
|
<van-button @click.stop="goBuy" color="#FFB25F" class="w-344px !h-[40px]">
|
||||||
<div>{{
|
<div>{{
|
||||||
`确认出价 ${auctionData?.nowAuctionPrice?.currency} ${auctionData?.nowAuctionPrice?.nextPrice ?? 0}`
|
`${t('live_room.confirm')} ${auctionData?.nowAuctionPrice?.currency} ${auctionData?.nowAuctionPrice?.nowPrice ?? 0}`
|
||||||
}}</div>
|
}}
|
||||||
|
</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="mt-10px mb-10px">
|
<div v-else class="mt-10px mb-10px">
|
||||||
<van-button @click="tipOpen" color="#D6D6D8" class="w-344px !h-[40px]" v-if="!quoteStatus">
|
<van-button @click="tipOpen" color="#D6D6D8" class="w-344px !h-[40px]" >
|
||||||
<div class="text-#7D7D7F text-14px">点击"开启出价",即刻参与竞拍</div>
|
<div class="text-#7D7D7F text-14px">{{ t('live_room.button') }}</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -134,36 +175,35 @@ const updateShow=()=>{
|
|||||||
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">
|
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-11px whitespace-nowrap">LOT{{ auctionData.artwork.index }}</div>
|
||||||
<div class="mr-10px truncate">{{ auctionData.artwork.name }}</div>
|
<div class="mr-10px truncate">{{ auctionData.artwork.name }}</div>
|
||||||
<div class="whitespace-nowrap">开始拍卖</div>
|
<div class="whitespace-nowrap">{{ t('live_room.start') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
#J_prismPlayer {
|
|
||||||
width: 100%;
|
|
||||||
height: 100% !important;
|
|
||||||
|
|
||||||
& > video {
|
<style scoped lang="scss">
|
||||||
width: 100%;
|
/* 定义过渡动画 */
|
||||||
height: 100%;
|
.fade-enter-active {
|
||||||
}
|
transition: opacity 1s ease;
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.v-enter-active,
|
|
||||||
.v-leave-active {
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.v-enter-from,
|
.fade-leave-active {
|
||||||
.v-leave-to {
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 定义进入和离开的状态 */
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fade-enter-to,
|
||||||
|
.fade-leave-from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.my-rolling-text {
|
.my-rolling-text {
|
||||||
--van-rolling-text-item-width: 10px;
|
--van-rolling-text-item-width: 10px;
|
||||||
--van-rolling-text-font-size: 16px;
|
--van-rolling-text-font-size: 16px;
|
||||||
|
@ -5,13 +5,13 @@ import countryCode from '../countryRegion/data/index.js'
|
|||||||
import {senCode, userLogin} from "@/api/auth/index.js";
|
import {senCode, userLogin} from "@/api/auth/index.js";
|
||||||
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 {userInfo,token}= authStore()
|
import {fddCheck} from "~/api/goods/index.js";
|
||||||
|
const {userInfo,token,selectedZone}= authStore()
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { locale } = useI18n()
|
const { locale } = useI18n()
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
title: '登录',
|
i18n: 'login.title'
|
||||||
i18n: 'login.title',
|
|
||||||
})
|
})
|
||||||
const loadingRef=ref({
|
const loadingRef=ref({
|
||||||
loading1:false,
|
loading1:false,
|
||||||
@ -37,13 +37,14 @@ const startCountdown=()=> {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
const countdown = ref(0);
|
const countdown = ref(0);
|
||||||
const phoneNum = ref('17630920520')
|
const phoneNum = ref('')
|
||||||
const code = ref('123789')
|
const code = ref('')
|
||||||
const pane = ref(0)
|
const pane = ref(0)
|
||||||
const showKeyboard = ref(false);
|
const showKeyboard = ref(false);
|
||||||
// 根据语言获取默认国家
|
// 根据语言获取默认国家
|
||||||
const getDefaultCountry = () => {
|
const getDefaultCountry = () => {
|
||||||
let defaultCode = 'CN' // 默认中国大陆
|
let defaultCode = 'CN' // 默认中国大陆
|
||||||
|
console.log('locale.value',locale.value)
|
||||||
switch (locale.value) {
|
switch (locale.value) {
|
||||||
case 'zh-CN':
|
case 'zh-CN':
|
||||||
defaultCode = 'CN'
|
defaultCode = 'CN'
|
||||||
@ -71,10 +72,12 @@ const getDefaultCountry = () => {
|
|||||||
|
|
||||||
const defaultCountry = getDefaultCountry()
|
const defaultCountry = getDefaultCountry()
|
||||||
|
|
||||||
// 获取选择的国家信息
|
|
||||||
const selectedZone = ref(route.query.zone || defaultCountry.zone)
|
|
||||||
const selectedCountry = ref(route.query.countryName || defaultCountry.name)
|
|
||||||
|
|
||||||
|
const selectedCountry = ref(route.query.countryName || defaultCountry.name)
|
||||||
|
console.log('selectedCountry',selectedCountry.value)
|
||||||
|
onMounted(()=>{
|
||||||
|
selectedZone.value=route.query.zone || defaultCountry.zone
|
||||||
|
})
|
||||||
// 监听语言变化,更新默认国家
|
// 监听语言变化,更新默认国家
|
||||||
watch(locale, () => {
|
watch(locale, () => {
|
||||||
if (!route.query.zone) {
|
if (!route.query.zone) {
|
||||||
@ -121,14 +124,42 @@ const goLogin =async () => {
|
|||||||
userInfo.value=res.data.accountInfo
|
userInfo.value=res.data.accountInfo
|
||||||
token.value=res.data.token
|
token.value=res.data.token
|
||||||
|
|
||||||
if (!res.data.isReal){
|
if (res.data?.accountInfo?.userExtend?.isReal===0){
|
||||||
await router.push('/realAuth');
|
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
|
||||||
|
}
|
||||||
|
console.log('123')
|
||||||
}else {
|
}else {
|
||||||
await router.push('/');
|
await router.push('/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadingRef.value.loading2=false
|
loadingRef.value.loading2=false
|
||||||
}
|
}
|
||||||
|
const isKeyboardVisible = ref(false)
|
||||||
|
const windowHeight = ref(window.innerHeight)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 记录初始窗口高度
|
||||||
|
windowHeight.value = window.innerHeight
|
||||||
|
|
||||||
|
// 监听窗口大小变化
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
// 如果当前高度明显小于初始高度,认为键盘已打开
|
||||||
|
isKeyboardVisible.value = window.innerHeight < windowHeight.value * 0.8
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('resize', () => {})
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -138,7 +169,7 @@ const goLogin =async () => {
|
|||||||
</div>
|
</div>
|
||||||
<van-swipe ref="vanSwipeRef" :show-indicators="false" :touchable="false" :lazy-render="true" :loop="false">
|
<van-swipe ref="vanSwipeRef" :show-indicators="false" :touchable="false" :lazy-render="true" :loop="false">
|
||||||
<van-swipe-item >
|
<van-swipe-item >
|
||||||
<div v-show="pane===0">
|
<div v-if="pane===0">
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="w-full flex justify-between" @click="goToPage">
|
<div class="w-full flex justify-between" @click="goToPage">
|
||||||
<div class="text-[16px] text-[#000]">
|
<div class="text-[16px] text-[#000]">
|
||||||
@ -158,37 +189,37 @@ const goLogin =async () => {
|
|||||||
<div />
|
<div />
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[55px]">
|
<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 :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>
|
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode') }}</van-button>
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.getCode')
|
|
||||||
}}</van-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</van-swipe-item>
|
</van-swipe-item>
|
||||||
<van-swipe-item>
|
<van-swipe-item>
|
||||||
<div v-show="pane===1">
|
<div v-if="pane===1">
|
||||||
<div class="flex mb-[16px]">
|
<div class="flex mb-[16px]">
|
||||||
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('login.hasSendTo') }}</div>
|
<div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('login.hasSendTo') }}</div>
|
||||||
<div class="text-[16px] text-[#000]">+{{ selectedZone }} {{ phoneNum }}</div>
|
<div class="text-[16px] text-[#000]">+{{ selectedZone }} {{ phoneNum }}</div>
|
||||||
</div>
|
</div>
|
||||||
<van-password-input :value="code" :gutter="10" :mask="false" focused @focus="showKeyboard = true" />
|
<van-password-input :value="code" :gutter="10" :mask="false" focused @focus="showKeyboard = true" />
|
||||||
<div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'} text-14px`">
|
<div class="flex justify-between">
|
||||||
{{ $t('login.reSend') }}<span v-if="countdown>0">({{countdown}})</span>
|
<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>
|
||||||
<div class="mt-[17px]">
|
<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">{{
|
<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>
|
||||||
$t('login.login')
|
|
||||||
}}</van-button>
|
|
||||||
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.login') }}</van-button>
|
<van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('login.login') }}</van-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[17px]">
|
|
||||||
<van-button type="primary" @click="goBack" block style="height: 48px">{{ $t('login.back') }}</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</van-swipe-item>
|
</van-swipe-item>
|
||||||
</van-swipe>
|
</van-swipe>
|
||||||
<van-number-keyboard v-model="code" :show="showKeyboard" @blur="showKeyboard = false" />
|
<van-number-keyboard v-model="code" :show="showKeyboard" @blur="showKeyboard = false" />
|
||||||
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
15
app/pages/payment/external/index.vue
vendored
Normal file
15
app/pages/payment/external/index.vue
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<iframe>
|
||||||
|
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
84
app/pages/payment/index.vue
Normal file
84
app/pages/payment/index.vue
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<script setup>
|
||||||
|
import {liveStore} from "~/stores/live/index.js";
|
||||||
|
import {createBuyOrder} from "~/api/goods/index.js";
|
||||||
|
import {goodStore} from "~/stores/goods/index.js";
|
||||||
|
import { showLoadingToast ,closeToast} from 'vant';
|
||||||
|
import {authStore} from "~/stores/auth/index.js";
|
||||||
|
import {message} from "~/components/x-message/useMessage.js";
|
||||||
|
const {checkoutSessionUrl,payment}= authStore()
|
||||||
|
const payStatus=ref(0)
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'payment.title'
|
||||||
|
})
|
||||||
|
const changePayStatus=()=>{
|
||||||
|
payStatus.value=payStatus.value===0?1:0
|
||||||
|
}
|
||||||
|
const { auctionData} = liveStore()
|
||||||
|
const amount=ref('')
|
||||||
|
const confirmPay=async ()=>{
|
||||||
|
if (payStatus.value===1&&!amount.value){
|
||||||
|
message.warning(t('payment.amountRequired'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (Number(payment.value.leftPrice)<Number(amount.value)){
|
||||||
|
message.warning(t('payment.exceedAmount'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showLoadingToast({
|
||||||
|
message: t('payment.loading'),
|
||||||
|
forbidClick: true,
|
||||||
|
});
|
||||||
|
const res=await createBuyOrder({
|
||||||
|
buyUid:payment.value.buyUid,
|
||||||
|
price:payStatus.value===0?payment.value.leftPrice:amount.value,
|
||||||
|
currency:payment.value.leftCurrency,
|
||||||
|
testReturnHost:window.location.origin,
|
||||||
|
testReturnEndPoint:'/payment/result'
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
window.location.href=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>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<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.payAll') : t('payment.payPartial')}}</div>
|
||||||
|
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">{{payment.leftCurrency}} {{payment?.leftPrice}}</div>
|
||||||
|
<div class="mb-12px" v-else>
|
||||||
|
<input v-model="amount" class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" :placeholder="`最多${payment.leftCurrency}${payment?.leftPrice}`" @input="handleInput">
|
||||||
|
</div>
|
||||||
|
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===1 ? t('payment.payAll') : t('payment.payPartial')}}</div>
|
||||||
|
<div class="w-full mt-auto mb-40px">
|
||||||
|
<van-button type="primary" block @click="confirmPay">
|
||||||
|
{{ t('payment.confirm') }}
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
44
app/pages/payment/result/index.vue
Normal file
44
app/pages/payment/result/index.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<script setup>
|
||||||
|
import {orderQuery} from "~/api/goods/index.js";
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'payment.text1',
|
||||||
|
})
|
||||||
|
const router = useRouter()
|
||||||
|
const {t}=useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const resData=ref({})
|
||||||
|
const res=await orderQuery({
|
||||||
|
orderNo:route.query.orderNo
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
resData.value=res.data
|
||||||
|
}
|
||||||
|
const statusLabel={
|
||||||
|
1:t('payment.text2'),
|
||||||
|
2:t('payment.text3'),
|
||||||
|
3:t('payment.text4'),
|
||||||
|
4:t('payment.text5'),
|
||||||
|
}
|
||||||
|
const goHome=()=>{
|
||||||
|
router.push('/')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px">
|
||||||
|
<div class="flex flex-col items-center mt-150px">
|
||||||
|
<img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt="">
|
||||||
|
<div class="text-#000 text-16px mb-25px">{{statusLabel[resData.status]}}!</div>
|
||||||
|
<div class="text-#999 text-16px">{{resData.currency}}{{resData.money}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-full mt-auto mb-40px">
|
||||||
|
<van-button type="primary" block @click="goHome">
|
||||||
|
{{ t('payment.backToHome') }}
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
14
app/pages/privacyPolicy/index.vue
Normal file
14
app/pages/privacyPolicy/index.vue
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
i18n: 'login.privacyPolicy'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="px-10px py-20px"><iframe class="w-full h-100vh" src="/privacyPolicy.html"></iframe></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -1,120 +1,160 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {userArtworks} from "@/api/goods/index.js";
|
import { userArtworks } from "@/api/goods/index.js"
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
import { authStore } from "@/stores/auth/index.js"
|
||||||
import xImage from '@/components/x-image/index.vue'
|
import xImage from '@/components/x-image/index.vue'
|
||||||
import {goodStore} from "~/stores/goods/index.js";
|
import { ref } from "vue"
|
||||||
import {ref} from "vue";
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: 'default',
|
||||||
title: '我的',
|
|
||||||
i18n: 'menu.profile',
|
i18n: 'menu.profile',
|
||||||
})
|
})
|
||||||
const {artWorkDetail} = goodStore()
|
const {t}=useI18n();
|
||||||
const myList=ref([])
|
|
||||||
const showMyList=ref([])
|
|
||||||
const {userInfo}= authStore()
|
|
||||||
const groupAndSortByDate=(data)=> {
|
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return Object.values(data.reduce((acc, curr) => {
|
|
||||||
if (!acc[curr.userCreatedAt]) {
|
|
||||||
acc[curr.userCreatedAt] = {
|
|
||||||
userCreatedAt: curr.userCreatedAt,
|
|
||||||
list: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
acc[curr.userCreatedAt].list.push(curr)
|
|
||||||
return acc;
|
|
||||||
}, {})).sort((a, b) => new Date(b.userCreatedAt) - new Date(a.userCreatedAt));
|
|
||||||
}
|
|
||||||
const initData=async ()=>{
|
|
||||||
const res=await userArtworks({})
|
|
||||||
if (res.status===0){
|
|
||||||
myList.value=res.data.data
|
|
||||||
showMyList.value=groupAndSortByDate(myList.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const { userInfo,payment } = authStore()
|
||||||
|
const showMyList = ref([])
|
||||||
const localState = ref({
|
const localState = ref({
|
||||||
finished: false,
|
finished: true,
|
||||||
refreshing: false,
|
refreshing: false
|
||||||
showDetail: false,
|
|
||||||
showHeight: ''
|
|
||||||
})
|
})
|
||||||
initData()
|
|
||||||
const goPay=()=>{
|
const groupByDate = (data) => {
|
||||||
router.push({
|
if (!Array.isArray(data)) return []
|
||||||
path:'/signature/personal-Info'
|
|
||||||
})
|
return Object.values(data.reduce((acc, curr) => {
|
||||||
}
|
const date = curr.userCreatedAt
|
||||||
const goDetail=(item)=>{
|
if (!acc[date]) {
|
||||||
router.push({
|
acc[date] = { userCreatedAt: date, list: [] }
|
||||||
path:'/artDetail',
|
|
||||||
query:{
|
|
||||||
uuid:item.uuid
|
|
||||||
}
|
}
|
||||||
})
|
acc[date].list.push(curr)
|
||||||
|
return acc
|
||||||
|
}, {})).sort((a, b) => new Date(b.userCreatedAt) - new Date(a.userCreatedAt))
|
||||||
}
|
}
|
||||||
const onRefresh = async () => {
|
|
||||||
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
localState.value.refreshing = true
|
const res = await userArtworks({})
|
||||||
localState.value.finished = false
|
if (res.status === 0) {
|
||||||
const { finished } = await getArtworkList(true)
|
showMyList.value = groupByDate(res.data.data)
|
||||||
localState.value.finished = finished
|
}
|
||||||
} finally {
|
} catch (error) {
|
||||||
localState.value.refreshing = false
|
console.error('获取数据失败:', 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-[100vw] bg-[url('@/static/images/3532@2x.png')] bg-cover pt-43px flex-grow-1 flex flex-col">
|
<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">
|
<!-- 用户信息 -->
|
||||||
<div class="mr-23px">
|
<div class="flex items-center px-16px mb-43px">
|
||||||
<img class="w-57px h-57px" src="@/static/images/5514@2x.png" alt="">
|
<img class="w-57px h-57px mr-23px" src="@/static/images/5514@2x.png" alt="">
|
||||||
</div>
|
<div class="flex flex-col">
|
||||||
<div class="flex flex-col">
|
<div class="text-18px text-#181818">{{ userInfo.realName }}</div>
|
||||||
<div class="text-18px text-#181818">{{userInfo.realName}}</div>
|
<div class="text-#575757 text-14px">{{ userInfo.telNum }}</div>
|
||||||
<div class="text-#575757 text-14px">{{userInfo.telNum}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1 ">
|
|
||||||
<div class="border-b-1px border-b-#D3D3D3 px-16px flex">
|
|
||||||
<div class="text-#000 text-16px border-b-3 border-b-#2B53AC h-36px">我的拍品</div>
|
|
||||||
</div>
|
</div>
|
||||||
<van-pull-refresh v-model="localState.refreshing"
|
</div>
|
||||||
success-text="刷新成功"
|
|
||||||
:success-duration="700"
|
<!-- 列表内容 -->
|
||||||
@refresh="onRefresh">
|
<div class="grow-1 flex flex-col">
|
||||||
<van-list
|
<div class="border-b-1px border-b-#D3D3D3 px-16px">
|
||||||
finished-text="没有更多了"
|
<div class="text-#000 text-16px border-b-3 border-b-#2B53AC w-80px h-36px">{{ $t('home.my_lots') }}</div>
|
||||||
>
|
</div>
|
||||||
<div class="px-16px pt-14px" v-for="(item,index) of showMyList" >
|
|
||||||
<div class="text-#575757 text-14px mb-3px">{{item.userCreatedAt}}</div>
|
<van-pull-refresh
|
||||||
<div class="flex mb-22px" v-for="(item1,index1) of item.list" @click="goDetail(item1)">
|
v-model="localState.refreshing"
|
||||||
<div class="flex-shrink-0 mr-10px rounded-4px overflow-hidden">
|
:success-duration="700"
|
||||||
<x-image class="w-80px h-80px" :src="item1?.auctionArtworkInfo?.artwork?.hdPic" :preview="false" alt=""/>
|
class="h-full grow-1"
|
||||||
</div>
|
@refresh="onRefresh"
|
||||||
<div class="flex flex-col justify-between grow-1">
|
>
|
||||||
<div class="text-#000 text-16px ellipsis line-height-21px">{{item1?.auctionArtworkInfo?.artworkTitle}}{{item1?.auctionArtworkInfo?.artworkTitle}}{{item1?.auctionArtworkInfo?.artworkTitle}}</div>
|
<template #success>
|
||||||
<div class="flex justify-between">
|
<van-icon name="success" /> <span>{{ $t('home.refresh_show') }}</span>
|
||||||
<div>
|
</template>
|
||||||
<div class="text-#575757 text-14px line-height-none mb-5px">起拍价:RMB 1,000</div>
|
<van-list :finished="localState.finished" :finished-text="$t('home.finished_text')" class="h-full">
|
||||||
<div class="text-#B58047 text-14px line-height-none">成交价:RMB 10,000</div>
|
<!-- 空状态 -->
|
||||||
|
<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>
|
||||||
<div v-if="[1,3,4].includes(item1.status)" @click.stop="goPay">
|
|
||||||
<van-button class="w-73px !h-30px" type="primary"><span class="text-12px">去支付</span></van-button>
|
|
||||||
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</van-list>
|
</van-list>
|
||||||
</van-pull-refresh>
|
</van-pull-refresh>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.ellipsis {
|
.ellipsis {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
import {authStore} from "@/stores/auth/index.js";
|
||||||
|
import {useI18n} from 'vue-i18n'
|
||||||
|
const {t:$t} = useI18n()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
type: {
|
type: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -15,46 +16,46 @@ const {userInfo}= authStore()
|
|||||||
<div class="text-#1A1A1A text-16px">
|
<div class="text-#1A1A1A text-16px">
|
||||||
<template v-if="type===0">
|
<template v-if="type===0">
|
||||||
<div class="flex mb-20px">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">姓名:</div>
|
<div class="mr-10px">{{$t('realAuth.name')}}:</div>
|
||||||
<div>{{userInfo.realName}}</div>
|
<div>{{userInfo.realName}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-20px">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">性别:</div>
|
<div class="mr-10px">{{$t('realAuth.gender')}}:</div>
|
||||||
<div>{{userInfo.sex}}</div>
|
<div>{{userInfo.sex===1?$t('realAuth.male'):$t('realAuth.female')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-20px">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">出生日期:</div>
|
<div class="mr-10px">{{$t('realAuth.birthday')}}:</div>
|
||||||
<div>{{userInfo.birthDate}}</div>
|
<div>{{userInfo.birthDate}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mr-10px">身份证号:</div>
|
<div class="mr-10px">{{$t('realAuth.idCard')}}:</div>
|
||||||
<div>{{userInfo.idNum}}</div>
|
<div>{{userInfo.idNum}}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="type===1">
|
<template v-if="type===1">
|
||||||
<div class="flex mb-20px" >
|
<div class="flex mb-20px" >
|
||||||
<div class="mr-10px">姓名:</div>
|
<div class="mr-10px">{{$t('realAuth.name')}}:</div>
|
||||||
<div>{{userInfo.realName}}</div>
|
<div>{{userInfo.realName}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-20px">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">性别:</div>
|
<div class="mr-10px">{{$t('realAuth.gender')}}:</div>
|
||||||
<div>{{userInfo.sex}}</div>
|
<div>{{userInfo.sex===1?$t('realAuth.male'):$t('realAuth.female')}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mb-20px">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">出生日期:</div>
|
<div class="mr-10px">{{$t('realAuth.birthday')}}:</div>
|
||||||
<div>{{userInfo.birthDate}}</div>
|
<div>{{userInfo.birthDate}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">家庭住址:</div>
|
<div class="mr-10px">{{$t('realAuth.adress')}}:</div>
|
||||||
<div>{{userInfo.idNum}}</div>
|
<div>{{userInfo.userExtend.address}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">所属银行:</div>
|
<div class="mr-10px">{{$t('realAuth.bank')}}:</div>
|
||||||
<div>{{userInfo.idNum}}</div>
|
<div>{{userInfo.userExtend.bankName}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex mb-20px">
|
||||||
<div class="mr-10px">银行卡号码:</div>
|
<div class="mr-10px">{{$t('realAuth.bankCard')}}:</div>
|
||||||
<div>{{userInfo.idNum}}</div>
|
<div>{{userInfo.userExtend.bankNo}}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,18 +5,19 @@ import {userUpdate} from "@/api/auth/index.js";
|
|||||||
import {message} from '@/components/x-message/useMessage.js'
|
import {message} from '@/components/x-message/useMessage.js'
|
||||||
import detail from './components/detail.vue'
|
import detail from './components/detail.vue'
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
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 router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const showPicker = ref(false);
|
const { locale } = useI18n()
|
||||||
const {userInfo}= authStore()
|
const {userInfo,selectedZone}= authStore()
|
||||||
const birthdayDate = ref([])
|
const active=ref(locale.value==='zh-CN'?0:1)
|
||||||
const showBirthdayPicker = ref(false)
|
|
||||||
const minDate = new Date(1950, 0, 1)
|
|
||||||
const maxDate = new Date(2025, 12, 31)
|
|
||||||
const active=ref(0)
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const form=ref({
|
const form=ref({
|
||||||
idNum: "",
|
|
||||||
realName: "",
|
realName: "",
|
||||||
sex:'',
|
sex:'',
|
||||||
birthDate:'',
|
birthDate:'',
|
||||||
@ -28,21 +29,13 @@ const form=ref({
|
|||||||
})
|
})
|
||||||
const form1=ref({
|
const form1=ref({
|
||||||
idNum:'',
|
idNum:'',
|
||||||
realName:''
|
realName:'',
|
||||||
|
userExtend:{}
|
||||||
})
|
})
|
||||||
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 onConfirm = ({ selectedValues, selectedOptions }) => {
|
|
||||||
form.value.sex=selectedValues?.[0]
|
|
||||||
showPicker.value = false
|
|
||||||
}
|
|
||||||
const onBirthdayConfirm = (value) => {
|
|
||||||
form.value.birthDate=value.selectedValues.join('-')
|
|
||||||
showBirthdayPicker.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
@ -55,28 +48,40 @@ function isFormComplete(obj) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const statusCode=ref(0)
|
|
||||||
|
const statusCode=ref(Number(route.query.statusCode))
|
||||||
const confirm=async ()=>{
|
const confirm=async ()=>{
|
||||||
const thatForm=active.value===0?form1.value:form.value
|
const thatForm=active.value===0?form1.value:form.value
|
||||||
|
thatForm.userExtend.isMainland=active.value===0?1:0
|
||||||
if (isFormComplete(thatForm)){
|
if (isFormComplete(thatForm)){
|
||||||
const res=await userUpdate(thatForm)
|
const res=await userUpdate(thatForm)
|
||||||
if (res.status===0){
|
if (res.status===0){
|
||||||
userInfo.value=res.data
|
userInfo.value=res.data
|
||||||
message.success('提交成功')
|
message.success(t('realAuth.success_mess'))
|
||||||
statusCode.value=1
|
//实名认证,选择的是大陆,并且手机区号选择的也是大陆就走法大大验证
|
||||||
|
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 {
|
}else {
|
||||||
message.error('请填写身份证相关信息')
|
message.error(t('realAuth.cnTabDesc'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const goHome=()=>{
|
const goHome=()=>{
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
definePageMeta({
|
const goLogin=()=>{
|
||||||
title: '实名认证',
|
router.back()
|
||||||
i18n: 'realAuth.title',
|
}
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -100,16 +105,13 @@ definePageMeta({
|
|||||||
<div class="text-[#BDBDBD] text-[16px] mb-[34px]">{{ $t('realAuth.otherTabDesc') }}</div>
|
<div class="text-[#BDBDBD] text-[16px] mb-[34px]">{{ $t('realAuth.otherTabDesc') }}</div>
|
||||||
<div class="mb-[100px]">
|
<div class="mb-[100px]">
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
<div class="border-b-[1.7px] mt-[8px]">
|
||||||
<van-field :label="$t('realAuth.name')" clearable :placeholder="$t('realAuth.namePlaceholder')"></van-field>
|
<van-field v-model="form.realName" :label="$t('realAuth.name')" clearable :placeholder="$t('realAuth.namePlaceholder')"></van-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
<div class="border-b-[1.7px] mt-[8px]">
|
||||||
<van-field :modelValue="columns.find(x=>x.value===form.sex)?.text" is-link readonly name="picker" :label="$t('realAuth.gender')"
|
<x-van-select v-model="form.sex" :placeholder="$t('realAuth.text1')" :label="$t('realAuth.gender')" :columns="columns"/>
|
||||||
@click="showPicker = true" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
<div class="border-b-[1.7px] mt-[8px]">
|
||||||
<van-field v-model="form.birthDate" is-link readonly name="birthdayPicker" :label="$t('realAuth.birthday')"
|
<x-van-date v-model="form.birthDate" :label="$t('realAuth.birthday')" :placeholder="$t('realAuth.birthdayPlaceholder')"/>
|
||||||
:placeholder="$t('realAuth.birthdayPlaceholder')" @click="showBirthdayPicker = true" />
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="border-b-[1.7px] mt-[8px]">
|
<div class="border-b-[1.7px] mt-[8px]">
|
||||||
<van-field v-model="form.userExtend.address" :label="$t('realAuth.adress')" clearable
|
<van-field v-model="form.userExtend.address" :label="$t('realAuth.adress')" clearable
|
||||||
@ -134,7 +136,7 @@ definePageMeta({
|
|||||||
</van-tab>
|
</van-tab>
|
||||||
</van-tabs>
|
</van-tabs>
|
||||||
<div class="flex justify-between" v-if="statusCode===0">
|
<div class="flex justify-between" v-if="statusCode===0">
|
||||||
<van-button style="width: 151px;height: 48px" color="#E9F1F8">
|
<van-button style="width: 151px;height: 48px" color="#E9F1F8" @click="goLogin">
|
||||||
<div class="text-#2B53AC text-16px">{{ $t('realAuth.cancel') }}</div>
|
<div class="text-#2B53AC text-16px">{{ $t('realAuth.cancel') }}</div>
|
||||||
</van-button>
|
</van-button>
|
||||||
<van-button @click="confirm" style="width: 151px;height: 48px" color="#2B53AC">
|
<van-button @click="confirm" style="width: 151px;height: 48px" color="#2B53AC">
|
||||||
@ -142,19 +144,13 @@ definePageMeta({
|
|||||||
</van-button>
|
</van-button>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="mt-auto pb-94px">
|
<div v-else class="mt-auto pb-94px">
|
||||||
<van-button color="#E9F1F8" @click="goHome" style="color: #2B53AC;font-weight: 600" block>去首页</van-button>
|
<van-button color="#E9F1F8" @click="goHome" style="color: #2B53AC;font-weight: 600" block>{{ $t('home.go_home')}}</van-button>
|
||||||
</div>
|
</div>
|
||||||
<van-popup v-model:show="showPicker" destroy-on-close position="bottom">
|
|
||||||
<van-picker :columns="columns" @confirm="onConfirm" @cancel="showPicker = false" />
|
|
||||||
</van-popup>
|
|
||||||
<van-popup v-model:show="showBirthdayPicker" destroy-on-close position="bottom">
|
|
||||||
<van-date-picker v-model="birthdayDate" :min-date="minDate" :max-date="maxDate"
|
|
||||||
@cancel="showBirthdayPicker = false" @confirm="onBirthdayConfirm" />
|
|
||||||
</van-popup>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
:deep(.van-tabs__line) {
|
:deep(.van-tabs__line) {
|
||||||
height: 2px;
|
height: 2px;
|
||||||
width: 107px;
|
width: 107px;
|
||||||
|
@ -1,18 +1,168 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const image = ref('');
|
import {showToast} from 'vant';
|
||||||
import { showToast } 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 { userInfo ,payment} = authStore()
|
||||||
|
const signaturePad = ref(null);
|
||||||
|
const isLandscapeMode = ref(false);
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const checkScreenOrientation = () => {
|
||||||
image.value = data.image;
|
|
||||||
|
const orientation = screen.orientation?.type || window.orientation;
|
||||||
|
if (orientation === 'landscape-primary' || orientation === 'landscape-secondary' ||
|
||||||
|
orientation === 90 || orientation === -90) {
|
||||||
|
isLandscapeMode.value = true;
|
||||||
|
} else {
|
||||||
|
isLandscapeMode.value = false;
|
||||||
|
showToast($t('signature.tips.landscape'));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const onClear = () => showToast('clear');
|
|
||||||
|
onMounted(() => {
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
checkScreenOrientation();
|
||||||
|
});
|
||||||
|
window.addEventListener('orientationchange', checkScreenOrientation);
|
||||||
|
screen.orientation?.addEventListener('change', checkScreenOrientation);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('orientationchange', checkScreenOrientation);
|
||||||
|
screen.orientation?.removeEventListener('change', checkScreenOrientation);
|
||||||
|
});
|
||||||
|
const imgUrl = ref('')
|
||||||
|
const show = ref(false)
|
||||||
|
const clearSignature = () => {
|
||||||
|
signaturePad.value?.clearSignature();
|
||||||
|
};
|
||||||
|
const submitSignature = () => {
|
||||||
|
if (signaturePad.value?.isEmpty()) {
|
||||||
|
showToast($t('signature.pleaseSign'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { data } = signaturePad.value?.saveSignature(); // 返回 base64 格式的图片数据
|
||||||
|
imgUrl.value = data;
|
||||||
|
show.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
const overlay = document.querySelector('.signature-container .van-overlay');
|
||||||
|
if (overlay) {
|
||||||
|
overlay.style.width = '100vw';
|
||||||
|
overlay.style.left = '0';
|
||||||
|
overlay.style.right = '0';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
const confirm = async () => {
|
||||||
|
const res = await signOnline({
|
||||||
|
auctionArtworkUuid:payment.value.auctionArtworkUuid,
|
||||||
|
signImgFileData: imgUrl.value
|
||||||
|
})
|
||||||
|
if (res.status===0){
|
||||||
|
router.push('/payment')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const goBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<van-signature @submit="onSubmit" @clear="onClear" />
|
<div class="signature-container bg-gray ">
|
||||||
<van-image v-if="image" :src="image" />
|
<template v-if="isLandscapeMode">
|
||||||
|
<div class="signature-content px-10px py-10px">
|
||||||
|
<VueSignaturePad
|
||||||
|
width="100%"
|
||||||
|
class="signature bg-#fff rounded-10px mb-10px"
|
||||||
|
ref="signaturePad"
|
||||||
|
/>
|
||||||
|
<div class="control-buttons justify-evenly">
|
||||||
|
<van-button
|
||||||
|
class="control-button"
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
@click="goBack"
|
||||||
|
>
|
||||||
|
{{ $t('signature.action.back') }}
|
||||||
|
</van-button>
|
||||||
|
<van-button
|
||||||
|
class="control-button"
|
||||||
|
size="mini"
|
||||||
|
type="warning"
|
||||||
|
@click="clearSignature"
|
||||||
|
>
|
||||||
|
{{ $t('signature.action.clear') }}
|
||||||
|
</van-button>
|
||||||
|
<van-button
|
||||||
|
class="control-button"
|
||||||
|
size="mini"
|
||||||
|
type="primary"
|
||||||
|
@click="submitSignature"
|
||||||
|
>
|
||||||
|
{{ $t('signature.action.confirm') }}
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="orientation-hint">
|
||||||
|
<p>{{$t('signature.tips.landscape')}}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<van-dialog v-model:show="show" class="signature-dialog" show-cancel-button @confirm="confirm">
|
||||||
|
<img class="h-100px" :src="imgUrl"/>
|
||||||
|
</van-dialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<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>
|
</style>
|
@ -6,6 +6,7 @@ definePageMeta({
|
|||||||
name: 'personal-info',
|
name: 'personal-info',
|
||||||
})
|
})
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
|
const {t:$t} = useI18n()
|
||||||
const showPicker = ref(false)
|
const showPicker = ref(false)
|
||||||
const showPicker1 = ref(false)
|
const showPicker1 = ref(false)
|
||||||
const onConfirm = () => {
|
const onConfirm = () => {
|
||||||
@ -28,13 +29,13 @@ const adress=ref('')
|
|||||||
<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')}}
|
||||||
</div>
|
</div>
|
||||||
<div class="grow-1 px-34px">
|
<div class="grow-1 px-34px">
|
||||||
<van-field type="tel" :label-width="161" label="文本" class="mb-10px" placeholder="请输入手机号">
|
<van-field type="tel" :label-width="161" :label="$t('personal.text')" class="mb-10px" :placeholder="$t('login.phonePlaceholder')">
|
||||||
<template #label>
|
<template #label>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mr-41px whitespace-nowrap">手机号</div>
|
<div class="mr-41px whitespace-nowrap">{{$t('profile.phone')}}</div>
|
||||||
<div @click="goCountryRegion">
|
<div @click="goCountryRegion">
|
||||||
<span class="mr-13px">+ 86</span>
|
<span class="mr-13px">+ 86</span>
|
||||||
<van-icon name="arrow-down" class="text-#777777"/>
|
<van-icon name="arrow-down" class="text-#777777"/>
|
||||||
@ -42,15 +43,15 @@ const adress=ref('')
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
<van-field label="姓名" class="mb-10px" placeholder="请输入姓名"/>
|
<van-field :label="$t('profile.name')" class="mb-10px" :placeholder="$t('realAuth.namePlaceholder')"/>
|
||||||
<x-van-select label="性别" :columns="columns"/>
|
<x-van-select :label="$t('realAuth.gender')" :columns="columns"/>
|
||||||
<x-van-date label="出生日期"/>
|
<x-van-date :label="$t('realAuth.birthday')"/>
|
||||||
<van-field v-model="adress" label="家庭住址" class="mb-10px" placeholder="请输入家庭住址"/>
|
<van-field v-model="adress" :label="$t('realAuth.adress')" class="mb-10px" :placeholder="$t('realAuth.adressPlaceholder')"/>
|
||||||
<van-field label="所属银行" class="mb-10px" placeholder="请输入所属银行"/>
|
<van-field :label="$t('realAuth.bank')" class="mb-10px" :placeholder="$t('realAuth.bankPlaceholder')"/>
|
||||||
<van-field label="银行卡号码" class="mb-10px" placeholder="请输入银行卡号码"/>
|
<van-field :label="$t('realAuth.bankCard')" class="mb-10px" :placeholder="$t('realAuth.bankCardPlaceholder')"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
<div class="h-81px bg-#fff flex justify-center pt-7px border-t">
|
||||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">下一步</van-button>
|
<van-button color="#2B53AC" class="w-213px van-btn-h-38px">{{$t('personal.next')}}</van-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,43 +1,95 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
const activeNames = ref(['1']);
|
import pdfView from './pdfView'
|
||||||
|
import { contractView } from "~/api/goods/index.js"
|
||||||
|
import { authStore } from "~/stores/auth/index.js"
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: 'default',
|
layout: 'default',
|
||||||
title: '签署内容'
|
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) {
|
||||||
|
console.error('获取拍卖笔录失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听折叠面板变化
|
||||||
|
const handleCollapseChange = (name) => {
|
||||||
|
activeNames.value = name
|
||||||
|
// 当打开拍卖笔录时获取PDF
|
||||||
|
if (name === '5' && !pmblUrl.value) {
|
||||||
|
fetchPmblPdf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const goSignature = () => {
|
||||||
|
router.push({
|
||||||
|
path: '/signature/panel'
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-#EBEBEB h-screen-nav flex flex-col">
|
<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">支付前需同意以下内容并签字</div>
|
<div class="h-50px text-14px text-#191919 bg-#fff flex items-center px-21px mb-6px shrink-0">
|
||||||
<van-collapse v-model="activeNames" class="grow-1">
|
{{ $t('signature.tips.prePayment') }}
|
||||||
<van-collapse-item name="1" class="mb-6px">
|
</div>
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
|
||||||
</template>
|
|
||||||
代码是写出来给人看的,附带能在机器上运行。
|
|
||||||
</van-collapse-item>
|
|
||||||
<van-collapse-item name="2" class="mb-6px">
|
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
|
||||||
</template>
|
|
||||||
代码是写出来给人看的,附带能在机器上运行。
|
|
||||||
</van-collapse-item>
|
|
||||||
<van-collapse-item name="3" class="mb-6px">
|
|
||||||
<template #title>
|
|
||||||
<div class="text-#2B53AC text-14px">《拍卖规则》</div>
|
|
||||||
</template>
|
|
||||||
代码是写出来给人看的,附带能在机器上运行。
|
|
||||||
</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">同意并签字</van-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
<van-collapse
|
||||||
:deep(.van-cell__right-icon){
|
accordion
|
||||||
color: #ACACAC;
|
v-model="activeNames"
|
||||||
font-size: 12px;
|
class="grow-1"
|
||||||
}
|
@change="handleCollapseChange"
|
||||||
</style>
|
>
|
||||||
|
<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>
|
68
app/pages/signature/protocol/pdfView/index.vue
Normal file
68
app/pages/signature/protocol/pdfView/index.vue
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<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,24 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import MasonryWall from '@yeger/vue-masonry-wall'
|
|
||||||
const items = [
|
|
||||||
{
|
|
||||||
title: 'First',
|
|
||||||
description: 'The first item.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Second',
|
|
||||||
description: 'The second item.',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<masonry-wall :items="items" :ssr-columns="2" :minColumns="2" :gap="16">
|
|
||||||
<template #default="{ item, index }">
|
|
||||||
<div :style="{ height: `${(index + 1) * 100}px` }">
|
|
||||||
<h1>{{ item.title }}</h1>
|
|
||||||
<span>{{ item.description }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</masonry-wall>
|
|
||||||
</template>
|
|
@ -16,8 +16,14 @@ export default defineNuxtPlugin(() => {
|
|||||||
const i18n = useNuxtApp().$i18n
|
const i18n = useNuxtApp().$i18n
|
||||||
const { setLocale } = i18n
|
const { setLocale } = i18n
|
||||||
|
|
||||||
const lang = localStorage.getItem('lang')
|
// 暂时设置固定语言,用于调试
|
||||||
|
// 可以根据需要修改这里的语言代码:'zh-CN' | 'en-US' | 'ja-JP' | 'zh-TW'
|
||||||
|
const fixedLang = 'zh-CN'
|
||||||
|
setLocale(fixedLang)
|
||||||
|
Locale.use(fixedLang)
|
||||||
|
|
||||||
|
// 原自动检测系统语言的逻辑(暂时注释)
|
||||||
|
/* const lang = localStorage.getItem('lang')
|
||||||
if (lang) {
|
if (lang) {
|
||||||
setLocale(lang as TypeLocale)
|
setLocale(lang as TypeLocale)
|
||||||
Locale.use(lang)
|
Locale.use(lang)
|
||||||
@ -25,6 +31,6 @@ export default defineNuxtPlugin(() => {
|
|||||||
else {
|
else {
|
||||||
setLocale(i18n.locale.value)
|
setLocale(i18n.locale.value)
|
||||||
Locale.use(i18n.locale.value)
|
Locale.use(i18n.locale.value)
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
BIN
app/static/images/5554@2x1.png
Normal file
BIN
app/static/images/5554@2x1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
app/static/images/z6022@2x.png
Normal file
BIN
app/static/images/z6022@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 485 KiB |
BIN
app/static/images/zu5512@2x.png
Normal file
BIN
app/static/images/zu5512@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
BIN
app/static/images/zu6020@2x.png
Normal file
BIN
app/static/images/zu6020@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
@ -4,7 +4,37 @@ export const codeAuthStore = createGlobalState(() => {
|
|||||||
const RefreshToken=useLocalStorage('RefreshToken','')
|
const RefreshToken=useLocalStorage('RefreshToken','')
|
||||||
const userInfo=useLocalStorage('userInfo',{})
|
const userInfo=useLocalStorage('userInfo',{})
|
||||||
const fingerprint=useLocalStorage('fingerprint','')
|
const fingerprint=useLocalStorage('fingerprint','')
|
||||||
|
const formData=useLocalStorage('formData',{
|
||||||
|
"countryCode": "",
|
||||||
|
"phone": "", //手机号
|
||||||
|
"userName": "", //用户名 (第一次传)
|
||||||
|
"gender": 1, //性别 1男 2女 3未知 (第一次传)
|
||||||
|
"birthday": "", //生日 (第一次传)
|
||||||
|
"address": "", //家庭住址 (第一次传)
|
||||||
|
"bankName": "", //银行名字(第一次传)
|
||||||
|
"bankNo": "", //银行卡号(第一次传)
|
||||||
|
"cardId": "",
|
||||||
|
cardType:1
|
||||||
|
})
|
||||||
|
const lotNo=useLocalStorage('lotNo',undefined)
|
||||||
|
const price=useLocalStorage('price',undefined)
|
||||||
|
const auctionArtworkUuid=useLocalStorage('auctionArtworkUuid',undefined)
|
||||||
|
const number=useLocalStorage('number',undefined)
|
||||||
|
const qrUid=useLocalStorage('qrUid',undefined)
|
||||||
|
const cpayment=useLocalStorage('cpayment',{
|
||||||
|
price:'',
|
||||||
|
currency:''
|
||||||
|
})
|
||||||
|
const qrData=useLocalStorage('qrData',{})
|
||||||
return{
|
return{
|
||||||
|
qrData,
|
||||||
|
qrUid,
|
||||||
|
cpayment,
|
||||||
|
lotNo,
|
||||||
|
price,
|
||||||
|
auctionArtworkUuid,
|
||||||
|
number,
|
||||||
|
formData,
|
||||||
userInfo,
|
userInfo,
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
token,
|
token,
|
||||||
|
@ -4,7 +4,19 @@ export const authStore = createGlobalState(() => {
|
|||||||
const RefreshToken=useLocalStorage('RefreshToken','')
|
const RefreshToken=useLocalStorage('RefreshToken','')
|
||||||
const userInfo=useLocalStorage('userInfo',{})
|
const userInfo=useLocalStorage('userInfo',{})
|
||||||
const fingerprint=useLocalStorage('fingerprint','')
|
const fingerprint=useLocalStorage('fingerprint','')
|
||||||
|
const checkoutSessionUrl=useLocalStorage('checkoutSessionUrl','')
|
||||||
|
const selectedZone=useLocalStorage('selectedZone','')
|
||||||
|
const payment=useLocalStorage('payment',{
|
||||||
|
leftPrice:'',
|
||||||
|
leftCurrency:'',
|
||||||
|
buyUid:'',
|
||||||
|
auctionArtworkUuid:''
|
||||||
|
})
|
||||||
|
|
||||||
return{
|
return{
|
||||||
|
selectedZone,
|
||||||
|
payment,
|
||||||
|
checkoutSessionUrl,
|
||||||
userInfo,
|
userInfo,
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
token,
|
token,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createGlobalState } from '@vueuse/core'
|
import {createGlobalState, useLocalStorage} from '@vueuse/core'
|
||||||
import {ref} from "vue";
|
import {ref} from "vue";
|
||||||
import {goodStore} from "@/stores/goods/index.js";
|
import {goodStore} from "@/stores/goods/index.js";
|
||||||
import {authStore} from "@/stores/auth/index.js";
|
import {authStore} from "@/stores/auth/index.js";
|
||||||
@ -6,17 +6,18 @@ import {message} from "~/components/x-message/useMessage.js";
|
|||||||
import { WebSocketClient } from '@/utils/websocket'
|
import { WebSocketClient } from '@/utils/websocket'
|
||||||
import {logSendlog} from "~/api/goods/index.js";
|
import {logSendlog} from "~/api/goods/index.js";
|
||||||
import CryptoJS from "crypto-js";
|
import CryptoJS from "crypto-js";
|
||||||
|
import {useI18n} from 'vue-i18n'
|
||||||
export const liveStore = createGlobalState(() => {
|
export const liveStore = createGlobalState(() => {
|
||||||
const {auctionDetail} = goodStore();
|
const {auctionDetail} = goodStore();
|
||||||
const { token } = authStore()
|
const { token } = authStore()
|
||||||
|
const t=useI18n().t
|
||||||
const fullLive = ref(false)
|
const fullLive = ref(false)
|
||||||
const quoteStatus = ref(false)
|
const quoteStatus = ref(false)
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
const cleanup = ref(null)
|
const cleanup = ref(null)
|
||||||
const show1=ref(false)
|
const show1=ref(false)
|
||||||
const playerId=ref('J_prismPlayer')
|
const playerId=ref('J_prismPlayer')
|
||||||
const auctionData=ref({})
|
const auctionData=useLocalStorage('auctionData',{})
|
||||||
const socket=ref(null)
|
const socket=ref(null)
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const pullLink=ref('')
|
const pullLink=ref('')
|
||||||
@ -108,6 +109,46 @@ export const liveStore = createGlobalState(() => {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 定义常量
|
||||||
|
const WS_TYPES = {
|
||||||
|
TIP: 'tip',
|
||||||
|
STOP_ARTWORK: 'stopArtwork',
|
||||||
|
OVER: 'over'
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIP_TYPES = {
|
||||||
|
FALLING: 'falling',
|
||||||
|
OTHERS_BID: 'othersBid',
|
||||||
|
SUCCESS_BID: 'successBid',
|
||||||
|
ARTWORK_OVER: 'artworkOver',
|
||||||
|
FAIL_BID: 'failBid'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础消息配置
|
||||||
|
const BASE_MESSAGE_STYLE = {
|
||||||
|
width: '151px',
|
||||||
|
bottom: '265px'
|
||||||
|
}
|
||||||
|
const createMessageConfig = (text, color, subText = '', extraStyle = {}) => ({
|
||||||
|
title: {
|
||||||
|
text,
|
||||||
|
color,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
icon: false,
|
||||||
|
...(subText && {
|
||||||
|
subTitle: {
|
||||||
|
text: subText,
|
||||||
|
color: '#939393',
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
style: {
|
||||||
|
...BASE_MESSAGE_STYLE,
|
||||||
|
...extraStyle
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const getSocketData = async () => {
|
const getSocketData = async () => {
|
||||||
const wsClient = new WebSocketClient(
|
const wsClient = new WebSocketClient(
|
||||||
config.public.NUXT_PUBLIC_SOCKET_URL,
|
config.public.NUXT_PUBLIC_SOCKET_URL,
|
||||||
@ -117,120 +158,76 @@ export const liveStore = createGlobalState(() => {
|
|||||||
auctionUuid: auctionDetail.value.uuid,
|
auctionUuid: auctionDetail.value.uuid,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 处理消息提示
|
||||||
|
const handleTipMessage = (tipType) => {
|
||||||
|
const tipConfigs = {
|
||||||
|
[TIP_TYPES.FALLING]: () =>
|
||||||
|
message.warning(createMessageConfig(t('live_room.text1'), '#F09F1F')),
|
||||||
|
|
||||||
|
[TIP_TYPES.OTHERS_BID]: () =>
|
||||||
|
message.error(createMessageConfig(t('live_room.text2'), '#CF3050', t('live_room.text3'))),
|
||||||
|
|
||||||
|
[TIP_TYPES.SUCCESS_BID]: ()=>{
|
||||||
|
quoteStatus.value=false
|
||||||
|
message.success(createMessageConfig(t('live_room.text4'), '#18A058', t('live_room.text5')))
|
||||||
|
},
|
||||||
|
[TIP_TYPES.ARTWORK_OVER]: () =>{
|
||||||
|
quoteStatus.value=false
|
||||||
|
message.success(createMessageConfig(
|
||||||
|
t('live_room.text6'),
|
||||||
|
'#575757',
|
||||||
|
t('live_room.text7'),
|
||||||
|
{ backgroundColor: '#fff', borderColor: '#fff' }
|
||||||
|
))
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
[TIP_TYPES.FAIL_BID]: () =>
|
||||||
|
message.error(createMessageConfig(
|
||||||
|
t('live_room.text8'),
|
||||||
|
'#CF3050',
|
||||||
|
t('live_room.text9'),
|
||||||
|
{ width: '186px' }
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handler = tipConfigs[tipType]
|
||||||
|
if (handler) handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocket 事件处理
|
||||||
ws.onOpen(() => {
|
ws.onOpen(() => {
|
||||||
console.log('WebSocket connected')
|
console.log('WebSocket connected')
|
||||||
})
|
})
|
||||||
|
|
||||||
ws.onMessage((data) => {
|
ws.onMessage((data) => {
|
||||||
auctionData.value = data.data
|
auctionData.value = data.data
|
||||||
if (data.data?.wsType === 'tip' ) {
|
console.log(' auctionData.value', auctionData.value)
|
||||||
if (data.data?.tip?.tipType === 'falling'){
|
const { wsType, tip } = data.data || {}
|
||||||
message.warning({
|
|
||||||
title: {
|
|
||||||
text: '即将落槌',
|
|
||||||
color: '#F09F1F',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
width: '151px',
|
|
||||||
bottom: '230px',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}else if (data.data?.tip?.tipType === 'othersBid'){
|
|
||||||
message.error({
|
|
||||||
title: {
|
|
||||||
text: '已有人出价',
|
|
||||||
color: '#CF3050',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
icon:false,
|
|
||||||
subTitle:{
|
|
||||||
text:'更新后再出价',
|
|
||||||
color: '#939393',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
width: '151px',
|
|
||||||
bottom: '230px'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}else if (data.data?.tip?.tipType === 'successBid'){
|
|
||||||
message.success({
|
|
||||||
title: {
|
|
||||||
text: '恭喜您,竞拍成功',
|
|
||||||
color: '#18A058',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
icon:false,
|
|
||||||
subTitle:{
|
|
||||||
text:'请缴款',
|
|
||||||
color: '#939393',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
width: '151px',
|
|
||||||
bottom: '230px'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}else if (data.data?.tip?.tipType === 'artworkOver'){
|
|
||||||
message.success({
|
|
||||||
title: {
|
|
||||||
text: '本拍品已结束',
|
|
||||||
color: '#575757',
|
|
||||||
align: 'center',
|
|
||||||
|
|
||||||
},
|
switch (wsType) {
|
||||||
icon:false,
|
case WS_TYPES.TIP:
|
||||||
subTitle:{
|
handleTipMessage(tip?.tipType)
|
||||||
text:'请期待下个拍品',
|
break
|
||||||
color: '#939393',
|
case WS_TYPES.STOP_ARTWORK:
|
||||||
align: 'center',
|
console.log('changeQuote',quoteStatus.value)
|
||||||
},
|
//quoteStatus.value = false
|
||||||
style: {
|
break
|
||||||
width: '151px',
|
case WS_TYPES.OVER:
|
||||||
bottom: '230px',
|
|
||||||
|
quoteStatus.value = false
|
||||||
|
console.log('changeQuote',quoteStatus.value)
|
||||||
|
message.success(createMessageConfig(
|
||||||
|
t('live_room.text10'),
|
||||||
|
'#575757',
|
||||||
|
'',
|
||||||
|
{
|
||||||
|
width: '195px',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
borderColor:'#fff'
|
borderColor: '#fff'
|
||||||
},
|
}
|
||||||
})
|
))
|
||||||
}else if (data.data?.tip?.tipType === 'failBid'){
|
break
|
||||||
message.error({
|
|
||||||
title: {
|
|
||||||
text: '很遗憾,竞拍失败',
|
|
||||||
color: '#CF3050',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
icon:false,
|
|
||||||
subTitle:{
|
|
||||||
text:'竞拍结束',
|
|
||||||
color: '#939393',
|
|
||||||
align: 'center',
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
width: '186px',
|
|
||||||
bottom: '230px'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}else if (data.data?.wsType==='stopArtwor'){
|
|
||||||
quoteStatus.value=false
|
|
||||||
}else if (data.data?.wsType==='over'){
|
|
||||||
message.success({
|
|
||||||
title: {
|
|
||||||
text: '竞拍结束,谢谢参与',
|
|
||||||
color: '#575757',
|
|
||||||
align: 'center',
|
|
||||||
|
|
||||||
},
|
|
||||||
icon:false,
|
|
||||||
style: {
|
|
||||||
width: '195px',
|
|
||||||
bottom: '230px',
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
borderColor:'#fff'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('onmessage', data)
|
console.log('onmessage', data)
|
||||||
@ -245,14 +242,14 @@ export const liveStore = createGlobalState(() => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const changeStatus = () => {
|
const changeStatus = () => {
|
||||||
if (auctionData.value.artwork.isSelling&&!auctionData.value.artwork.isSoled){
|
if (auctionData.value.artwork?.isSelling&&!auctionData.value.artwork.isSoled){
|
||||||
quoteStatus.value = true
|
quoteStatus.value = !quoteStatus.value
|
||||||
}else {
|
}else {
|
||||||
if (quoteStatus.value){
|
if (quoteStatus.value){
|
||||||
quoteStatus.value = false
|
quoteStatus.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
console.log('changeQuote',quoteStatus.value)
|
||||||
}
|
}
|
||||||
return{
|
return{
|
||||||
fullLive,
|
fullLive,
|
||||||
|
7
env/.env.prod
vendored
7
env/.env.prod
vendored
@ -1,7 +1,4 @@
|
|||||||
# 生产环境配置
|
# 生产环境配置
|
||||||
NUXT_PUBLIC_API_BASE=http://api.example.com
|
NUXT_PUBLIC_API_BASE=https://auction.yixunlink.com
|
||||||
NUXT_PUBLIC_WS_URL=ws://ws.example.com
|
NUXT_PUBLIC_SOCKET_URL=wss://auction.yixunlink.com
|
||||||
NUXT_API_SECRET=prod-secret
|
NUXT_API_SECRET=prod-secret
|
||||||
|
|
||||||
# 阿里云播放器配置
|
|
||||||
NUXT_PUBLIC_PLAYER_SOURCE=artc://live-pull-sh-01.szjixun.cn/live/live?auth_key=1736748343-0-0-feef65166e5cc62957c35b6e3eec82a1
|
|
6
env/.env.test
vendored
6
env/.env.test
vendored
@ -1,7 +1,5 @@
|
|||||||
# 测试环境配置
|
# 测试环境配置
|
||||||
NUXT_PUBLIC_API_BASE=https://auction-test.szjixun.cn
|
NUXT_PUBLIC_API_BASE=https://auction-test.szjixun.cn
|
||||||
NUXT_PUBLIC_API_COLLECT_CODE=https://auction-test.szjixun.cn
|
NUXT_PUBLIC_API_COLLECT_CODE=http://auction-test.szjixun.cn
|
||||||
NUXT_API_SECRET=test-secret
|
NUXT_API_SECRET=test-secret
|
||||||
NUXT_PUBLIC_SOCKET_URL=ws://172.16.100.99:8005
|
NUXT_PUBLIC_SOCKET_URL=wss://auction-test.szjixun.cn
|
||||||
# 阿里云播放器配置
|
|
||||||
NUXT_PUBLIC_PLAYER_SOURCE=artc://live-push-sh-01.szjixun.cn/live001/86180cae-1e07-4b8d-b45e-50d8ce800110?auth_key=1739255918-0-0-5251017e725a860570a59de7e4e2fd98
|
|
@ -1,18 +1,22 @@
|
|||||||
{
|
{
|
||||||
"appSetting":{
|
"appSetting": {
|
||||||
"appName": "FENGHE",
|
"appName": "FENGHE",
|
||||||
"appDescription": "TAIFENG INTERNATIONAL KYOTO AUCTION",
|
"appDescription": "TAIFENG INTERNATIONAL KYOTO AUCTION",
|
||||||
"appKeyWords": "TAIFENG,TAIFENG CULTURE,FENGHE,KYOTO,AUCTION"
|
"appKeyWords": "TAIFENG,TAIFENG CULTURE,FENGHE,KYOTO,AUCTION"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"home": "Home",
|
"home": "Kyoto Auction",
|
||||||
"profile": "Profile",
|
"profile": "Profile",
|
||||||
"darkMode": "🌗 Dark Mode",
|
"darkMode": "🌗 Dark Mode",
|
||||||
"language": "📚 Language",
|
"language": "📚 Language",
|
||||||
"404Demo": "🙅 Page 404 Demo",
|
"404Demo": "🙅 404 Page Demo",
|
||||||
"unocssExample": "🎨 Unocss example",
|
"unocssExample": "🎨 Unocss Example",
|
||||||
"keepAlive": "🧡 KeepAlive Demo",
|
"keepAlive": "🧡 KeepAlive Demo",
|
||||||
"fetch": "🏄 Network Request"
|
"persistPiniaState": "💾 Persist Pinia State",
|
||||||
|
"fetch": "🏄 Network Request",
|
||||||
|
"auction": "Auction",
|
||||||
|
"live": "Live",
|
||||||
|
"settings": "Settings"
|
||||||
},
|
},
|
||||||
"tabbar": {
|
"tabbar": {
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
@ -25,14 +29,92 @@
|
|||||||
"login": "Login",
|
"login": "Login",
|
||||||
"back": "Back",
|
"back": "Back",
|
||||||
"hasSendTo": "Verification code has been sent to",
|
"hasSendTo": "Verification code has been sent to",
|
||||||
"reSend": "Re-send"
|
"reSend": "Resend",
|
||||||
|
"agreement": "By logging in, you agree to the",
|
||||||
|
"privacyPolicy": "Privacy Policy"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"items": "items",
|
||||||
|
"auction": "Lots",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"networkError": "Network error, please try again",
|
||||||
|
"systemError": "System error, please try again later",
|
||||||
|
"success": "Operation successful",
|
||||||
|
"fail": "Operation failed",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"back": "Back",
|
||||||
|
"next": "Next",
|
||||||
|
"save": "Save",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"view": "View",
|
||||||
|
"close": "Close",
|
||||||
|
"refresh": "Refresh",
|
||||||
|
"noData": "No data",
|
||||||
|
"loadMore": "Load more",
|
||||||
|
"noMore": "No more data",
|
||||||
|
"refreshSuccess": "Refresh successful",
|
||||||
|
"pleaseInput": "Please enter",
|
||||||
|
"pleaseSelect": "Please select"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"name": "Name",
|
||||||
|
"phone": "Phone",
|
||||||
|
"text1": "You have no lots",
|
||||||
|
"text2": "Go to auction",
|
||||||
|
"title": "Profile",
|
||||||
|
"account": {
|
||||||
|
"title": "Account Information",
|
||||||
|
"avatar": "Avatar",
|
||||||
|
"nickname": "Nickname",
|
||||||
|
"phone": "Phone",
|
||||||
|
"email": "Email",
|
||||||
|
"realName": "Real Name Authentication",
|
||||||
|
"verified": "Verified",
|
||||||
|
"unverified": "Unverified",
|
||||||
|
"edit": "Edit"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"title": "My Orders",
|
||||||
|
"all": "All",
|
||||||
|
"unpaid": "Unpaid",
|
||||||
|
"paid": "Paid",
|
||||||
|
"completed": "Completed",
|
||||||
|
"cancelled": "Cancelled"
|
||||||
|
},
|
||||||
|
"favorite": {
|
||||||
|
"title": "My Favorites",
|
||||||
|
"empty": "No favorites",
|
||||||
|
"delete": "Delete",
|
||||||
|
"deleteConfirm": "Are you sure to delete selected favorites?"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"title": "Shipping Addresses",
|
||||||
|
"add": "Add Address",
|
||||||
|
"edit": "Edit Address",
|
||||||
|
"delete": "Delete Address",
|
||||||
|
"default": "Default Address",
|
||||||
|
"setDefault": "Set as Default",
|
||||||
|
"name": "Recipient",
|
||||||
|
"phone": "Phone Number",
|
||||||
|
"region": "Region",
|
||||||
|
"detail": "Detailed Address",
|
||||||
|
"save": "Save",
|
||||||
|
"deleteConfirm": "Are you sure to delete this address?"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "Settings",
|
||||||
|
"notification": "Notifications",
|
||||||
|
"language": "Language",
|
||||||
|
"about": "About Us",
|
||||||
|
"logout": "Logout",
|
||||||
|
"logoutConfirm": "Are you sure to logout?"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error_page": {
|
"error_page": {
|
||||||
"back_btn": "Back",
|
"back_btn": "Back",
|
||||||
"txt": "Not found"
|
"txt": "Not Found"
|
||||||
},
|
|
||||||
"profile_page": {
|
|
||||||
"txt": "WIP"
|
|
||||||
},
|
},
|
||||||
"prose_page": {
|
"prose_page": {
|
||||||
"btn_fetch": "Fetch",
|
"btn_fetch": "Fetch",
|
||||||
@ -40,12 +122,13 @@
|
|||||||
"btn_empty_desc": "No data"
|
"btn_empty_desc": "No data"
|
||||||
},
|
},
|
||||||
"countryRegion": {
|
"countryRegion": {
|
||||||
"title": "Country and Region",
|
"title": "Country/Region",
|
||||||
"searchPlaceholder": "Please enter the country and region",
|
"searchPlaceholder": "Enter country or region",
|
||||||
"frequentCountry": "Frequent"
|
"frequentCountry": "Frequently Used"
|
||||||
},
|
},
|
||||||
"realAuth": {
|
"realAuth": {
|
||||||
"title": "Real-name Authentication",
|
"phonePlaceholder": "Please enter your phone number",
|
||||||
|
"title": "Real Name Authentication",
|
||||||
"cnTab": "Mainland Residents",
|
"cnTab": "Mainland Residents",
|
||||||
"otherTab": "Non-Mainland Residents",
|
"otherTab": "Non-Mainland Residents",
|
||||||
"cnTabDesc": "Please fill in ID card information",
|
"cnTabDesc": "Please fill in ID card information",
|
||||||
@ -62,10 +145,518 @@
|
|||||||
"adress": "Home Address",
|
"adress": "Home Address",
|
||||||
"adressPlaceholder": "Please enter home address",
|
"adressPlaceholder": "Please enter home address",
|
||||||
"bank": "Bank",
|
"bank": "Bank",
|
||||||
"bankPlaceholder": "Please select your bank",
|
"bankPlaceholder": "Please select bank",
|
||||||
"bankCard": "Bank Card Number",
|
"bankCard": "Bank Card Number",
|
||||||
"bankCardPlaceholder": "Please enter bank card number",
|
"bankCardPlaceholder": "Please enter bank card number",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"confirm": "Confirm"
|
"confirm": "Confirm",
|
||||||
|
"success_mess": "Submitted successfully",
|
||||||
|
"text1": "Please select gender",
|
||||||
|
"detail": {
|
||||||
|
"gender": {
|
||||||
|
"male": "Male",
|
||||||
|
"female": "Female"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"detail": {
|
||||||
|
"text1": "Artist",
|
||||||
|
"text2": "Total Area",
|
||||||
|
"text3": "Length",
|
||||||
|
"text4": "Width",
|
||||||
|
"text5": "Artwork Introduction",
|
||||||
|
"text6": "Starting Price",
|
||||||
|
"text7": "Bid History",
|
||||||
|
"text8": "Lot Details"
|
||||||
|
},
|
||||||
|
"art_detail_page": {
|
||||||
|
"button": "Proceed to payment",
|
||||||
|
"prompt_title": "Congratulations",
|
||||||
|
"prompt_desc": "Bid successful"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"tab1": "Lots List",
|
||||||
|
"tab2": "Auction Instructions",
|
||||||
|
"lot_detail": "Lot Details",
|
||||||
|
"refresh_show": "Refresh successful",
|
||||||
|
"finished_text": "No more data",
|
||||||
|
"start_price": "Starting Price",
|
||||||
|
"close_price": "Hammer Price",
|
||||||
|
"my_lots": "My Lots",
|
||||||
|
"go_home": "Go to Home",
|
||||||
|
"text1": "Click to enter live room",
|
||||||
|
"text2": "Beijing Time"
|
||||||
|
},
|
||||||
|
"live_room": {
|
||||||
|
"error_mess": "Failed to get live content, retry?",
|
||||||
|
"success_mess": "Bid successful",
|
||||||
|
"warn_mess": "Bidding is not enabled",
|
||||||
|
"now_price": "Current Price",
|
||||||
|
"lower_price": "Next Increment",
|
||||||
|
"confirm": "Confirm Bid",
|
||||||
|
"button": "Click 'Enable Bidding' to participate",
|
||||||
|
"start": "Start Auction",
|
||||||
|
"head": "Leading",
|
||||||
|
"out": "Out",
|
||||||
|
"success": "Successful",
|
||||||
|
"next_lot": "Next lot coming soon",
|
||||||
|
"spot": "Onsite Bidding",
|
||||||
|
"network": "Online Bidding",
|
||||||
|
"me": "Me",
|
||||||
|
"all_pay": "Pay in Full",
|
||||||
|
"part_pay": "Partial Payment",
|
||||||
|
"lots": "Lots",
|
||||||
|
"colse_bid": "Close Bidding",
|
||||||
|
"start_bid": "Enable Bidding",
|
||||||
|
"total": "Total",
|
||||||
|
"lots_num": "lots",
|
||||||
|
"cast": "Casting",
|
||||||
|
"wait_update": "Waiting for Update",
|
||||||
|
"text1": "Hammer soon",
|
||||||
|
"text2": "Someone has placed a bid",
|
||||||
|
"text3": "Please bid after update",
|
||||||
|
"text4": "Congratulations, you won the bid",
|
||||||
|
"text5": "Please make payment",
|
||||||
|
"text6": "This lot has ended",
|
||||||
|
"text7": "Please wait for the next lot",
|
||||||
|
"text8": "Sorry, bidding unsuccessful",
|
||||||
|
"text9": "Bidding ended",
|
||||||
|
"text10": "Bidding ended, thank you for participating"
|
||||||
|
},
|
||||||
|
"personal": {
|
||||||
|
"title": "Please fill in your personal information",
|
||||||
|
"text": "Text",
|
||||||
|
"next": "Next"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "Payment",
|
||||||
|
"result": {
|
||||||
|
"title": "Payment Result",
|
||||||
|
"success": "Payment Successful",
|
||||||
|
"fail": "Payment Failed",
|
||||||
|
"unpaid": "Unpaid",
|
||||||
|
"expired": "Payment Expired",
|
||||||
|
"partial": "Partially Paid"
|
||||||
|
},
|
||||||
|
"text1": "Payment Result",
|
||||||
|
"text2": "Payment Successful",
|
||||||
|
"text3": "Payment Failed",
|
||||||
|
"text4": "Unpaid",
|
||||||
|
"text5": "Payment Expired",
|
||||||
|
"text6": "Partially Paid",
|
||||||
|
"next": "Next",
|
||||||
|
"backHome": "Back to Home",
|
||||||
|
"confirm": "Confirm Payment",
|
||||||
|
"fullPayment": "Pay in Full",
|
||||||
|
"partialPayment": "Partial Payment",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"error": {
|
||||||
|
"enterAmount": "Please enter amount",
|
||||||
|
"exceedTotal": "Cannot exceed total amount",
|
||||||
|
"invalidAmount": "Please enter a valid payment amount",
|
||||||
|
"networkError": "Network error, please try again",
|
||||||
|
"systemError": "System error, please try again later"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"amount": "Maximum {currency}{price}"
|
||||||
|
},
|
||||||
|
"amount": "Payment Amount"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"protocol": {
|
||||||
|
"loading": "Loading...",
|
||||||
|
"title": "Signature Content",
|
||||||
|
"agree": "Agree and Sign",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"success": "Signature Successful",
|
||||||
|
"fail": "Signature Failed",
|
||||||
|
"back": "Back"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"agreeAndSign": "Agree and Sign"
|
||||||
|
},
|
||||||
|
"loading": "Loading...",
|
||||||
|
"agreement": {
|
||||||
|
"notice": "Auction Notice",
|
||||||
|
"rules": "Auction Rules",
|
||||||
|
"buyerGuide": "Buyer's Guide",
|
||||||
|
"buyerAgreement": "Buyer's Agreement",
|
||||||
|
"record": "Auction Record Confirmation",
|
||||||
|
"transfer": "Auction Transfer Confirmation"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"getRecord": "Failed to get auction record"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"agree": "Agree and Sign",
|
||||||
|
"back": "Back",
|
||||||
|
"clear": "Clear",
|
||||||
|
"confirm": "Confirm"
|
||||||
|
},
|
||||||
|
"tips": {
|
||||||
|
"landscape": "Please use landscape mode",
|
||||||
|
"needSign": "Please sign first",
|
||||||
|
"prePayment": "Please agree and sign before payment"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"liveRoom": {
|
||||||
|
"loading": "Live stream loading...",
|
||||||
|
"error": {
|
||||||
|
"player": "Player error:",
|
||||||
|
"init": "Player initialization failed:",
|
||||||
|
"noVideo": "Video element not found",
|
||||||
|
"screenshot": "Failed to get video screenshot:"
|
||||||
|
},
|
||||||
|
"player": {
|
||||||
|
"autoplay": true,
|
||||||
|
"muted": true,
|
||||||
|
"width": "100%",
|
||||||
|
"height": "100%"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error_mess": "Failed to get live content, retry?",
|
||||||
|
"success_mess": "Bid successful",
|
||||||
|
"warn_mess": "Bidding is not enabled",
|
||||||
|
"now_price": "Current Price",
|
||||||
|
"lower_price": "Next Increment",
|
||||||
|
"confirm": "Confirm Bid",
|
||||||
|
"button": "Click 'Enable Bidding' to participate",
|
||||||
|
"start": "Start Auction",
|
||||||
|
"head": "Leading",
|
||||||
|
"out": "Out",
|
||||||
|
"success": "Successful",
|
||||||
|
"next_lot": "Next lot coming soon",
|
||||||
|
"spot": "Onsite Bidding",
|
||||||
|
"network": "Online Bidding",
|
||||||
|
"me": "Me",
|
||||||
|
"all_pay": "Pay in Full",
|
||||||
|
"part_pay": "Partial Payment",
|
||||||
|
"lots": "Lots",
|
||||||
|
"colse_bid": "Close Bidding",
|
||||||
|
"start_bid": "Enable Bidding",
|
||||||
|
"total": "Total",
|
||||||
|
"lots_num": "lots",
|
||||||
|
"cast": "Casting",
|
||||||
|
"wait_update": "Waiting for Update",
|
||||||
|
"text1": "Hammer soon",
|
||||||
|
"text2": "Someone has placed a bid",
|
||||||
|
"text3": "Please bid after update",
|
||||||
|
"text4": "Congratulations, you won the bid",
|
||||||
|
"text5": "Please make payment",
|
||||||
|
"text6": "This lot has ended",
|
||||||
|
"text7": "Please wait for the next lot",
|
||||||
|
"text8": "Sorry, bidding unsuccessful",
|
||||||
|
"text9": "Bidding ended",
|
||||||
|
"text10": "Bidding ended, thank you for participating"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacyPolicy": {
|
||||||
|
"title": "Privacy Policy",
|
||||||
|
"content": {
|
||||||
|
"header": "Please read the 'Fenghe Privacy Policy' carefully (especially the bold content) and make sure you understand our rules for handling your personal information. If you have any questions during reading, you can contact our customer service for consultation. If you do not agree with any terms in the agreement, you should stop accessing immediately.",
|
||||||
|
"version": "Version update date: February 6, 2025",
|
||||||
|
"scope": "Fenghe Privacy Policy applies to the online auction, shopping and other products or services under Shanghai Fenghe Auction Co., Ltd., including but not limited to online auction live, online bidding, domestic proxy bidding, overseas proxy bidding, time-limited auction, consignment, global art purchase, family collections and other websites, clients, mini programs, as well as various products and/or services provided to you as new forms emerge with technological development."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectCode": {
|
||||||
|
"login": {
|
||||||
|
"title": "Collection Code Login",
|
||||||
|
"phoneNumber": "Phone Number",
|
||||||
|
"phoneNumberPlaceholder": "Please enter phone number",
|
||||||
|
"password": "Password",
|
||||||
|
"passwordPlaceholder": "Please enter password",
|
||||||
|
"passwordLogin": "Password Login",
|
||||||
|
"codeLogin": "Verification Code Login",
|
||||||
|
"getCode": "Get Code",
|
||||||
|
"login": "Login",
|
||||||
|
"hasSendTo": "Sent to",
|
||||||
|
"reSend": "Resend",
|
||||||
|
"back": "Back"
|
||||||
|
},
|
||||||
|
"mine": {
|
||||||
|
"title": "Profile",
|
||||||
|
"logout": "Logout",
|
||||||
|
"offlineQrcode": "Offline Payment QR Code",
|
||||||
|
"refreshSuccess": "Refresh successful",
|
||||||
|
"noMore": "No more data",
|
||||||
|
"add": "Add",
|
||||||
|
"addQrcode": {
|
||||||
|
"title": "Add Payment QR Code",
|
||||||
|
"amount": "Amount",
|
||||||
|
"amountUnit": "RMB",
|
||||||
|
"amountPlaceholder": "Please enter amount",
|
||||||
|
"lotNo": "Lot No.",
|
||||||
|
"lotNoPlaceholder": "Please enter lot number",
|
||||||
|
"existingWarning": "A payment QR code already exists for this lot number. Are you sure you want to create another one?",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"confirm": "Confirm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qrcode": {
|
||||||
|
"status": {
|
||||||
|
"paid": "Paid",
|
||||||
|
"unpaid": "Unpaid",
|
||||||
|
"partialPaid": "Partially Paid"
|
||||||
|
},
|
||||||
|
"card": {
|
||||||
|
"lotNo": "Lot: ",
|
||||||
|
"creator": "Creator: ",
|
||||||
|
"createTime": "Created: ",
|
||||||
|
"view": "View"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "Payment",
|
||||||
|
"fullPayment": "Pay in Full",
|
||||||
|
"partialPayment": "Partial Payment",
|
||||||
|
"confirmPayment": "Confirm Payment",
|
||||||
|
"maxAmount": "Maximum {currency}{price}",
|
||||||
|
"enterAmount": "Please enter amount",
|
||||||
|
"exceedTotal": "Cannot exceed total amount"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"title": "Signature",
|
||||||
|
"back": "Back",
|
||||||
|
"clear": "Clear",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"pleaseSign": "Please sign first",
|
||||||
|
"loading": "Loading..."
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"amountRequired": "Please enter amount",
|
||||||
|
"lotNoRequired": "Please enter Lot No.",
|
||||||
|
"deleteSuccess": "Delete successful"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"required": "This field is required",
|
||||||
|
"invalidFormat": "Invalid format",
|
||||||
|
"invalidPhone": "Please enter a valid phone number",
|
||||||
|
"invalidEmail": "Please enter a valid email address",
|
||||||
|
"invalidPassword": "Invalid password format",
|
||||||
|
"invalidCode": "Invalid verification code format",
|
||||||
|
"invalidAmount": "Please enter a valid amount",
|
||||||
|
"invalidNumber": "Please enter a valid number"
|
||||||
|
},
|
||||||
|
"realName": {
|
||||||
|
"title": "Real Name Authentication",
|
||||||
|
"cnTab": "Chinese Mainland Residents",
|
||||||
|
"otherTab": "Non-Chinese Mainland Residents",
|
||||||
|
"cnTabDesc": "Please fill in ID card information",
|
||||||
|
"otherTabDesc": "Please upload personal information",
|
||||||
|
"idCard": "ID Card Number",
|
||||||
|
"idCardPlaceholder": "Please enter ID card number",
|
||||||
|
"name": "Name",
|
||||||
|
"namePlaceholder": "Please enter your name",
|
||||||
|
"gender": "Gender",
|
||||||
|
"male": "Male",
|
||||||
|
"female": "Female",
|
||||||
|
"birthday": "Date of Birth",
|
||||||
|
"birthdayPlaceholder": "Please select date of birth",
|
||||||
|
"address": "Home Address",
|
||||||
|
"addressPlaceholder": "Please enter home address",
|
||||||
|
"bank": "Bank",
|
||||||
|
"bankPlaceholder": "Please select bank",
|
||||||
|
"bankCard": "Bank Card Number",
|
||||||
|
"bankCardPlaceholder": "Please enter bank card number",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"success": "Submission successful",
|
||||||
|
"selectGender": "Please select gender"
|
||||||
|
},
|
||||||
|
"auction": {
|
||||||
|
"title": "Lot Details",
|
||||||
|
"area": "Total Area",
|
||||||
|
"length": "Length",
|
||||||
|
"width": "Width",
|
||||||
|
"description": "Artwork Description",
|
||||||
|
"startPrice": "Starting Price",
|
||||||
|
"bidList": "Bidding History",
|
||||||
|
"detail": "Lot Details",
|
||||||
|
"tab": {
|
||||||
|
"detail": "Lot Details",
|
||||||
|
"description": "Lot Description"
|
||||||
|
},
|
||||||
|
"lotDetail": "LOT Details",
|
||||||
|
"refresh": {
|
||||||
|
"success": "Refresh successful",
|
||||||
|
"noMore": "No more data"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"start": "Starting Price",
|
||||||
|
"current": "Current Price",
|
||||||
|
"hammer": "Hammer Price"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"live": {
|
||||||
|
"enterRoom": "Click to enter live room",
|
||||||
|
"beijingTime": "Beijing Time",
|
||||||
|
"status": {
|
||||||
|
"notStarted": "Not Started",
|
||||||
|
"live": "Live",
|
||||||
|
"ended": "Ended"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"networkError": "Network error, please check your connection",
|
||||||
|
"reconnecting": "Reconnecting...",
|
||||||
|
"reconnectSuccess": "Reconnection successful",
|
||||||
|
"reconnectFail": "Reconnection failed, please refresh the page"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"title": "Country/Region",
|
||||||
|
"searchPlaceholder": "Enter country or region",
|
||||||
|
"frequentCountry": "Frequently Used"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"name": "FENGHE",
|
||||||
|
"description": "FENGHE International Kyoto Auction",
|
||||||
|
"keywords": "FENGHE,FENGHE CULTURE,FENGHE,KYOTO,AUCTION",
|
||||||
|
"language": "📚 Language",
|
||||||
|
"unocssExample": "🎨 Unocss Example",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"error": {
|
||||||
|
"404": {
|
||||||
|
"title": "Page Not Found",
|
||||||
|
"back": "Back"
|
||||||
|
},
|
||||||
|
"network": "Network Error",
|
||||||
|
"server": "Server Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bid": {
|
||||||
|
"title": "Bidding",
|
||||||
|
"noBids": "No bidding items",
|
||||||
|
"bidNow": "Bid Now",
|
||||||
|
"success": "Bid Successful",
|
||||||
|
"fail": "Bid Failed",
|
||||||
|
"confirm": "Confirm Bid",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"amount": "Bid Amount",
|
||||||
|
"currentPrice": "Current Price",
|
||||||
|
"nextPrice": "Next Increment",
|
||||||
|
"bidHistory": "Bidding History",
|
||||||
|
"bidder": "Bidder",
|
||||||
|
"bidTime": "Bid Time",
|
||||||
|
"bidAmount": "Bid Amount",
|
||||||
|
"status": {
|
||||||
|
"bidding": "Bidding",
|
||||||
|
"ended": "Ended",
|
||||||
|
"upcoming": "Upcoming",
|
||||||
|
"cancelled": "Cancelled"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"confirmBid": "Confirm bid of {amount}?",
|
||||||
|
"bidSuccess": "Bid successful",
|
||||||
|
"bidFail": "Bid failed",
|
||||||
|
"priceChanged": "Price has been updated, please bid again",
|
||||||
|
"insufficientBalance": "Insufficient balance",
|
||||||
|
"notQualified": "You are not qualified to bid",
|
||||||
|
"auctionEnded": "Auction has ended",
|
||||||
|
"auctionNotStarted": "Auction has not started"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "Settings",
|
||||||
|
"language": "Language",
|
||||||
|
"notification": "Notifications",
|
||||||
|
"about": "About Us",
|
||||||
|
"feedback": "Feedback",
|
||||||
|
"privacy": "Privacy Policy",
|
||||||
|
"terms": "Terms of Service",
|
||||||
|
"version": "Version Information",
|
||||||
|
"logout": "Logout",
|
||||||
|
"darkMode": "Dark Mode",
|
||||||
|
"auto": "System",
|
||||||
|
"light": "Light",
|
||||||
|
"dark": "Dark"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"default": {
|
||||||
|
"title": "FENGHE Auction",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"error": "Error",
|
||||||
|
"retry": "Retry",
|
||||||
|
"back": "Back"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"notFound": "Page Not Found",
|
||||||
|
"back": "Back to Home",
|
||||||
|
"retry": "Retry"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"loading": {
|
||||||
|
"text": "Loading..."
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"text": "No Data",
|
||||||
|
"description": "No relevant content found"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"text": "Error",
|
||||||
|
"description": "Loading failed, please try again",
|
||||||
|
"button": "Retry"
|
||||||
|
},
|
||||||
|
"navbar": {
|
||||||
|
"back": "Back",
|
||||||
|
"close": "Close",
|
||||||
|
"home": "Home"
|
||||||
|
},
|
||||||
|
"tabbar": {
|
||||||
|
"home": "Home",
|
||||||
|
"auction": "Auction",
|
||||||
|
"live": "Live",
|
||||||
|
"profile": "Profile"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"close": "Close"
|
||||||
|
},
|
||||||
|
"toast": {
|
||||||
|
"success": "Success",
|
||||||
|
"fail": "Failed",
|
||||||
|
"loading": "Loading..."
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"required": "Required",
|
||||||
|
"optional": "Optional",
|
||||||
|
"save": "Save",
|
||||||
|
"submit": "Submit",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"pleaseInput": "Please enter",
|
||||||
|
"pleaseSelect": "Please select"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"text": "Click to Upload",
|
||||||
|
"delete": "Delete",
|
||||||
|
"preview": "Preview",
|
||||||
|
"maxSize": "File size cannot exceed {size}",
|
||||||
|
"format": "Supported formats: {formats}",
|
||||||
|
"uploading": "Uploading...",
|
||||||
|
"uploadSuccess": "Upload successful",
|
||||||
|
"uploadFail": "Upload failed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"floatingBubble": {
|
||||||
|
"backToLive": "Back to Live"
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"error": {
|
||||||
|
"badRequest": "Invalid request parameters",
|
||||||
|
"unauthorized": "Unauthorized or login expired",
|
||||||
|
"forbidden": "Access forbidden",
|
||||||
|
"notFound": "Requested resource not found",
|
||||||
|
"serverError": "Server internal error",
|
||||||
|
"badGateway": "Gateway error",
|
||||||
|
"serviceUnavailable": "Service temporarily unavailable",
|
||||||
|
"gatewayTimeout": "Gateway timeout",
|
||||||
|
"operationFailed": "Operation failed",
|
||||||
|
"loginExpired": "Login has expired, please login again",
|
||||||
|
"networkError": "Network connection failed, please check your network settings",
|
||||||
|
"requestFailed": "Request failed",
|
||||||
|
"httpNotInitialized": "HTTP client not initialized. Call setupHttp first."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,120 @@
|
|||||||
{
|
{
|
||||||
"appSetting": {
|
"appSetting": {
|
||||||
"appName": "豊和",
|
"appName": "FENGHE",
|
||||||
"appDescription": "泰豊国際京都オークション",
|
"appDescription": "泰風インターナショナル京都オークション",
|
||||||
"appKeyWords": "泰豊,泰豊文化,豊和,京都,オークション"
|
"appKeyWords": "泰風,泰風文化,FENGHE,京都,オークション"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"home": "ホーム",
|
"home": "京都オークション",
|
||||||
"profile": "マイページ",
|
"profile": "プロフィール",
|
||||||
"darkMode": "🌗 ダークモード",
|
"darkMode": "🌗 ダークモード",
|
||||||
"language": "📚 言語",
|
"language": "📚 言語",
|
||||||
"404Demo": "🙅 404ページ デモ",
|
"404Demo": "🙅 404ページデモ",
|
||||||
"unocssExample": "🎨 Unocss 例",
|
"unocssExample": "🎨 Unocssの例",
|
||||||
"keepAlive": "🧡 KeepAlive デモ",
|
"keepAlive": "🧡 KeepAliveデモ",
|
||||||
"persistPiniaState": "💾 Pinia 状態の永続化",
|
"persistPiniaState": "💾 Piniaの状態を保持",
|
||||||
"fetch": "🏄 ネットワークリクエスト"
|
"fetch": "🏄 ネットワークリクエスト",
|
||||||
|
"auction": "オークション",
|
||||||
|
"live": "ライブ",
|
||||||
|
"settings": "設定"
|
||||||
},
|
},
|
||||||
"tabbar": {
|
"tabbar": {
|
||||||
"home": "ホーム",
|
"home": "ホーム",
|
||||||
"profile": "マイページ"
|
"profile": "プロフィール"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "ログイン",
|
"title": "ログイン",
|
||||||
"phonePlaceholder": "携帯番号を入力してください",
|
"phonePlaceholder": "電話番号を入力してください",
|
||||||
"getCode": "認証コードを取得",
|
"getCode": "認証コードを取得",
|
||||||
"login": "ログイン",
|
"login": "ログイン",
|
||||||
"back": "戻る",
|
"back": "戻る",
|
||||||
"hasSendTo": "認証コードは",
|
"hasSendTo": "認証コードを送信しました:",
|
||||||
"reSend": "再送"
|
"reSend": "再送信",
|
||||||
|
"agreement": "ログインすることで",
|
||||||
|
"privacyPolicy": "プライバシーポリシー"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"items": "点",
|
||||||
|
"auction": "オークション",
|
||||||
|
"loading": "読み込み中...",
|
||||||
|
"networkError": "ネットワークエラー、再試行してください",
|
||||||
|
"systemError": "システムエラー、後でもう一度お試しください",
|
||||||
|
"success": "操作が成功しました",
|
||||||
|
"fail": "操作が失敗しました",
|
||||||
|
"confirm": "確認",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"back": "戻る",
|
||||||
|
"next": "次へ",
|
||||||
|
"save": "保存",
|
||||||
|
"edit": "編集",
|
||||||
|
"delete": "削除",
|
||||||
|
"view": "表示",
|
||||||
|
"close": "閉じる",
|
||||||
|
"refresh": "更新",
|
||||||
|
"noData": "データがありません",
|
||||||
|
"loadMore": "もっと読み込む",
|
||||||
|
"noMore": "これ以上ありません",
|
||||||
|
"refreshSuccess": "更新成功",
|
||||||
|
"pleaseInput": "入力してください",
|
||||||
|
"pleaseSelect": "選択してください"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"name": "名前",
|
||||||
|
"phone": "電話番号",
|
||||||
|
"text1": "出品物がありません",
|
||||||
|
"text2": "今すぐ入札",
|
||||||
|
"title": "プロフィール",
|
||||||
|
"account": {
|
||||||
|
"title": "アカウント情報",
|
||||||
|
"avatar": "アバター",
|
||||||
|
"nickname": "ニックネーム",
|
||||||
|
"phone": "電話番号",
|
||||||
|
"email": "メールアドレス",
|
||||||
|
"realName": "本人確認",
|
||||||
|
"verified": "認証済み",
|
||||||
|
"unverified": "未認証",
|
||||||
|
"edit": "編集"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"title": "注文履歴",
|
||||||
|
"all": "すべて",
|
||||||
|
"unpaid": "未払い",
|
||||||
|
"paid": "支払い済み",
|
||||||
|
"completed": "完了",
|
||||||
|
"cancelled": "キャンセル"
|
||||||
|
},
|
||||||
|
"favorite": {
|
||||||
|
"title": "お気に入り",
|
||||||
|
"empty": "お気に入りがありません",
|
||||||
|
"delete": "削除",
|
||||||
|
"deleteConfirm": "選択したお気に入りを削除しますか?"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"title": "配送先住所",
|
||||||
|
"add": "住所を追加",
|
||||||
|
"edit": "住所を編集",
|
||||||
|
"delete": "住所を削除",
|
||||||
|
"default": "デフォルトの住所",
|
||||||
|
"setDefault": "デフォルトに設定",
|
||||||
|
"name": "受取人",
|
||||||
|
"phone": "電話番号",
|
||||||
|
"region": "地域",
|
||||||
|
"detail": "詳細住所",
|
||||||
|
"save": "保存",
|
||||||
|
"deleteConfirm": "この住所を削除しますか?"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "設定",
|
||||||
|
"notification": "通知",
|
||||||
|
"language": "言語",
|
||||||
|
"about": "当社について",
|
||||||
|
"logout": "ログアウト",
|
||||||
|
"logoutConfirm": "ログアウトしますか?"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error_page": {
|
"error_page": {
|
||||||
"back_btn": "戻る",
|
"back_btn": "戻る",
|
||||||
"txt": "ページが見つかりません"
|
"txt": "見つかりません"
|
||||||
},
|
},
|
||||||
"prose_page": {
|
"prose_page": {
|
||||||
"btn_fetch": "取得",
|
"btn_fetch": "取得",
|
||||||
@ -38,20 +122,21 @@
|
|||||||
"btn_empty_desc": "データなし"
|
"btn_empty_desc": "データなし"
|
||||||
},
|
},
|
||||||
"countryRegion": {
|
"countryRegion": {
|
||||||
"title": "国と地域",
|
"title": "国/地域",
|
||||||
"searchPlaceholder": "国と地域を入力してください",
|
"searchPlaceholder": "国または地域を入力",
|
||||||
"frequentCountry": "よく使う"
|
"frequentCountry": "よく使用する"
|
||||||
},
|
},
|
||||||
"realAuth": {
|
"realAuth": {
|
||||||
"title": "実名認証",
|
"phonePlaceholder": "電話番号を入力してください",
|
||||||
"cnTab": "中国本土住民",
|
"title": "本人確認",
|
||||||
"otherTab": "非中国本土住民",
|
"cnTab": "中国本土居住者",
|
||||||
"cnTabDesc": "身分証情報を入力してください",
|
"otherTab": "中国本土以外の居住者",
|
||||||
|
"cnTabDesc": "身分証明書の情報を入力してください",
|
||||||
"otherTabDesc": "個人情報をアップロードしてください",
|
"otherTabDesc": "個人情報をアップロードしてください",
|
||||||
"idCard": "身分証番号",
|
"idCard": "身分証明書番号",
|
||||||
"idCardPlaceholder": "身分証番号を入力してください",
|
"idCardPlaceholder": "身分証明書番号を入力してください",
|
||||||
"name": "氏名",
|
"name": "名前",
|
||||||
"namePlaceholder": "氏名を入力してください",
|
"namePlaceholder": "名前を入力してください",
|
||||||
"gender": "性別",
|
"gender": "性別",
|
||||||
"male": "男性",
|
"male": "男性",
|
||||||
"female": "女性",
|
"female": "女性",
|
||||||
@ -59,11 +144,519 @@
|
|||||||
"birthdayPlaceholder": "生年月日を入力してください",
|
"birthdayPlaceholder": "生年月日を入力してください",
|
||||||
"adress": "住所",
|
"adress": "住所",
|
||||||
"adressPlaceholder": "住所を入力してください",
|
"adressPlaceholder": "住所を入力してください",
|
||||||
"bank": "所属銀行",
|
"bank": "銀行",
|
||||||
"bankPlaceholder": "所属銀行を選択してください",
|
"bankPlaceholder": "銀行を選択してください",
|
||||||
"bankCard": "銀行カード番号",
|
"bankCard": "銀行カード番号",
|
||||||
"bankCardPlaceholder": "銀行カード番号を入力してください",
|
"bankCardPlaceholder": "銀行カード番号を入力してください",
|
||||||
"cancel": "キャンセル",
|
"cancel": "キャンセル",
|
||||||
"confirm": "確定"
|
"confirm": "確認",
|
||||||
|
"success_mess": "提出が完了しました",
|
||||||
|
"text1": "性別を選択してください",
|
||||||
|
"detail": {
|
||||||
|
"gender": {
|
||||||
|
"male": "男性",
|
||||||
|
"female": "女性"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"detail": {
|
||||||
|
"text1": "アーティスト",
|
||||||
|
"text2": "総面積",
|
||||||
|
"text3": "長さ",
|
||||||
|
"text4": "幅",
|
||||||
|
"text5": "作品説明",
|
||||||
|
"text6": "開始価格",
|
||||||
|
"text7": "入札履歴",
|
||||||
|
"text8": "商品詳細"
|
||||||
|
},
|
||||||
|
"art_detail_page": {
|
||||||
|
"button": "支払う",
|
||||||
|
"prompt_title": "おめでとうございます",
|
||||||
|
"prompt_desc": "入札成功"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"tab1": "商品一覧",
|
||||||
|
"tab2": "オークション説明",
|
||||||
|
"lot_detail": "商品詳細",
|
||||||
|
"refresh_show": "更新成功",
|
||||||
|
"finished_text": "これ以上ありません",
|
||||||
|
"start_price": "開始価格",
|
||||||
|
"close_price": "落札価格",
|
||||||
|
"my_lots": "マイ商品",
|
||||||
|
"go_home": "ホームへ",
|
||||||
|
"text1": "クリックしてライブルームに入る",
|
||||||
|
"text2": "北京時間"
|
||||||
|
},
|
||||||
|
"live_room": {
|
||||||
|
"error_mess": "ライブコンテンツの取得に失敗しました。再試行しますか?",
|
||||||
|
"success_mess": "入札成功",
|
||||||
|
"warn_mess": "入札が有効になっていません",
|
||||||
|
"now_price": "現在価格",
|
||||||
|
"lower_price": "次の最低価格",
|
||||||
|
"confirm": "入札確認",
|
||||||
|
"button": "'入札を有効にする'をクリックして参加",
|
||||||
|
"start": "オークション開始",
|
||||||
|
"head": "リード",
|
||||||
|
"out": "アウト",
|
||||||
|
"success": "成立",
|
||||||
|
"next_lot": "次の商品がまもなく開始",
|
||||||
|
"spot": "会場入札",
|
||||||
|
"network": "オンライン入札",
|
||||||
|
"me": "私",
|
||||||
|
"all_pay": "全額支払い",
|
||||||
|
"part_pay": "一部支払い",
|
||||||
|
"lots": "ロット",
|
||||||
|
"colse_bid": "入札を閉じる",
|
||||||
|
"start_bid": "入札を開始",
|
||||||
|
"total": "合計",
|
||||||
|
"lots_num": "ロット",
|
||||||
|
"cast": "キャスティング",
|
||||||
|
"wait_update": "更新を待っています",
|
||||||
|
"text1": "まもなく落札",
|
||||||
|
"text2": "入札されました",
|
||||||
|
"text3": "更新後に入札してください",
|
||||||
|
"text4": "おめでとうございます、落札成功",
|
||||||
|
"text5": "お支払いをお願いします",
|
||||||
|
"text6": "このロットは終了しました",
|
||||||
|
"text7": "次のロットをお待ちください",
|
||||||
|
"text8": "申し訳ありません、落札失敗",
|
||||||
|
"text9": "入札終了",
|
||||||
|
"text10": "入札終了、ご参加ありがとうございました"
|
||||||
|
},
|
||||||
|
"personal": {
|
||||||
|
"title": "個人情報を入力してください",
|
||||||
|
"text": "テキスト",
|
||||||
|
"next": "次へ"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "支払い",
|
||||||
|
"result": {
|
||||||
|
"title": "支払い結果",
|
||||||
|
"success": "支払い成功",
|
||||||
|
"fail": "支払い失敗",
|
||||||
|
"unpaid": "未払い",
|
||||||
|
"expired": "支払い期限切れ",
|
||||||
|
"partial": "一部支払い"
|
||||||
|
},
|
||||||
|
"text1": "支払い結果",
|
||||||
|
"text2": "支払い成功",
|
||||||
|
"text3": "支払い失敗",
|
||||||
|
"text4": "未払い",
|
||||||
|
"text5": "支払い期限切れ",
|
||||||
|
"text6": "一部支払い",
|
||||||
|
"next": "次へ",
|
||||||
|
"backHome": "ホームに戻る",
|
||||||
|
"confirm": "支払い確認",
|
||||||
|
"fullPayment": "全額支払い",
|
||||||
|
"partialPayment": "一部支払い",
|
||||||
|
"loading": "読み込み中...",
|
||||||
|
"error": {
|
||||||
|
"enterAmount": "金額を入力してください",
|
||||||
|
"exceedTotal": "合計金額を超えることはできません",
|
||||||
|
"invalidAmount": "有効な支払い金額を入力してください",
|
||||||
|
"networkError": "ネットワークエラー、再試行してください",
|
||||||
|
"systemError": "システムエラー、後でもう一度お試しください"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"amount": "最大 {currency}{price}"
|
||||||
|
},
|
||||||
|
"amount": "支払い金額"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"protocol": {
|
||||||
|
"loading": "読み込み中...",
|
||||||
|
"title": "署名内容",
|
||||||
|
"agree": "同意して署名",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"confirm": "確認",
|
||||||
|
"success": "署名成功",
|
||||||
|
"fail": "署名失敗",
|
||||||
|
"back": "戻る"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"agreeAndSign": "同意して署名"
|
||||||
|
},
|
||||||
|
"loading": "読み込み中...",
|
||||||
|
"agreement": {
|
||||||
|
"notice": "オークション通知",
|
||||||
|
"rules": "オークションルール",
|
||||||
|
"buyerGuide": "バイヤーガイド",
|
||||||
|
"buyerAgreement": "バイヤー契約",
|
||||||
|
"record": "オークション記録確認",
|
||||||
|
"transfer": "オークション譲渡確認"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"getRecord": "オークション記録の取得に失敗しました"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"agree": "同意して署名",
|
||||||
|
"back": "戻る",
|
||||||
|
"clear": "クリア",
|
||||||
|
"confirm": "確認"
|
||||||
|
},
|
||||||
|
"tips": {
|
||||||
|
"landscape": "横向きでご使用ください",
|
||||||
|
"needSign": "最初に署名してください",
|
||||||
|
"prePayment": "支払い前に同意して署名してください"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"liveRoom": {
|
||||||
|
"loading": "ライブストリーム読み込み中...",
|
||||||
|
"error": {
|
||||||
|
"player": "プレーヤーエラー:",
|
||||||
|
"init": "プレーヤーの初期化に失敗しました:",
|
||||||
|
"noVideo": "ビデオ要素が見つかりません",
|
||||||
|
"screenshot": "ビデオスクリーンショットの取得に失敗しました:"
|
||||||
|
},
|
||||||
|
"player": {
|
||||||
|
"autoplay": true,
|
||||||
|
"muted": true,
|
||||||
|
"width": "100%",
|
||||||
|
"height": "100%"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error_mess": "ライブコンテンツの取得に失敗しました。再試行しますか?",
|
||||||
|
"success_mess": "入札成功",
|
||||||
|
"warn_mess": "入札が有効になっていません",
|
||||||
|
"now_price": "現在価格",
|
||||||
|
"lower_price": "次の最低価格",
|
||||||
|
"confirm": "入札確認",
|
||||||
|
"button": "'入札を有効にする'をクリックして参加",
|
||||||
|
"start": "オークション開始",
|
||||||
|
"head": "リード",
|
||||||
|
"out": "アウト",
|
||||||
|
"success": "成立",
|
||||||
|
"next_lot": "次の商品がまもなく開始",
|
||||||
|
"spot": "会場入札",
|
||||||
|
"network": "オンライン入札",
|
||||||
|
"me": "私",
|
||||||
|
"all_pay": "全額支払い",
|
||||||
|
"part_pay": "一部支払い",
|
||||||
|
"lots": "ロット",
|
||||||
|
"colse_bid": "入札を閉じる",
|
||||||
|
"start_bid": "入札を開始",
|
||||||
|
"total": "合計",
|
||||||
|
"lots_num": "ロット",
|
||||||
|
"cast": "キャスティング",
|
||||||
|
"wait_update": "更新を待っています",
|
||||||
|
"text1": "まもなく落札",
|
||||||
|
"text2": "入札されました",
|
||||||
|
"text3": "更新後に入札してください",
|
||||||
|
"text4": "おめでとうございます、落札成功",
|
||||||
|
"text5": "お支払いをお願いします",
|
||||||
|
"text6": "このロットは終了しました",
|
||||||
|
"text7": "次のロットをお待ちください",
|
||||||
|
"text8": "申し訳ありません、落札失敗",
|
||||||
|
"text9": "入札終了",
|
||||||
|
"text10": "入札終了、ご参加ありがとうございました"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacyPolicy": {
|
||||||
|
"title": "プライバシーポリシー",
|
||||||
|
"content": {
|
||||||
|
"header": "「Fengheプライバシーポリシー」を注意深くお読みください(特に太字の内容)、そして個人情報の取り扱いに関する規則をご理解ください。読んでいる間に質問がある場合は、カスタマーサービスにお問い合わせください。契約内の条項に同意しない場合は、直ちにアクセスを停止してください。",
|
||||||
|
"version": "バージョン更新日:2025年2月6日",
|
||||||
|
"scope": "Fengheプライバシーポリシーは、上海Fengheオークション株式会社のオンラインオークション、ショッピングなどの製品やサービスに適用されます。これには、オンラインオークションライブ、オンライン入札、国内代理入札、海外代理入札、期間限定オークション、委託、グローバルアート購入、家族コレクションなどのウェブサイト、クライアント、ミニプログラム、および技術の発展に伴い新しい形で提供される様々な製品やサービスが含まれます。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectCode": {
|
||||||
|
"login": {
|
||||||
|
"title": "コレクションコードログイン",
|
||||||
|
"phoneNumber": "電話番号",
|
||||||
|
"phoneNumberPlaceholder": "電話番号を入力してください",
|
||||||
|
"password": "パスワード",
|
||||||
|
"passwordPlaceholder": "パスワードを入力してください",
|
||||||
|
"passwordLogin": "パスワードログイン",
|
||||||
|
"codeLogin": "認証コードログイン",
|
||||||
|
"getCode": "コードを取得",
|
||||||
|
"login": "ログイン",
|
||||||
|
"hasSendTo": "送信先",
|
||||||
|
"reSend": "再送信",
|
||||||
|
"back": "戻る"
|
||||||
|
},
|
||||||
|
"mine": {
|
||||||
|
"title": "プロフィール",
|
||||||
|
"logout": "ログアウト",
|
||||||
|
"offlineQrcode": "オフライン支払いQRコード",
|
||||||
|
"refreshSuccess": "更新成功",
|
||||||
|
"noMore": "これ以上ありません",
|
||||||
|
"add": "追加",
|
||||||
|
"addQrcode": {
|
||||||
|
"title": "支払いQRコードを追加",
|
||||||
|
"amount": "金額",
|
||||||
|
"amountUnit": "RMB",
|
||||||
|
"amountPlaceholder": "金額を入力してください",
|
||||||
|
"lotNo": "ロット番号",
|
||||||
|
"lotNoPlaceholder": "ロット番号を入力してください",
|
||||||
|
"existingWarning": "このロット番号の支払いQRコードはすでに存在します。別のコードを作成しますか?",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"confirm": "確認"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qrcode": {
|
||||||
|
"status": {
|
||||||
|
"paid": "支払い済み",
|
||||||
|
"unpaid": "未払い",
|
||||||
|
"partialPaid": "一部支払い済み"
|
||||||
|
},
|
||||||
|
"card": {
|
||||||
|
"lotNo": "ロット:",
|
||||||
|
"creator": "作成者:",
|
||||||
|
"createTime": "作成日時:",
|
||||||
|
"view": "表示"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "支払い",
|
||||||
|
"fullPayment": "全額支払い",
|
||||||
|
"partialPayment": "一部支払い",
|
||||||
|
"confirmPayment": "支払い確認",
|
||||||
|
"maxAmount": "最大 {currency}{price}",
|
||||||
|
"enterAmount": "金額を入力してください",
|
||||||
|
"exceedTotal": "合計金額を超えることはできません"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"title": "署名",
|
||||||
|
"back": "戻る",
|
||||||
|
"clear": "クリア",
|
||||||
|
"confirm": "確認",
|
||||||
|
"pleaseSign": "最初に署名してください",
|
||||||
|
"loading": "読み込み中..."
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"amountRequired": "金額を入力してください",
|
||||||
|
"lotNoRequired": "ロット番号を入力してください",
|
||||||
|
"deleteSuccess": "削除成功"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"required": "この項目は必須です",
|
||||||
|
"invalidFormat": "形式が無効です",
|
||||||
|
"invalidPhone": "有効な電話番号を入力してください",
|
||||||
|
"invalidEmail": "有効なメールアドレスを入力してください",
|
||||||
|
"invalidPassword": "無効なパスワード形式",
|
||||||
|
"invalidCode": "無効な認証コード形式",
|
||||||
|
"invalidAmount": "有効な金額を入力してください",
|
||||||
|
"invalidNumber": "有効な数値を入力してください"
|
||||||
|
},
|
||||||
|
"realName": {
|
||||||
|
"title": "本人確認",
|
||||||
|
"cnTab": "中国本土居住者",
|
||||||
|
"otherTab": "中国本土以外の居住者",
|
||||||
|
"cnTabDesc": "身分証明書の情報を入力してください",
|
||||||
|
"otherTabDesc": "個人情報をアップロードしてください",
|
||||||
|
"idCard": "身分証明書番号",
|
||||||
|
"idCardPlaceholder": "身分証明書番号を入力してください",
|
||||||
|
"name": "名前",
|
||||||
|
"namePlaceholder": "名前を入力してください",
|
||||||
|
"gender": "性別",
|
||||||
|
"male": "男性",
|
||||||
|
"female": "女性",
|
||||||
|
"birthday": "生年月日",
|
||||||
|
"birthdayPlaceholder": "生年月日を選択してください",
|
||||||
|
"address": "住所",
|
||||||
|
"addressPlaceholder": "住所を入力してください",
|
||||||
|
"bank": "銀行",
|
||||||
|
"bankPlaceholder": "銀行を選択してください",
|
||||||
|
"bankCard": "銀行カード番号",
|
||||||
|
"bankCardPlaceholder": "銀行カード番号を入力してください",
|
||||||
|
"confirm": "確認",
|
||||||
|
"success": "提出成功",
|
||||||
|
"selectGender": "性別を選択してください"
|
||||||
|
},
|
||||||
|
"auction": {
|
||||||
|
"title": "商品詳細",
|
||||||
|
"area": "総面積",
|
||||||
|
"length": "長さ",
|
||||||
|
"width": "幅",
|
||||||
|
"description": "作品説明",
|
||||||
|
"startPrice": "開始価格",
|
||||||
|
"bidList": "入札履歴",
|
||||||
|
"detail": "商品詳細",
|
||||||
|
"tab": {
|
||||||
|
"detail": "商品詳細",
|
||||||
|
"description": "商品説明"
|
||||||
|
},
|
||||||
|
"lotDetail": "ロット詳細",
|
||||||
|
"refresh": {
|
||||||
|
"success": "更新成功",
|
||||||
|
"noMore": "これ以上ありません"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"start": "開始価格",
|
||||||
|
"current": "現在価格",
|
||||||
|
"hammer": "落札価格"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"live": {
|
||||||
|
"enterRoom": "クリックしてライブルームに入る",
|
||||||
|
"beijingTime": "北京時間",
|
||||||
|
"status": {
|
||||||
|
"notStarted": "未開始",
|
||||||
|
"live": "ライブ中",
|
||||||
|
"ended": "終了"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"networkError": "ネットワークエラー、接続を確認してください",
|
||||||
|
"reconnecting": "再接続中...",
|
||||||
|
"reconnectSuccess": "再接続成功",
|
||||||
|
"reconnectFail": "再接続失敗、ページを更新してください"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"title": "国/地域",
|
||||||
|
"searchPlaceholder": "国または地域を入力",
|
||||||
|
"frequentCountry": "よく使用する"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"name": "FENGHE",
|
||||||
|
"description": "FENGHEインターナショナル京都オークション",
|
||||||
|
"keywords": "FENGHE,FENGHE文化,FENGHE,京都,オークション",
|
||||||
|
"language": "📚 言語",
|
||||||
|
"unocssExample": "🎨 Unocss例",
|
||||||
|
"loading": "読み込み中...",
|
||||||
|
"error": {
|
||||||
|
"404": {
|
||||||
|
"title": "ページが見つかりません",
|
||||||
|
"back": "戻る"
|
||||||
|
},
|
||||||
|
"network": "ネットワークエラー",
|
||||||
|
"server": "サーバーエラー"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bid": {
|
||||||
|
"title": "入札",
|
||||||
|
"noBids": "入札アイテムがありません",
|
||||||
|
"bidNow": "今すぐ入札",
|
||||||
|
"success": "入札成功",
|
||||||
|
"fail": "入札失敗",
|
||||||
|
"confirm": "入札確認",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"amount": "入札金額",
|
||||||
|
"currentPrice": "現在価格",
|
||||||
|
"nextPrice": "次の最低価格",
|
||||||
|
"bidHistory": "入札履歴",
|
||||||
|
"bidder": "入札者",
|
||||||
|
"bidTime": "入札時間",
|
||||||
|
"bidAmount": "入札金額",
|
||||||
|
"status": {
|
||||||
|
"bidding": "入札中",
|
||||||
|
"ended": "終了",
|
||||||
|
"upcoming": "まもなく開始",
|
||||||
|
"cancelled": "キャンセル"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"confirmBid": "{amount}の入札を確認しますか?",
|
||||||
|
"bidSuccess": "入札成功",
|
||||||
|
"bidFail": "入札失敗",
|
||||||
|
"priceChanged": "価格が更新されました、再度入札してください",
|
||||||
|
"insufficientBalance": "残高不足",
|
||||||
|
"notQualified": "入札資格がありません",
|
||||||
|
"auctionEnded": "オークションは終了しました",
|
||||||
|
"auctionNotStarted": "オークションはまだ開始していません"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "設定",
|
||||||
|
"language": "言語",
|
||||||
|
"notification": "通知",
|
||||||
|
"about": "当社について",
|
||||||
|
"feedback": "フィードバック",
|
||||||
|
"privacy": "プライバシーポリシー",
|
||||||
|
"terms": "利用規約",
|
||||||
|
"version": "バージョン情報",
|
||||||
|
"logout": "ログアウト",
|
||||||
|
"darkMode": "ダークモード",
|
||||||
|
"auto": "システム設定に従う",
|
||||||
|
"light": "ライト",
|
||||||
|
"dark": "ダーク"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"default": {
|
||||||
|
"title": "FENGHEオークション",
|
||||||
|
"loading": "読み込み中...",
|
||||||
|
"error": "エラー",
|
||||||
|
"retry": "再試行",
|
||||||
|
"back": "戻る"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"notFound": "ページが見つかりません",
|
||||||
|
"back": "ホームに戻る",
|
||||||
|
"retry": "再試行"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"loading": {
|
||||||
|
"text": "読み込み中..."
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"text": "データなし",
|
||||||
|
"description": "関連コンテンツが見つかりません"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"text": "エラー",
|
||||||
|
"description": "読み込みに失敗しました、再試行してください",
|
||||||
|
"button": "再試行"
|
||||||
|
},
|
||||||
|
"navbar": {
|
||||||
|
"back": "戻る",
|
||||||
|
"close": "閉じる",
|
||||||
|
"home": "ホーム"
|
||||||
|
},
|
||||||
|
"tabbar": {
|
||||||
|
"home": "ホーム",
|
||||||
|
"auction": "オークション",
|
||||||
|
"live": "ライブ",
|
||||||
|
"profile": "プロフィール"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"confirm": "確認",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"close": "閉じる"
|
||||||
|
},
|
||||||
|
"toast": {
|
||||||
|
"success": "成功",
|
||||||
|
"fail": "失敗",
|
||||||
|
"loading": "読み込み中..."
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"required": "必須",
|
||||||
|
"optional": "任意",
|
||||||
|
"save": "保存",
|
||||||
|
"submit": "送信",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"pleaseInput": "入力してください",
|
||||||
|
"pleaseSelect": "選択してください"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"text": "アップロードするにはクリック",
|
||||||
|
"delete": "削除",
|
||||||
|
"preview": "プレビュー",
|
||||||
|
"maxSize": "ファイルサイズは{size}を超えることができません",
|
||||||
|
"format": "対応フォーマット:{formats}",
|
||||||
|
"uploading": "アップロード中...",
|
||||||
|
"uploadSuccess": "アップロード成功",
|
||||||
|
"uploadFail": "アップロード失敗"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"floatingBubble": {
|
||||||
|
"backToLive": "ライブに戻る"
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"error": {
|
||||||
|
"badRequest": "リクエストパラメータが無効です",
|
||||||
|
"unauthorized": "認証されていないか、ログインが期限切れです",
|
||||||
|
"forbidden": "アクセスが禁止されています",
|
||||||
|
"notFound": "要求されたリソースが見つかりません",
|
||||||
|
"serverError": "サーバー内部エラー",
|
||||||
|
"badGateway": "ゲートウェイエラー",
|
||||||
|
"serviceUnavailable": "サービスが一時的に利用できません",
|
||||||
|
"gatewayTimeout": "ゲートウェイタイムアウト",
|
||||||
|
"operationFailed": "操作に失敗しました",
|
||||||
|
"loginExpired": "ログインの有効期限が切れました。再度ログインしてください",
|
||||||
|
"networkError": "ネットワーク接続に失敗しました。ネットワーク設定を確認してください",
|
||||||
|
"requestFailed": "リクエストに失敗しました",
|
||||||
|
"httpNotInitialized": "HTTPクライアントが初期化されていません。先にsetupHttpを呼び出してください"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"appKeyWords": "泰丰,泰丰文化,豐和,京都,拍卖会"
|
"appKeyWords": "泰丰,泰丰文化,豐和,京都,拍卖会"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"home": "主页",
|
"home": "京都拍卖会",
|
||||||
"profile": "我的",
|
"profile": "我的",
|
||||||
"darkMode": "🌗 暗黑模式",
|
"darkMode": "🌗 暗黑模式",
|
||||||
"language": "📚 语言",
|
"language": "📚 语言",
|
||||||
@ -13,7 +13,10 @@
|
|||||||
"unocssExample": "🎨 Unocss 示例",
|
"unocssExample": "🎨 Unocss 示例",
|
||||||
"keepAlive": "🧡 KeepAlive 演示",
|
"keepAlive": "🧡 KeepAlive 演示",
|
||||||
"persistPiniaState": "💾 持久化 Pinia 状态",
|
"persistPiniaState": "💾 持久化 Pinia 状态",
|
||||||
"fetch": "🏄 网络请求"
|
"fetch": "🏄 网络请求",
|
||||||
|
"auction": "拍卖",
|
||||||
|
"live": "直播",
|
||||||
|
"settings": "设置"
|
||||||
},
|
},
|
||||||
"tabbar": {
|
"tabbar": {
|
||||||
"home": "主页",
|
"home": "主页",
|
||||||
@ -26,11 +29,88 @@
|
|||||||
"login": "登录",
|
"login": "登录",
|
||||||
"back": "返回",
|
"back": "返回",
|
||||||
"hasSendTo": "已发送验证码至",
|
"hasSendTo": "已发送验证码至",
|
||||||
"reSend": "重新发送"
|
"reSend": "重新发送",
|
||||||
|
"agreement": "登录即同意",
|
||||||
|
"privacyPolicy": "《隐私政策》"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"items": "件",
|
||||||
|
"auction": "拍品",
|
||||||
|
"loading": "加载中...",
|
||||||
|
"networkError": "网络错误,请重试",
|
||||||
|
"systemError": "系统错误,请稍后重试",
|
||||||
|
"success": "操作成功",
|
||||||
|
"fail": "操作失败",
|
||||||
|
"confirm": "确认",
|
||||||
|
"cancel": "取消",
|
||||||
|
"back": "返回",
|
||||||
|
"next": "下一步",
|
||||||
|
"save": "保存",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"view": "查看",
|
||||||
|
"close": "关闭",
|
||||||
|
"refresh": "刷新",
|
||||||
|
"noData": "暂无数据",
|
||||||
|
"loadMore": "加载更多",
|
||||||
|
"noMore": "没有更多了",
|
||||||
|
"refreshSuccess": "刷新成功",
|
||||||
|
"pleaseInput": "请输入",
|
||||||
|
"pleaseSelect": "请选择"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"name": "姓名",
|
"name": "姓名",
|
||||||
"phone": "手机号"
|
"phone": "手机号",
|
||||||
|
"text1": "您暂无拍品",
|
||||||
|
"text2": "快去竞拍吧",
|
||||||
|
"title": "个人中心",
|
||||||
|
"account": {
|
||||||
|
"title": "账户信息",
|
||||||
|
"avatar": "头像",
|
||||||
|
"nickname": "昵称",
|
||||||
|
"phone": "手机号",
|
||||||
|
"email": "邮箱",
|
||||||
|
"realName": "实名认证",
|
||||||
|
"verified": "已认证",
|
||||||
|
"unverified": "未认证",
|
||||||
|
"edit": "编辑"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"title": "我的订单",
|
||||||
|
"all": "全部",
|
||||||
|
"unpaid": "待付款",
|
||||||
|
"paid": "已付款",
|
||||||
|
"completed": "已完成",
|
||||||
|
"cancelled": "已取消"
|
||||||
|
},
|
||||||
|
"favorite": {
|
||||||
|
"title": "我的收藏",
|
||||||
|
"empty": "暂无收藏",
|
||||||
|
"delete": "删除",
|
||||||
|
"deleteConfirm": "确认删除选中的收藏?"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"title": "收货地址",
|
||||||
|
"add": "新增地址",
|
||||||
|
"edit": "编辑地址",
|
||||||
|
"delete": "删除地址",
|
||||||
|
"default": "默认地址",
|
||||||
|
"setDefault": "设为默认",
|
||||||
|
"name": "收货人",
|
||||||
|
"phone": "手机号码",
|
||||||
|
"region": "所在地区",
|
||||||
|
"detail": "详细地址",
|
||||||
|
"save": "保存",
|
||||||
|
"deleteConfirm": "确认删除该地址?"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "设置",
|
||||||
|
"notification": "消息通知",
|
||||||
|
"language": "语言",
|
||||||
|
"about": "关于我们",
|
||||||
|
"logout": "退出登录",
|
||||||
|
"logoutConfirm": "确认退出登录?"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error_page": {
|
"error_page": {
|
||||||
"back_btn": "返回",
|
"back_btn": "返回",
|
||||||
@ -47,6 +127,7 @@
|
|||||||
"frequentCountry": "常用"
|
"frequentCountry": "常用"
|
||||||
},
|
},
|
||||||
"realAuth": {
|
"realAuth": {
|
||||||
|
"phonePlaceholder": "请输入手机号",
|
||||||
"title": "实名认证",
|
"title": "实名认证",
|
||||||
"cnTab": "大陆居民",
|
"cnTab": "大陆居民",
|
||||||
"otherTab": "非大陆居民",
|
"otherTab": "非大陆居民",
|
||||||
@ -61,13 +142,521 @@
|
|||||||
"female": "女",
|
"female": "女",
|
||||||
"birthday": "出生日期",
|
"birthday": "出生日期",
|
||||||
"birthdayPlaceholder": "请输入出生日期",
|
"birthdayPlaceholder": "请输入出生日期",
|
||||||
"adress":"家庭住址",
|
"adress": "家庭住址",
|
||||||
"adressPlaceholder": "请输入家庭住址",
|
"adressPlaceholder": "请输入家庭住址",
|
||||||
"bank": "所属银行",
|
"bank": "所属银行",
|
||||||
"bankPlaceholder": "请选择所属银行",
|
"bankPlaceholder": "请选择所属银行",
|
||||||
"bankCard": "银行卡号码",
|
"bankCard": "银行卡号码",
|
||||||
"bankCardPlaceholder": "请输入银行卡号码",
|
"bankCardPlaceholder": "请输入银行卡号码",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"confirm": "确定"
|
"confirm": "确定",
|
||||||
|
"success_mess": "提交成功",
|
||||||
|
"text1": "请选择性别",
|
||||||
|
"detail": {
|
||||||
|
"gender": {
|
||||||
|
"male": "男",
|
||||||
|
"female": "女"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"detail": {
|
||||||
|
"text1": "作者",
|
||||||
|
"text2": "总平尺数",
|
||||||
|
"text3": "长",
|
||||||
|
"text4": "宽",
|
||||||
|
"text5": "画作简介",
|
||||||
|
"text6": "起拍价",
|
||||||
|
"text7": "竞价表",
|
||||||
|
"text8": "拍卖品详情"
|
||||||
|
},
|
||||||
|
"art_detail_page": {
|
||||||
|
"button": "去支付",
|
||||||
|
"prompt_title": "恭喜您",
|
||||||
|
"prompt_desc": "竞拍成功"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"tab1": "拍品列表",
|
||||||
|
"tab2": "拍卖说明",
|
||||||
|
"lot_detail": "拍品详情",
|
||||||
|
"refresh_show": "刷新成功",
|
||||||
|
"finished_text": "没有更多了",
|
||||||
|
"start_price": "起拍价",
|
||||||
|
"close_price": "成交价",
|
||||||
|
"my_lots": "我的拍品",
|
||||||
|
"go_home": "去首页",
|
||||||
|
"text1": "点击进入直播间",
|
||||||
|
"text2": "北京时间"
|
||||||
|
},
|
||||||
|
"live_room": {
|
||||||
|
"error_mess": "直播内容获取失败,是否重新获取",
|
||||||
|
"success_mess": "出价成功",
|
||||||
|
"warn_mess": "出价状态未开启",
|
||||||
|
"now_price": "当前价",
|
||||||
|
"lower_price": "下口价",
|
||||||
|
"confirm": "确认出价",
|
||||||
|
"button": "点击'开启出价',即刻参与竞拍",
|
||||||
|
"start": "开始拍卖",
|
||||||
|
"head":"领先",
|
||||||
|
"out": "出局",
|
||||||
|
"success": "成交",
|
||||||
|
"next_lot": "即将开始下一个拍品",
|
||||||
|
"spot": "现场竞价",
|
||||||
|
"network": "网络竞价",
|
||||||
|
"me": "我",
|
||||||
|
"all_pay": "支付全部",
|
||||||
|
"part_pay": "支付部分",
|
||||||
|
"lots": "拍品",
|
||||||
|
"colse_bid": "关闭出价",
|
||||||
|
"start_bid": "开启出价",
|
||||||
|
"total": "共",
|
||||||
|
"lots_num": "个拍品",
|
||||||
|
"cast": "投屏中",
|
||||||
|
"wait_update": "等待更新",
|
||||||
|
"text1": "即将落槌",
|
||||||
|
"text2": "已有人出价",
|
||||||
|
"text3": "更新后再出价",
|
||||||
|
"text4": "恭喜您,竞拍成功",
|
||||||
|
"text5": "请缴款",
|
||||||
|
"text6": "本拍品已结束",
|
||||||
|
"text7": "请期待下个拍品",
|
||||||
|
"text8": "很遗憾,竞拍失败",
|
||||||
|
"text9": "竞拍结束",
|
||||||
|
"text10": "竞拍结束,谢谢参与"
|
||||||
|
},
|
||||||
|
"personal": {
|
||||||
|
"title": "请填写个人相关信息",
|
||||||
|
"text":"文本",
|
||||||
|
"next": "下一步"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "支付",
|
||||||
|
"result": {
|
||||||
|
"title": "支付结果",
|
||||||
|
"success": "支付成功",
|
||||||
|
"fail": "支付失败",
|
||||||
|
"unpaid": "未支付",
|
||||||
|
"expired": "支付已过期",
|
||||||
|
"partial": "部分支付"
|
||||||
|
},
|
||||||
|
"text1": "支付结果",
|
||||||
|
"text2": "支付成功",
|
||||||
|
"text3": "支付失败",
|
||||||
|
"text4": "未支付",
|
||||||
|
"text5": "支付过期",
|
||||||
|
"text6": "部分支付",
|
||||||
|
"next": "下一步",
|
||||||
|
"backHome": "回到首页",
|
||||||
|
"confirm": "确认支付",
|
||||||
|
"fullPayment": "支付全部",
|
||||||
|
"partialPayment": "支付部分",
|
||||||
|
"loading": "加载中...",
|
||||||
|
"error": {
|
||||||
|
"enterAmount": "请输入金额",
|
||||||
|
"exceedTotal": "不得高于全部金额",
|
||||||
|
"invalidAmount": "请输入有效的支付金额",
|
||||||
|
"networkError": "网络错误,请重试",
|
||||||
|
"systemError": "系统错误,请稍后重试"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"amount": "最多{currency}{price}"
|
||||||
|
},
|
||||||
|
"amount": "支付金额"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"protocol": {
|
||||||
|
"loading": "加载中...",
|
||||||
|
"title": "签署内容",
|
||||||
|
"agree": "同意并签字",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirm": "确认",
|
||||||
|
"success": "签署成功",
|
||||||
|
"fail": "签署失败",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"agreeAndSign": "同意并签署"
|
||||||
|
},
|
||||||
|
"loading": "加载中...",
|
||||||
|
"agreement": {
|
||||||
|
"notice": "《拍卖公告》",
|
||||||
|
"rules": "《拍卖规则》",
|
||||||
|
"buyerGuide": "《竞买须知》",
|
||||||
|
"buyerAgreement": "《竞买协议》",
|
||||||
|
"record": "《拍卖笔录成交确认书》",
|
||||||
|
"transfer": "《拍卖移交确认书》"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"getRecord": "获取拍卖笔录失败"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"agree": "同意并签字",
|
||||||
|
"back": "返回",
|
||||||
|
"clear": "清空",
|
||||||
|
"confirm": "确认"
|
||||||
|
},
|
||||||
|
"tips": {
|
||||||
|
"landscape": "请将手机横屏使用",
|
||||||
|
"needSign": "请先签名",
|
||||||
|
"prePayment": "支付前需同意以下内容并签字"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"liveRoom": {
|
||||||
|
"loading": "直播加载中...",
|
||||||
|
"error": {
|
||||||
|
"player": "播放器错误:",
|
||||||
|
"init": "播放器初始化失败:",
|
||||||
|
"noVideo": "未找到视频元素",
|
||||||
|
"screenshot": "获取视频截图失败:"
|
||||||
|
},
|
||||||
|
"player": {
|
||||||
|
"autoplay": true,
|
||||||
|
"muted": true,
|
||||||
|
"width": "100%",
|
||||||
|
"height": "100%"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error_mess": "直播内容获取失败,是否重新获取",
|
||||||
|
"success_mess": "出价成功",
|
||||||
|
"warn_mess": "出价状态未开启",
|
||||||
|
"now_price": "当前价",
|
||||||
|
"lower_price": "下口价",
|
||||||
|
"confirm": "确认出价",
|
||||||
|
"button": "点击'开启出价',即刻参与竞拍",
|
||||||
|
"start": "开始拍卖",
|
||||||
|
"head": "领先",
|
||||||
|
"out": "出局",
|
||||||
|
"success": "成交",
|
||||||
|
"next_lot": "即将开始下一个拍品",
|
||||||
|
"spot": "现场竞价",
|
||||||
|
"network": "网络竞价",
|
||||||
|
"me": "我",
|
||||||
|
"all_pay": "支付全部",
|
||||||
|
"part_pay": "支付部分",
|
||||||
|
"lots": "拍品",
|
||||||
|
"colse_bid": "关闭出价",
|
||||||
|
"start_bid": "开启出价",
|
||||||
|
"total": "共",
|
||||||
|
"lots_num": "个拍品",
|
||||||
|
"cast": "投屏中",
|
||||||
|
"wait_update": "等待更新",
|
||||||
|
"text1": "即将落槌",
|
||||||
|
"text2": "已有人出价",
|
||||||
|
"text3": "更新后再出价",
|
||||||
|
"text4": "恭喜您,竞拍成功",
|
||||||
|
"text5": "请缴款",
|
||||||
|
"text6": "本拍品已结束",
|
||||||
|
"text7": "请期待下个拍品",
|
||||||
|
"text8": "很遗憾,竞拍失败",
|
||||||
|
"text9": "竞拍结束",
|
||||||
|
"text10": "竞拍结束,谢谢参与"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacyPolicy": {
|
||||||
|
"title": "隐私政策",
|
||||||
|
"content": {
|
||||||
|
"header": "请仔细阅读《丰和隐私政策》(尤其是加粗的内容)并确定了解我们对您个人信息的处理规则。阅读过程中,如您有任何疑问,可联系我们的客服咨询,如您不同意协议中的任何条款,您应立即停止访问。",
|
||||||
|
"version": "版本更新日期:2025 年 2 月 6 日",
|
||||||
|
"scope": "丰和隐私政策适用于上海丰和拍卖有限公司旗下的网络竞拍、购物等产品或服务,包括但不限于在线拍卖直播、在线竞拍、国内代拍、海外代拍、限时竞拍、我要送拍、全球艺购、藏宝传家等网站、客户端、小程序以及随技术发展出现的新形态向您提供的各项产品与/或服务。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectCode": {
|
||||||
|
"login": {
|
||||||
|
"title": "收藏码登录",
|
||||||
|
"phoneNumber": "手机号",
|
||||||
|
"phoneNumberPlaceholder": "请输入手机号",
|
||||||
|
"password": "密码",
|
||||||
|
"passwordPlaceholder": "请输入密码",
|
||||||
|
"passwordLogin": "密码登录",
|
||||||
|
"codeLogin": "验证码登录",
|
||||||
|
"getCode": "获取验证码",
|
||||||
|
"login": "登录",
|
||||||
|
"hasSendTo": "已发送至",
|
||||||
|
"reSend": "重新发送",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"mine": {
|
||||||
|
"title": "个人中心",
|
||||||
|
"logout": "退出登录",
|
||||||
|
"offlineQrcode": "线下付款二维码",
|
||||||
|
"refreshSuccess": "刷新成功",
|
||||||
|
"noMore": "没有更多了",
|
||||||
|
"add": "新增",
|
||||||
|
"addQrcode": {
|
||||||
|
"title": "新增收款二维码",
|
||||||
|
"amount": "金额",
|
||||||
|
"amountUnit": "RMB",
|
||||||
|
"amountPlaceholder": "请输入金额",
|
||||||
|
"lotNo": "Lot号",
|
||||||
|
"lotNoPlaceholder": "请输入拍品序号",
|
||||||
|
"existingWarning": "该拍品号当前已存在收款二维码,确定要创建吗?",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirm": "确定"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qrcode": {
|
||||||
|
"status": {
|
||||||
|
"paid": "已付款",
|
||||||
|
"unpaid": "未付款",
|
||||||
|
"partialPaid": "已部分付款"
|
||||||
|
},
|
||||||
|
"card": {
|
||||||
|
"lotNo": "Lot:",
|
||||||
|
"creator": "创建人:",
|
||||||
|
"createTime": "创建时间:",
|
||||||
|
"view": "查看"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "支付",
|
||||||
|
"fullPayment": "支付全部",
|
||||||
|
"partialPayment": "支付部分",
|
||||||
|
"confirmPayment": "确认支付",
|
||||||
|
"maxAmount": "最多{currency}{price}",
|
||||||
|
"enterAmount": "请输入金额",
|
||||||
|
"exceedTotal": "不得高于全部金额"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"title": "签署",
|
||||||
|
"back": "返回",
|
||||||
|
"clear": "清空",
|
||||||
|
"confirm": "确认",
|
||||||
|
"pleaseSign": "请先签名",
|
||||||
|
"loading": "加载中..."
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"amountRequired": "请输入金额",
|
||||||
|
"lotNoRequired": "请输入Lot号",
|
||||||
|
"deleteSuccess": "删除成功"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"required": "此项为必填项",
|
||||||
|
"invalidFormat": "格式不正确",
|
||||||
|
"invalidPhone": "请输入有效的手机号",
|
||||||
|
"invalidEmail": "请输入有效的邮箱地址",
|
||||||
|
"invalidPassword": "密码格式不正确",
|
||||||
|
"invalidCode": "验证码格式不正确",
|
||||||
|
"invalidAmount": "请输入有效的金额",
|
||||||
|
"invalidNumber": "请输入有效的数字"
|
||||||
|
},
|
||||||
|
"realName": {
|
||||||
|
"title": "实名认证",
|
||||||
|
"cnTab": "中国大陆居民",
|
||||||
|
"otherTab": "非中国大陆居民",
|
||||||
|
"cnTabDesc": "请填写身份证信息",
|
||||||
|
"otherTabDesc": "请上传个人信息",
|
||||||
|
"idCard": "身份证号",
|
||||||
|
"idCardPlaceholder": "请输入身份证号",
|
||||||
|
"name": "姓名",
|
||||||
|
"namePlaceholder": "请输入姓名",
|
||||||
|
"gender": "性别",
|
||||||
|
"male": "男",
|
||||||
|
"female": "女",
|
||||||
|
"birthday": "出生日期",
|
||||||
|
"birthdayPlaceholder": "请选择出生日期",
|
||||||
|
"address": "家庭住址",
|
||||||
|
"addressPlaceholder": "请输入家庭住址",
|
||||||
|
"bank": "开户银行",
|
||||||
|
"bankPlaceholder": "请选择开户银行",
|
||||||
|
"bankCard": "银行卡号",
|
||||||
|
"bankCardPlaceholder": "请输入银行卡号",
|
||||||
|
"confirm": "确认",
|
||||||
|
"success": "提交成功",
|
||||||
|
"selectGender": "请选择性别"
|
||||||
|
},
|
||||||
|
"auction": {
|
||||||
|
"title": "拍品详情",
|
||||||
|
"area": "总平方尺",
|
||||||
|
"length": "长",
|
||||||
|
"width": "宽",
|
||||||
|
"description": "作品介绍",
|
||||||
|
"startPrice": "起拍价",
|
||||||
|
"bidList": "竞拍记录",
|
||||||
|
"detail": "拍品详情",
|
||||||
|
"tab": {
|
||||||
|
"detail": "拍品详情",
|
||||||
|
"description": "拍品说明"
|
||||||
|
},
|
||||||
|
"lotDetail": "LOT详情",
|
||||||
|
"refresh": {
|
||||||
|
"success": "刷新成功",
|
||||||
|
"noMore": "没有更多了"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"start": "起拍价",
|
||||||
|
"current": "当前价",
|
||||||
|
"hammer": "成交价"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"live": {
|
||||||
|
"enterRoom": "点击进入直播间",
|
||||||
|
"beijingTime": "北京时间",
|
||||||
|
"status": {
|
||||||
|
"notStarted": "未开始",
|
||||||
|
"live": "直播中",
|
||||||
|
"ended": "已结束"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"networkError": "网络异常,请检查网络连接",
|
||||||
|
"reconnecting": "正在重连...",
|
||||||
|
"reconnectSuccess": "重连成功",
|
||||||
|
"reconnectFail": "重连失败,请刷新页面"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"title": "国家和地区",
|
||||||
|
"searchPlaceholder": "请输入国家或地区",
|
||||||
|
"frequentCountry": "常用"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"name": "丰和",
|
||||||
|
"description": "丰和国际京都拍卖",
|
||||||
|
"keywords": "丰和,丰和文化,FENGHE,京都,拍卖",
|
||||||
|
"language": "📚 语言",
|
||||||
|
"unocssExample": "🎨 Unocss示例",
|
||||||
|
"loading": "加载中...",
|
||||||
|
"error": {
|
||||||
|
"404": {
|
||||||
|
"title": "页面不存在",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"network": "网络错误",
|
||||||
|
"server": "服务器错误"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bid": {
|
||||||
|
"title": "竞拍",
|
||||||
|
"noBids": "暂无竞拍商品",
|
||||||
|
"bidNow": "立即竞拍",
|
||||||
|
"success": "竞拍成功",
|
||||||
|
"fail": "竞拍失败",
|
||||||
|
"confirm": "确认出价",
|
||||||
|
"cancel": "取消",
|
||||||
|
"amount": "出价金额",
|
||||||
|
"currentPrice": "当前价",
|
||||||
|
"nextPrice": "下一口价",
|
||||||
|
"bidHistory": "竞价记录",
|
||||||
|
"bidder": "竞买人",
|
||||||
|
"bidTime": "竞价时间",
|
||||||
|
"bidAmount": "竞价金额",
|
||||||
|
"status": {
|
||||||
|
"bidding": "竞价中",
|
||||||
|
"ended": "已结束",
|
||||||
|
"upcoming": "即将开始",
|
||||||
|
"cancelled": "已取消"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"confirmBid": "确认出价 {amount} 元?",
|
||||||
|
"bidSuccess": "出价成功",
|
||||||
|
"bidFail": "出价失败",
|
||||||
|
"priceChanged": "价格已更新,请重新出价",
|
||||||
|
"insufficientBalance": "余额不足",
|
||||||
|
"notQualified": "您暂未获得竞买资格",
|
||||||
|
"auctionEnded": "拍卖已结束",
|
||||||
|
"auctionNotStarted": "拍卖未开始"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "设置",
|
||||||
|
"language": "语言",
|
||||||
|
"notification": "消息通知",
|
||||||
|
"about": "关于我们",
|
||||||
|
"feedback": "意见反馈",
|
||||||
|
"privacy": "隐私政策",
|
||||||
|
"terms": "服务条款",
|
||||||
|
"version": "版本信息",
|
||||||
|
"logout": "退出登录",
|
||||||
|
"darkMode": "深色模式",
|
||||||
|
"auto": "跟随系统",
|
||||||
|
"light": "浅色",
|
||||||
|
"dark": "深色"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"default": {
|
||||||
|
"title": "丰和拍卖",
|
||||||
|
"loading": "加载中...",
|
||||||
|
"error": "出错了",
|
||||||
|
"retry": "重试",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"notFound": "页面不存在",
|
||||||
|
"back": "返回首页",
|
||||||
|
"retry": "重试"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"loading": {
|
||||||
|
"text": "加载中..."
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"text": "暂无数据",
|
||||||
|
"description": "没有找到相关内容"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"text": "出错了",
|
||||||
|
"description": "加载失败,请重试",
|
||||||
|
"button": "重试"
|
||||||
|
},
|
||||||
|
"navbar": {
|
||||||
|
"back": "返回",
|
||||||
|
"close": "关闭",
|
||||||
|
"home": "首页"
|
||||||
|
},
|
||||||
|
"tabbar": {
|
||||||
|
"home": "首页",
|
||||||
|
"auction": "拍卖",
|
||||||
|
"live": "直播",
|
||||||
|
"profile": "我的"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"close": "关闭"
|
||||||
|
},
|
||||||
|
"toast": {
|
||||||
|
"success": "操作成功",
|
||||||
|
"fail": "操作失败",
|
||||||
|
"loading": "加载中..."
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"required": "必填",
|
||||||
|
"optional": "选填",
|
||||||
|
"save": "保存",
|
||||||
|
"submit": "提交",
|
||||||
|
"cancel": "取消",
|
||||||
|
"pleaseInput": "请输入",
|
||||||
|
"pleaseSelect": "请选择"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"text": "点击上传",
|
||||||
|
"delete": "删除",
|
||||||
|
"preview": "预览",
|
||||||
|
"maxSize": "文件大小不能超过 {size}",
|
||||||
|
"format": "支持的文件格式:{formats}",
|
||||||
|
"uploading": "上传中...",
|
||||||
|
"uploadSuccess": "上传成功",
|
||||||
|
"uploadFail": "上传失败"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"floatingBubble": {
|
||||||
|
"backToLive": "回到直播"
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"error": {
|
||||||
|
"badRequest": "请求参数错误",
|
||||||
|
"unauthorized": "未授权或登录过期",
|
||||||
|
"forbidden": "访问被禁止",
|
||||||
|
"notFound": "请求的资源不存在",
|
||||||
|
"serverError": "服务器内部错误",
|
||||||
|
"badGateway": "网关错误",
|
||||||
|
"serviceUnavailable": "服务暂时不可用",
|
||||||
|
"gatewayTimeout": "网关超时",
|
||||||
|
"operationFailed": "操作失败",
|
||||||
|
"loginExpired": "登录已过期,请重新登录",
|
||||||
|
"networkError": "网络连接失败,请检查网络设置",
|
||||||
|
"requestFailed": "请求失败",
|
||||||
|
"httpNotInitialized": "HTTP客户端未初始化,请先调用setupHttp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,28 +5,163 @@
|
|||||||
"appKeyWords": "泰豐,泰豐文化,豐和,京都,拍賣會"
|
"appKeyWords": "泰豐,泰豐文化,豐和,京都,拍賣會"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"home": "首頁",
|
"home": "京都拍賣會",
|
||||||
"profile": "我的",
|
"profile": "我的",
|
||||||
"darkMode": "🌗 暗黑模式",
|
"darkMode": "🌗 暗黑模式",
|
||||||
"language": "📚 語言",
|
"language": "📚 語言",
|
||||||
"404Demo": "🙅 404頁面 演示",
|
"404Demo": "🙅 404頁 演示",
|
||||||
"unocssExample": "🎨 Unocss 示例",
|
"unocssExample": "🎨 Unocss 示例",
|
||||||
"keepAlive": "🧡 KeepAlive 演示",
|
"keepAlive": "🧡 KeepAlive 演示",
|
||||||
"persistPiniaState": "💾 持久化 Pinia 狀態",
|
"persistPiniaState": "💾 持久化 Pinia 狀態",
|
||||||
"fetch": "🏄 網路請求"
|
"fetch": "🏄 網絡請求",
|
||||||
|
"auction": "拍賣",
|
||||||
|
"live": "直播",
|
||||||
|
"settings": "設置"
|
||||||
},
|
},
|
||||||
"tabbar": {
|
"tabbar": {
|
||||||
"home": "首頁",
|
"home": "主頁",
|
||||||
"profile": "我的"
|
"profile": "我的"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"title": "登入",
|
"title": "登錄",
|
||||||
"phonePlaceholder": "請輸入手機號",
|
"phonePlaceholder": "請輸入手機號",
|
||||||
"getCode": "獲取驗證碼",
|
"getCode": "獲取驗證碼",
|
||||||
"login": "登入",
|
"login": "登錄",
|
||||||
"back": "返回",
|
"back": "返回",
|
||||||
"hasSendTo": "已發送驗證碼至",
|
"hasSendTo": "已發送驗證碼至",
|
||||||
"reSend": "重新發送"
|
"reSend": "重新發送",
|
||||||
|
"agreement": "登錄即同意",
|
||||||
|
"privacyPolicy": "《隱私政策》"
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"items": "件",
|
||||||
|
"auction": "拍品",
|
||||||
|
"loading": "加載中...",
|
||||||
|
"networkError": "網絡錯誤,請重試",
|
||||||
|
"systemError": "系統錯誤,請稍後重試",
|
||||||
|
"success": "操作成功",
|
||||||
|
"fail": "操作失敗",
|
||||||
|
"confirm": "確認",
|
||||||
|
"cancel": "取消",
|
||||||
|
"back": "返回",
|
||||||
|
"next": "下一步",
|
||||||
|
"save": "保存",
|
||||||
|
"edit": "編輯",
|
||||||
|
"delete": "刪除",
|
||||||
|
"view": "查看",
|
||||||
|
"close": "關閉",
|
||||||
|
"refresh": "刷新",
|
||||||
|
"noData": "暫無數據",
|
||||||
|
"loadMore": "加載更多",
|
||||||
|
"noMore": "沒有更多了",
|
||||||
|
"refreshSuccess": "刷新成功",
|
||||||
|
"pleaseInput": "請輸入",
|
||||||
|
"pleaseSelect": "請選擇"
|
||||||
|
},
|
||||||
|
"liveRoom": {
|
||||||
|
"loading": "直播加載中...",
|
||||||
|
"error": {
|
||||||
|
"player": "播放器錯誤:",
|
||||||
|
"init": "播放器初始化失敗:",
|
||||||
|
"noVideo": "未找到視頻元素",
|
||||||
|
"screenshot": "獲取視頻截圖失敗:"
|
||||||
|
},
|
||||||
|
"player": {
|
||||||
|
"autoplay": true,
|
||||||
|
"muted": true,
|
||||||
|
"width": "100%",
|
||||||
|
"height": "100%"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"error_mess": "直播內容獲取失敗,是否重新獲取",
|
||||||
|
"success_mess": "出價成功",
|
||||||
|
"warn_mess": "出價狀態未開啟",
|
||||||
|
"now_price": "當前價",
|
||||||
|
"lower_price": "下口價",
|
||||||
|
"confirm": "確認出價",
|
||||||
|
"button": "點擊'開啟出價',即刻參與競拍",
|
||||||
|
"start": "開始拍賣",
|
||||||
|
"head": "領先",
|
||||||
|
"out": "出局",
|
||||||
|
"success": "成交",
|
||||||
|
"next_lot": "即將開始下一個拍品",
|
||||||
|
"spot": "現場競價",
|
||||||
|
"network": "網絡競價",
|
||||||
|
"me": "我",
|
||||||
|
"all_pay": "支付全部",
|
||||||
|
"part_pay": "支付部分",
|
||||||
|
"lots": "拍品",
|
||||||
|
"colse_bid": "關閉出價",
|
||||||
|
"start_bid": "開啟出價",
|
||||||
|
"total": "共",
|
||||||
|
"lots_num": "個拍品",
|
||||||
|
"cast": "投屏中",
|
||||||
|
"wait_update": "等待更新",
|
||||||
|
"text1": "即將落槌",
|
||||||
|
"text2": "已有人出價",
|
||||||
|
"text3": "更新後再出價",
|
||||||
|
"text4": "恭喜您,競拍成功",
|
||||||
|
"text5": "請繳款",
|
||||||
|
"text6": "本拍品已結束",
|
||||||
|
"text7": "請期待下個拍品",
|
||||||
|
"text8": "很遺憾,競拍失敗",
|
||||||
|
"text9": "競拍結束",
|
||||||
|
"text10": "競拍結束,謝謝參與"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"name": "姓名",
|
||||||
|
"phone": "手機號",
|
||||||
|
"text1": "您暫無拍品",
|
||||||
|
"text2": "快去競拍吧",
|
||||||
|
"title": "個人中心",
|
||||||
|
"account": {
|
||||||
|
"title": "賬戶信息",
|
||||||
|
"avatar": "頭像",
|
||||||
|
"nickname": "暱稱",
|
||||||
|
"phone": "手機號",
|
||||||
|
"email": "郵箱",
|
||||||
|
"realName": "實名認證",
|
||||||
|
"verified": "已認證",
|
||||||
|
"unverified": "未認證",
|
||||||
|
"edit": "編輯"
|
||||||
|
},
|
||||||
|
"order": {
|
||||||
|
"title": "我的訂單",
|
||||||
|
"all": "全部",
|
||||||
|
"unpaid": "待付款",
|
||||||
|
"paid": "已付款",
|
||||||
|
"completed": "已完成",
|
||||||
|
"cancelled": "已取消"
|
||||||
|
},
|
||||||
|
"favorite": {
|
||||||
|
"title": "我的收藏",
|
||||||
|
"empty": "暫無收藏",
|
||||||
|
"delete": "刪除",
|
||||||
|
"deleteConfirm": "確認刪除選中的收藏?"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"title": "收貨地址",
|
||||||
|
"add": "新增地址",
|
||||||
|
"edit": "編輯地址",
|
||||||
|
"delete": "刪除地址",
|
||||||
|
"default": "默認地址",
|
||||||
|
"setDefault": "設為默認",
|
||||||
|
"name": "收貨人",
|
||||||
|
"phone": "手機號碼",
|
||||||
|
"region": "所在地區",
|
||||||
|
"detail": "詳細地址",
|
||||||
|
"save": "保存",
|
||||||
|
"deleteConfirm": "確認刪除該地址?"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "設置",
|
||||||
|
"notification": "消息通知",
|
||||||
|
"language": "語言",
|
||||||
|
"about": "關於我們",
|
||||||
|
"logout": "退出登錄",
|
||||||
|
"logoutConfirm": "確認退出登錄?"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"error_page": {
|
"error_page": {
|
||||||
"back_btn": "返回",
|
"back_btn": "返回",
|
||||||
@ -43,7 +178,8 @@
|
|||||||
"frequentCountry": "常用"
|
"frequentCountry": "常用"
|
||||||
},
|
},
|
||||||
"realAuth": {
|
"realAuth": {
|
||||||
"title": "實名認證 ",
|
"phonePlaceholder": "請輸入手機號",
|
||||||
|
"title": "實名認證",
|
||||||
"cnTab": "大陸居民",
|
"cnTab": "大陸居民",
|
||||||
"otherTab": "非大陸居民",
|
"otherTab": "非大陸居民",
|
||||||
"cnTabDesc": "請填寫身份證相關信息",
|
"cnTabDesc": "請填寫身份證相關信息",
|
||||||
@ -57,14 +193,471 @@
|
|||||||
"female": "女",
|
"female": "女",
|
||||||
"birthday": "出生日期",
|
"birthday": "出生日期",
|
||||||
"birthdayPlaceholder": "請輸入出生日期",
|
"birthdayPlaceholder": "請輸入出生日期",
|
||||||
"adress":"家庭住址",
|
"adress": "家庭住址",
|
||||||
"adressPlaceholder": "請輸入家庭住址",
|
"adressPlaceholder": "請輸入家庭住址",
|
||||||
"bank": "所屬銀行",
|
"bank": "所屬銀行",
|
||||||
"bankPlaceholder": "請選擇所屬銀行",
|
"bankPlaceholder": "請選擇所屬銀行",
|
||||||
"bankCard": "銀行卡號碼",
|
"bankCard": "銀行卡號碼",
|
||||||
"bankCardPlaceholder": "請輸入銀行卡號碼",
|
"bankCardPlaceholder": "請輸入銀行卡號碼",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"confirm": "確定"
|
"confirm": "確定",
|
||||||
|
"success_mess": "提交成功",
|
||||||
|
"text1": "請選擇性別",
|
||||||
|
"detail": {
|
||||||
|
"gender": {
|
||||||
|
"male": "男",
|
||||||
|
"female": "女"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"detail": {
|
||||||
|
"text1": "作者",
|
||||||
|
"text2": "總平尺數",
|
||||||
|
"text3": "長",
|
||||||
|
"text4": "寬",
|
||||||
|
"text5": "畫作簡介",
|
||||||
|
"text6": "起拍價",
|
||||||
|
"text7": "競價表",
|
||||||
|
"text8": "拍賣品詳情"
|
||||||
|
},
|
||||||
|
"art_detail_page": {
|
||||||
|
"button": "去支付",
|
||||||
|
"prompt_title": "恭喜您",
|
||||||
|
"prompt_desc": "競拍成功"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"tab1": "拍品列表",
|
||||||
|
"tab2": "拍賣說明",
|
||||||
|
"lot_detail": "拍品詳情",
|
||||||
|
"refresh_show": "刷新成功",
|
||||||
|
"finished_text": "沒有更多了",
|
||||||
|
"start_price": "起拍價",
|
||||||
|
"close_price": "成交價",
|
||||||
|
"my_lots": "我的拍品",
|
||||||
|
"go_home": "去首頁",
|
||||||
|
"text1": "點擊進入直播間",
|
||||||
|
"text2": "北京時間"
|
||||||
|
},
|
||||||
|
"live_room": {
|
||||||
|
"error_mess": "直播內容獲取失敗,是否重新獲取",
|
||||||
|
"success_mess": "出價成功",
|
||||||
|
"warn_mess": "出價狀態未開啟",
|
||||||
|
"now_price": "當前價",
|
||||||
|
"lower_price": "下口價",
|
||||||
|
"confirm": "確認出價",
|
||||||
|
"button": "點擊'開啟出價',即刻參與競拍",
|
||||||
|
"start": "開始拍賣",
|
||||||
|
"head": "領先",
|
||||||
|
"out": "出局",
|
||||||
|
"success": "成交",
|
||||||
|
"next_lot": "即將開始下一個拍品",
|
||||||
|
"spot": "現場競價",
|
||||||
|
"network": "網絡競價",
|
||||||
|
"me": "我",
|
||||||
|
"all_pay": "支付全部",
|
||||||
|
"part_pay": "支付部分",
|
||||||
|
"lots": "拍品",
|
||||||
|
"colse_bid": "關閉出價",
|
||||||
|
"start_bid": "開啟出價",
|
||||||
|
"total": "共",
|
||||||
|
"lots_num": "個拍品",
|
||||||
|
"cast": "投屏中",
|
||||||
|
"wait_update": "等待更新",
|
||||||
|
"text1": "即將落槌",
|
||||||
|
"text2": "已有人出價",
|
||||||
|
"text3": "更新後再出價",
|
||||||
|
"text4": "恭喜您,競拍成功",
|
||||||
|
"text5": "請繳款",
|
||||||
|
"text6": "本拍品已結束",
|
||||||
|
"text7": "請期待下個拍品",
|
||||||
|
"text8": "很遺憾,競拍失敗",
|
||||||
|
"text9": "競拍結束",
|
||||||
|
"text10": "競拍結束,謝謝參與"
|
||||||
|
},
|
||||||
|
"personal": {
|
||||||
|
"title": "請填寫個人相關信息",
|
||||||
|
"text": "文本",
|
||||||
|
"next": "下一步"
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "支付",
|
||||||
|
"result": {
|
||||||
|
"title": "支付結果",
|
||||||
|
"success": "支付成功",
|
||||||
|
"fail": "支付失敗",
|
||||||
|
"unpaid": "未支付",
|
||||||
|
"expired": "支付已過期",
|
||||||
|
"partial": "部分支付"
|
||||||
|
},
|
||||||
|
"text1": "支付結果",
|
||||||
|
"text2": "支付成功",
|
||||||
|
"text3": "支付失敗",
|
||||||
|
"text4": "未支付",
|
||||||
|
"text5": "支付過期",
|
||||||
|
"text6": "部分支付",
|
||||||
|
"next": "下一步",
|
||||||
|
"backHome": "回到首頁",
|
||||||
|
"confirm": "確認支付",
|
||||||
|
"fullPayment": "支付全部",
|
||||||
|
"partialPayment": "支付部分",
|
||||||
|
"loading": "加載中...",
|
||||||
|
"error": {
|
||||||
|
"enterAmount": "請輸入金額",
|
||||||
|
"exceedTotal": "不得高於全部金額",
|
||||||
|
"invalidAmount": "請輸入有效的支付金額",
|
||||||
|
"networkError": "網絡錯誤,請重試",
|
||||||
|
"systemError": "系統錯誤,請稍後重試"
|
||||||
|
},
|
||||||
|
"placeholder": {
|
||||||
|
"amount": "最多{currency}{price}"
|
||||||
|
},
|
||||||
|
"amount": "支付金額"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"protocol": {
|
||||||
|
"loading": "加載中...",
|
||||||
|
"title": "簽署內容",
|
||||||
|
"agree": "同意並簽字",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirm": "確認",
|
||||||
|
"success": "簽署成功",
|
||||||
|
"fail": "簽署失敗",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"agreeAndSign": "同意並簽署"
|
||||||
|
},
|
||||||
|
"loading": "加載中...",
|
||||||
|
"agreement": {
|
||||||
|
"notice": "《拍賣公告》",
|
||||||
|
"rules": "《拍賣規則》",
|
||||||
|
"buyerGuide": "《競買須知》",
|
||||||
|
"buyerAgreement": "《競買協議》",
|
||||||
|
"record": "《拍賣筆錄成交確認書》",
|
||||||
|
"transfer": "《拍賣移交確認書》"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"getRecord": "獲取拍賣筆錄失敗"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"agree": "同意並簽字",
|
||||||
|
"back": "返回",
|
||||||
|
"clear": "清空",
|
||||||
|
"confirm": "確認"
|
||||||
|
},
|
||||||
|
"tips": {
|
||||||
|
"landscape": "請將手機橫屏使用",
|
||||||
|
"needSign": "請先簽名",
|
||||||
|
"prePayment": "支付前需同意以下內容並簽字"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacyPolicy": {
|
||||||
|
"title": "隱私政策",
|
||||||
|
"content": {
|
||||||
|
"header": "請仔細閱讀《豐和隱私政策》(尤其是加粗的內容)並確定了解我們對您個人信息的處理規則。閱讀過程中,如您有任何疑問,可聯繫我們的客服諮詢,如您不同意協議中的任何條款,您應立即停止訪問。",
|
||||||
|
"version": "版本更新日期:2025 年 2 月 6 日",
|
||||||
|
"scope": "豐和隱私政策適用於上海豐和拍賣有限公司旗下的網絡競拍、購物等產品或服務,包括但不限於在線拍賣直播、在線競拍、國內代拍、海外代拍、限時競拍、我要送拍、全球藝購、藏寶傳家等網站、客戶端、小程序以及隨技術發展出現的新形態向您提供的各項產品與/或服務。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"collectCode": {
|
||||||
|
"login": {
|
||||||
|
"title": "收藏碼登錄",
|
||||||
|
"phoneNumber": "手機號",
|
||||||
|
"phoneNumberPlaceholder": "請輸入手機號",
|
||||||
|
"password": "密碼",
|
||||||
|
"passwordPlaceholder": "請輸入密碼",
|
||||||
|
"passwordLogin": "密碼登錄",
|
||||||
|
"codeLogin": "驗證碼登錄",
|
||||||
|
"getCode": "獲取驗證碼",
|
||||||
|
"login": "登錄",
|
||||||
|
"hasSendTo": "已發送至",
|
||||||
|
"reSend": "重新發送",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"mine": {
|
||||||
|
"title": "個人中心",
|
||||||
|
"logout": "退出登錄",
|
||||||
|
"offlineQrcode": "線下付款二維碼",
|
||||||
|
"refreshSuccess": "刷新成功",
|
||||||
|
"noMore": "沒有更多了",
|
||||||
|
"add": "新增",
|
||||||
|
"addQrcode": {
|
||||||
|
"title": "新增收款二維碼",
|
||||||
|
"amount": "金額",
|
||||||
|
"amountUnit": "RMB",
|
||||||
|
"amountPlaceholder": "請輸入金額",
|
||||||
|
"lotNo": "Lot號",
|
||||||
|
"lotNoPlaceholder": "請輸入拍品序號",
|
||||||
|
"existingWarning": "該拍品號當前已存在收款二維碼,確定要創建嗎?",
|
||||||
|
"cancel": "取消",
|
||||||
|
"confirm": "確定"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"qrcode": {
|
||||||
|
"status": {
|
||||||
|
"paid": "已付款",
|
||||||
|
"unpaid": "未付款",
|
||||||
|
"partialPaid": "已部分付款"
|
||||||
|
},
|
||||||
|
"card": {
|
||||||
|
"lotNo": "Lot:",
|
||||||
|
"creator": "創建人:",
|
||||||
|
"createTime": "創建時間:",
|
||||||
|
"view": "查看"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"payment": {
|
||||||
|
"title": "支付",
|
||||||
|
"fullPayment": "支付全部",
|
||||||
|
"partialPayment": "支付部分",
|
||||||
|
"confirmPayment": "確認支付",
|
||||||
|
"maxAmount": "最多{currency}{price}",
|
||||||
|
"enterAmount": "請輸入金額",
|
||||||
|
"exceedTotal": "不得高於全部金額"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"title": "簽署",
|
||||||
|
"back": "返回",
|
||||||
|
"clear": "清空",
|
||||||
|
"confirm": "確認",
|
||||||
|
"pleaseSign": "請先簽名",
|
||||||
|
"loading": "加載中..."
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"amountRequired": "請輸入金額",
|
||||||
|
"lotNoRequired": "請輸入Lot號",
|
||||||
|
"deleteSuccess": "刪除成功"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validation": {
|
||||||
|
"required": "此項為必填項",
|
||||||
|
"invalidFormat": "格式不正確",
|
||||||
|
"invalidPhone": "請輸入有效的手機號",
|
||||||
|
"invalidEmail": "請輸入有效的郵箱地址",
|
||||||
|
"invalidPassword": "密碼格式不正確",
|
||||||
|
"invalidCode": "驗證碼格式不正確",
|
||||||
|
"invalidAmount": "請輸入有效的金額",
|
||||||
|
"invalidNumber": "請輸入有效的數字"
|
||||||
|
},
|
||||||
|
"realName": {
|
||||||
|
"title": "實名認證",
|
||||||
|
"cnTab": "中國大陸居民",
|
||||||
|
"otherTab": "非中國大陸居民",
|
||||||
|
"cnTabDesc": "請填寫身份證信息",
|
||||||
|
"otherTabDesc": "請上傳個人信息",
|
||||||
|
"idCard": "身份證號",
|
||||||
|
"idCardPlaceholder": "請輸入身份證號",
|
||||||
|
"name": "姓名",
|
||||||
|
"namePlaceholder": "請輸入姓名",
|
||||||
|
"gender": "性別",
|
||||||
|
"male": "男",
|
||||||
|
"female": "女",
|
||||||
|
"birthday": "出生日期",
|
||||||
|
"birthdayPlaceholder": "請選擇出生日期",
|
||||||
|
"address": "家庭住址",
|
||||||
|
"addressPlaceholder": "請輸入家庭住址",
|
||||||
|
"bank": "開戶銀行",
|
||||||
|
"bankPlaceholder": "請選擇開戶銀行",
|
||||||
|
"bankCard": "銀行卡號",
|
||||||
|
"bankCardPlaceholder": "請輸入銀行卡號",
|
||||||
|
"confirm": "確認",
|
||||||
|
"success": "提交成功",
|
||||||
|
"selectGender": "請選擇性別"
|
||||||
|
},
|
||||||
|
"auction": {
|
||||||
|
"title": "拍品詳情",
|
||||||
|
"area": "總平方尺",
|
||||||
|
"length": "長",
|
||||||
|
"width": "寬",
|
||||||
|
"description": "作品介紹",
|
||||||
|
"startPrice": "起拍價",
|
||||||
|
"bidList": "競拍記錄",
|
||||||
|
"detail": "拍品詳情",
|
||||||
|
"tab": {
|
||||||
|
"detail": "拍品詳情",
|
||||||
|
"description": "拍品說明"
|
||||||
|
},
|
||||||
|
"lotDetail": "LOT詳情",
|
||||||
|
"refresh": {
|
||||||
|
"success": "刷新成功",
|
||||||
|
"noMore": "沒有更多了"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"start": "起拍價",
|
||||||
|
"current": "當前價",
|
||||||
|
"hammer": "成交價"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"live": {
|
||||||
|
"enterRoom": "點擊進入直播間",
|
||||||
|
"beijingTime": "北京時間",
|
||||||
|
"status": {
|
||||||
|
"notStarted": "未開始",
|
||||||
|
"live": "直播中",
|
||||||
|
"ended": "已結束"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"networkError": "網絡異常,請檢查網絡連接",
|
||||||
|
"reconnecting": "正在重連...",
|
||||||
|
"reconnectSuccess": "重連成功",
|
||||||
|
"reconnectFail": "重連失敗,請刷新頁面"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"title": "國家和地區",
|
||||||
|
"searchPlaceholder": "請輸入國家或地區",
|
||||||
|
"frequentCountry": "常用"
|
||||||
|
},
|
||||||
|
"app": {
|
||||||
|
"name": "豐和",
|
||||||
|
"description": "豐和國際京都拍賣",
|
||||||
|
"keywords": "豐和,豐和文化,FENGHE,京都,拍賣",
|
||||||
|
"language": "📚 語言",
|
||||||
|
"unocssExample": "🎨 Unocss示例",
|
||||||
|
"loading": "加載中...",
|
||||||
|
"error": {
|
||||||
|
"404": {
|
||||||
|
"title": "頁面不存在",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"network": "網絡錯誤",
|
||||||
|
"server": "服務器錯誤"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bid": {
|
||||||
|
"title": "競拍",
|
||||||
|
"noBids": "暫無競拍商品",
|
||||||
|
"bidNow": "立即競拍",
|
||||||
|
"success": "競拍成功",
|
||||||
|
"fail": "競拍失敗",
|
||||||
|
"confirm": "確認出價",
|
||||||
|
"cancel": "取消",
|
||||||
|
"amount": "出價金額",
|
||||||
|
"currentPrice": "當前價",
|
||||||
|
"nextPrice": "下一口價",
|
||||||
|
"bidHistory": "競價記錄",
|
||||||
|
"bidder": "競買人",
|
||||||
|
"bidTime": "競價時間",
|
||||||
|
"bidAmount": "競價金額",
|
||||||
|
"status": {
|
||||||
|
"bidding": "競價中",
|
||||||
|
"ended": "已結束",
|
||||||
|
"upcoming": "即將開始",
|
||||||
|
"cancelled": "已取消"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"confirmBid": "確認出價 {amount} 元?",
|
||||||
|
"bidSuccess": "出價成功",
|
||||||
|
"bidFail": "出價失敗",
|
||||||
|
"priceChanged": "價格已更新,請重新出價",
|
||||||
|
"insufficientBalance": "餘額不足",
|
||||||
|
"notQualified": "您暫未獲得競買資格",
|
||||||
|
"auctionEnded": "拍賣已結束",
|
||||||
|
"auctionNotStarted": "拍賣未開始"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "設置",
|
||||||
|
"language": "語言",
|
||||||
|
"notification": "消息通知",
|
||||||
|
"about": "關於我們",
|
||||||
|
"feedback": "意見反饋",
|
||||||
|
"privacy": "隱私政策",
|
||||||
|
"terms": "服務條款",
|
||||||
|
"version": "版本信息",
|
||||||
|
"logout": "退出登錄",
|
||||||
|
"darkMode": "深色模式",
|
||||||
|
"auto": "跟隨系統",
|
||||||
|
"light": "淺色",
|
||||||
|
"dark": "深色"
|
||||||
|
},
|
||||||
|
"layout": {
|
||||||
|
"default": {
|
||||||
|
"title": "豐和拍賣",
|
||||||
|
"loading": "加載中...",
|
||||||
|
"error": "出錯了",
|
||||||
|
"retry": "重試",
|
||||||
|
"back": "返回"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"notFound": "頁面不存在",
|
||||||
|
"back": "返回首頁",
|
||||||
|
"retry": "重試"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"loading": {
|
||||||
|
"text": "加載中..."
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"text": "暫無數據",
|
||||||
|
"description": "沒有找到相關內容"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"text": "出錯了",
|
||||||
|
"description": "加載失敗,請重試",
|
||||||
|
"button": "重試"
|
||||||
|
},
|
||||||
|
"navbar": {
|
||||||
|
"back": "返回",
|
||||||
|
"close": "關閉",
|
||||||
|
"home": "首頁"
|
||||||
|
},
|
||||||
|
"tabbar": {
|
||||||
|
"home": "首頁",
|
||||||
|
"auction": "拍賣",
|
||||||
|
"live": "直播",
|
||||||
|
"profile": "我的"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"confirm": "確定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"close": "關閉"
|
||||||
|
},
|
||||||
|
"toast": {
|
||||||
|
"success": "操作成功",
|
||||||
|
"fail": "操作失敗",
|
||||||
|
"loading": "加載中..."
|
||||||
|
},
|
||||||
|
"form": {
|
||||||
|
"required": "必填",
|
||||||
|
"optional": "選填",
|
||||||
|
"save": "保存",
|
||||||
|
"submit": "提交",
|
||||||
|
"cancel": "取消",
|
||||||
|
"pleaseInput": "請輸入",
|
||||||
|
"pleaseSelect": "請選擇"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"text": "點擊上傳",
|
||||||
|
"delete": "刪除",
|
||||||
|
"preview": "預覽",
|
||||||
|
"maxSize": "文件大小不能超過 {size}",
|
||||||
|
"format": "支持的文件格式:{formats}",
|
||||||
|
"uploading": "上傳中...",
|
||||||
|
"uploadSuccess": "上傳成功",
|
||||||
|
"uploadFail": "上傳失敗"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"floatingBubble": {
|
||||||
|
"backToLive": "回到直播"
|
||||||
|
},
|
||||||
|
"http": {
|
||||||
|
"error": {
|
||||||
|
"badRequest": "請求參數錯誤",
|
||||||
|
"unauthorized": "未授權或登錄過期",
|
||||||
|
"forbidden": "訪問被禁止",
|
||||||
|
"notFound": "請求的資源不存在",
|
||||||
|
"serverError": "伺服器內部錯誤",
|
||||||
|
"badGateway": "閘道錯誤",
|
||||||
|
"serviceUnavailable": "服務暫時不可用",
|
||||||
|
"gatewayTimeout": "閘道超時",
|
||||||
|
"operationFailed": "操作失敗",
|
||||||
|
"loginExpired": "登錄已過期,請重新登錄",
|
||||||
|
"networkError": "網絡連接失敗,請檢查網絡設置",
|
||||||
|
"requestFailed": "請求失敗",
|
||||||
|
"httpNotInitialized": "HTTP客戶端未初始化,請先調用setupHttp"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
index.html
Normal file
1
index.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -15,7 +15,6 @@ export default defineNuxtConfig({
|
|||||||
modules: [
|
modules: [
|
||||||
'@vant/nuxt',
|
'@vant/nuxt',
|
||||||
'@unocss/nuxt',
|
'@unocss/nuxt',
|
||||||
'@nuxt/image',
|
|
||||||
'@nuxtjs/i18n',
|
'@nuxtjs/i18n',
|
||||||
],
|
],
|
||||||
image: {
|
image: {
|
||||||
@ -42,13 +41,13 @@ export default defineNuxtConfig({
|
|||||||
'postcss-mobile-forever': {
|
'postcss-mobile-forever': {
|
||||||
appSelector: '#__nuxt',
|
appSelector: '#__nuxt',
|
||||||
viewportWidth: 375,
|
viewportWidth: 375,
|
||||||
maxDisplayWidth: 600,
|
|
||||||
// devtools excluded
|
// devtools excluded
|
||||||
exclude: /@nuxt/,
|
exclude: /@nuxt/,
|
||||||
border: true,
|
border: true,
|
||||||
rootContainingBlockSelectorList: [
|
rootContainingBlockSelectorList: [
|
||||||
'van-tabbar',
|
'van-tabbar',
|
||||||
'van-popup',
|
'van-popup',
|
||||||
|
'van-overlay',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -64,7 +63,6 @@ export default defineNuxtConfig({
|
|||||||
alwaysRedirect: true,
|
alwaysRedirect: true,
|
||||||
fallbackLocale: 'zh-CN'
|
fallbackLocale: 'zh-CN'
|
||||||
},
|
},
|
||||||
langDir: 'locales',
|
|
||||||
defaultLocale: 'zh-CN',
|
defaultLocale: 'zh-CN',
|
||||||
vueI18n: './i18n/i18n.config.ts',
|
vueI18n: './i18n/i18n.config.ts',
|
||||||
},
|
},
|
||||||
@ -91,7 +89,15 @@ export default defineNuxtConfig({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
nitro: {
|
||||||
|
externals: {
|
||||||
|
inline: ['tslib'] // 将 tslib 内联到构建中
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
build: {
|
||||||
|
transpile: ['tslib'] // 确保 tslib 被正确转译
|
||||||
|
},
|
||||||
vite: {
|
vite: {
|
||||||
build: {
|
build: {
|
||||||
target: 'esnext',
|
target: 'esnext',
|
||||||
@ -110,7 +116,10 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
|
|
||||||
devtools: {
|
devtools: {
|
||||||
enabled: true,
|
vscode: {
|
||||||
|
// 配置为 cursor 编辑器
|
||||||
|
editor: 'cursor'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
typescript: {
|
typescript: {
|
||||||
|
11
package.json
11
package.json
@ -19,24 +19,29 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fingerprintjs/fingerprintjs": "^4.5.1",
|
"@fingerprintjs/fingerprintjs": "^4.5.1",
|
||||||
"@nuxtjs/i18n": "^9.1.1",
|
"@nuxtjs/i18n": "^9.1.1",
|
||||||
|
"@vue-office/pdf": "^2.0.10",
|
||||||
"@vueuse/core": "^12.4.0",
|
"@vueuse/core": "^12.4.0",
|
||||||
"@yeger/vue-masonry-wall": "^5.0.17",
|
|
||||||
"aliyun-aliplayer": "^2.28.5",
|
"aliyun-aliplayer": "^2.28.5",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
|
"countup.js": "^2.8.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
|
"mammoth": "^1.9.0",
|
||||||
"nuxt": "^3.15.0",
|
"nuxt": "^3.15.0",
|
||||||
"pinyin": "4.0.0-alpha.2",
|
"pinyin": "4.0.0-alpha.2",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"segmentit": "^2.0.3",
|
"segmentit": "^2.0.3",
|
||||||
|
"tslib": "^2.6.0",
|
||||||
"vconsole": "^3.15.1",
|
"vconsole": "^3.15.1",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0"
|
"vue-demi": "^0.14.10",
|
||||||
|
"vue-pdf-embed": "^2.1.2",
|
||||||
|
"vue-router": "^4.5.0",
|
||||||
|
"vue-signature-pad": "^3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/carbon": "^1.2.5",
|
"@iconify-json/carbon": "^1.2.5",
|
||||||
"@nuxt/image": "^1.9.0",
|
|
||||||
"@unocss/nuxt": "0.65.2",
|
"@unocss/nuxt": "0.65.2",
|
||||||
"@unocss/preset-rem-to-px": "0.65.2",
|
"@unocss/preset-rem-to-px": "0.65.2",
|
||||||
"@vant/nuxt": "^1.0.6",
|
"@vant/nuxt": "^1.0.6",
|
||||||
|
3013
pnpm-lock.yaml
3013
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
BIN
public/pdfs/jmxy.pdf
Normal file
BIN
public/pdfs/jmxy.pdf
Normal file
Binary file not shown.
BIN
public/pdfs/jmxz.pdf
Normal file
BIN
public/pdfs/jmxz.pdf
Normal file
Binary file not shown.
BIN
public/pdfs/pmbl.pdf
Normal file
BIN
public/pdfs/pmbl.pdf
Normal file
Binary file not shown.
BIN
public/pdfs/pmgg.pdf
Normal file
BIN
public/pdfs/pmgg.pdf
Normal file
Binary file not shown.
BIN
public/pdfs/pmgz.pdf
Normal file
BIN
public/pdfs/pmgz.pdf
Normal file
Binary file not shown.
BIN
public/pdfs/pmyjqrs.pdf
Normal file
BIN
public/pdfs/pmyjqrs.pdf
Normal file
Binary file not shown.
BIN
public/pdfs/privacyPolicy.pdf
Normal file
BIN
public/pdfs/privacyPolicy.pdf
Normal file
Binary file not shown.
31
public/privacyPolicy.html
Normal file
31
public/privacyPolicy.html
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user