Compare commits
	
		
			32 Commits
		
	
	
		
			629e31bc21
			...
			e49b6a78d4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e49b6a78d4 | ||
|  | 23a127b0d3 | ||
|  | 839dbe8a42 | ||
|  | ac25fe40dc | ||
|  | fb6cb233a1 | ||
|  | a79f1b85da | ||
|  | 2b13718cea | ||
|  | 575fcae049 | ||
|  | 53571882a0 | ||
|  | 8207170a01 | ||
|  | 9688e9b3a6 | ||
|  | e0af9f99a0 | ||
|  | 5d814a3922 | ||
|  | 33713932a1 | ||
|  | e7cd4ff9ba | ||
|  | a0d3b2b329 | ||
|  | 779dc84356 | ||
|  | b1d2dc19d2 | ||
|  | 2fdcfc8c3b | ||
|  | 4b7a7ce285 | ||
|  | 09bbd9ae14 | ||
|  | 437e74ee86 | ||
|  | 38fc5d78ca | ||
|  | a84e1524b5 | ||
|  | be60cac47e | ||
|  | 46d17fb6e6 | ||
|  | da43bb5429 | ||
|  | 1263128171 | ||
|  | c32869988c | ||
|  | 1ed311c5f9 | ||
|  | bbb191651e | ||
|  | bed0e6c4be | 
| @ -1,4 +1,4 @@ | |||||||
| import { request } from '@/api/http.js' | import { request } from '@/api-collect-code/http.js' | ||||||
| 
 | 
 | ||||||
| export async function checkPhone(data) { | export async function checkPhone(data) { | ||||||
|     return await request({ |     return await request({ | ||||||
| @ -9,7 +9,7 @@ export async function checkPhone(data) { | |||||||
| } | } | ||||||
| export async function userSend(data) { | export async function userSend(data) { | ||||||
|     return await request( { |     return await request( { | ||||||
|         url:'/api/v1/m/user/send', |         url:'/api/v1/m/user/mobile/send', | ||||||
|         method: 'POST', |         method: 'POST', | ||||||
|         data |         data | ||||||
|     }) |     }) | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import { request } from '@/api/http.js' | import { request } from '@/api-collect-code/http.js' | ||||||
| 
 | 
 | ||||||
| export async function offlineQrcodeList(data) { | export async function offlineQrcodeList(data) { | ||||||
|     return await request( { |     return await request( { | ||||||
| @ -56,7 +56,7 @@ export async function offlineQrcode(data) { | |||||||
| export async function createOrder(data) { | export async function createOrder(data) { | ||||||
| 
 | 
 | ||||||
|     return await request( { |     return await request( { | ||||||
|         url:'/api/v1/offlineQrcode/createOrder', |         url:'/api/v1/offlineQrcode/createOrder/V2', | ||||||
|         method: 'POST', |         method: 'POST', | ||||||
|         data |         data | ||||||
|     }) |     }) | ||||||
|  | |||||||
| @ -9,9 +9,9 @@ let http | |||||||
| // HTTP 状态码映射 - 使用i18n国际化
 | // HTTP 状态码映射 - 使用i18n国际化
 | ||||||
| export function setupHttp() { | export function setupHttp() { | ||||||
|   if (http) return http |   if (http) return http | ||||||
|  const {token}=  codeAuthStore() |  const {codeToken}=  codeAuthStore() | ||||||
|   const config = useRuntimeConfig() |   const config = useRuntimeConfig() | ||||||
|   const baseURL = config.public.NUXT_PUBLIC_API_COLLECT_CODE |   const baseURL = config.public.NUXT_PUBLIC_API_BASE | ||||||
|   const router = useRouter() |   const router = useRouter() | ||||||
|   const i18n = useNuxtApp().$i18n |   const i18n = useNuxtApp().$i18n | ||||||
|    |    | ||||||
| @ -43,7 +43,7 @@ export function setupHttp() { | |||||||
|       // 添加 token
 |       // 添加 token
 | ||||||
|       options.headers = { |       options.headers = { | ||||||
|         ...options.headers, |         ...options.headers, | ||||||
|         Authorization: token.value, |         Authorization: codeToken.value, | ||||||
|         'accept-language': i18n.locale.value |         'accept-language': i18n.locale.value | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
| @ -64,11 +64,11 @@ export function setupHttp() { | |||||||
|       if (data.status === 1) { |       if (data.status === 1) { | ||||||
|         message.error(data.msg || i18n.t('http.error.operationFailed')) |         message.error(data.msg || i18n.t('http.error.operationFailed')) | ||||||
|       } |       } | ||||||
| 
 |       console.log('拦截响应',data) | ||||||
|       // 处理登录失效
 |       // 处理登录失效
 | ||||||
|       if (data.status === 401) { |       if (data.status === 401) { | ||||||
|         message.error(i18n.t('http.error.loginExpired')) |         message.error(i18n.t('http.error.loginExpired')) | ||||||
|         token.value = '' // 清除 token
 |         codeToken.value = '' // 清除 token
 | ||||||
|         router.replace('/collectCode/login') |         router.replace('/collectCode/login') | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -31,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> | ||||||
|  | |||||||
							
								
								
									
										276
									
								
								app/components/StripeCheckout.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								app/components/StripeCheckout.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,276 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="stripe-container"> | ||||||
|  |     <form id="payment-form" @submit.prevent="handleSubmit"> | ||||||
|  |       <div id="payment-element"> | ||||||
|  |         <!--Stripe.js injects the Payment Element--> | ||||||
|  |       </div> | ||||||
|  |       <button id="submit"> | ||||||
|  |         <div class="spinner hidden" id="spinner"></div> | ||||||
|  |         <span id="button-text">Pay now</span> | ||||||
|  |       </button> | ||||||
|  |       <div id="payment-message" class="hidden"></div> | ||||||
|  |     </form> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script setup> | ||||||
|  | import { ref, onMounted } from 'vue' | ||||||
|  | 
 | ||||||
|  | // The items the customer wants to buy | ||||||
|  | const items = [{ id: "xl-tshirt", amount: 1000 }] | ||||||
|  | 
 | ||||||
|  | const stripe = ref(null) | ||||||
|  | const elements = ref(null) | ||||||
|  | const isLoading = ref(false) | ||||||
|  | 
 | ||||||
|  | onMounted(async () => { | ||||||
|  |   try { | ||||||
|  |     // 初始化 Stripe | ||||||
|  |     stripe.value = window.Stripe("pk_test_51QfbSAAB1Vm8VfJq3AWsR4k2mZjnlF7XFrmlbc6XVXrtwXquAUfwzZmOFDbxMIAwqJBgqao8KLt2wmPc4vNOCTeo00WB78KtfV") | ||||||
|  |     await initialize() | ||||||
|  |   } catch (error) { | ||||||
|  |     showMessage("Failed to initialize payment system") | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | // Fetches a payment intent and captures the client secret | ||||||
|  | const initialize = async () => { | ||||||
|  |   try { | ||||||
|  |     const response = await fetch("/create-payment-intent", { | ||||||
|  |       method: "POST", | ||||||
|  |       headers: { "Content-Type": "application/json" }, | ||||||
|  |       body: JSON.stringify({ items }), | ||||||
|  |     }) | ||||||
|  |     const { clientSecret } = await response.json() | ||||||
|  | 
 | ||||||
|  |     const appearance = { | ||||||
|  |       theme: 'stripe', | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // 创建 elements 实例 | ||||||
|  |     elements.value = stripe.value.elements({  | ||||||
|  |       appearance,  | ||||||
|  |       clientSecret, | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     // 创建并挂载 Payment Element | ||||||
|  |     const paymentElement = elements.value.create("payment", { | ||||||
|  |       layout: "accordion", | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     // 确保挂载到正确的 DOM 元素 | ||||||
|  |     const mountElement = document.getElementById("payment-element") | ||||||
|  |     if (mountElement) { | ||||||
|  |       paymentElement.mount(mountElement) | ||||||
|  |     } else { | ||||||
|  |       throw new Error("Payment element mount point not found") | ||||||
|  |     } | ||||||
|  |   } catch (error) { | ||||||
|  |     showMessage("Failed to load payment form") | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const handleSubmit = async () => { | ||||||
|  |   if (!stripe.value || !elements.value) { | ||||||
|  |     showMessage("Payment system not initialized") | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   setLoading(true) | ||||||
|  | 
 | ||||||
|  |   try { | ||||||
|  |     const { error } = await stripe.value.confirmPayment({ | ||||||
|  |       elements: elements.value, | ||||||
|  |       confirmParams: { | ||||||
|  |         return_url: window.location.origin + "/complete.html", | ||||||
|  |       }, | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |     if (error) { | ||||||
|  |       if (error.type === "card_error" || error.type === "validation_error") { | ||||||
|  |         showMessage(error.message) | ||||||
|  |       } else { | ||||||
|  |         showMessage("An unexpected error occurred.") | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } catch (e) { | ||||||
|  |     showMessage("Payment processing failed") | ||||||
|  |   } finally { | ||||||
|  |     setLoading(false) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const showMessage = (messageText) => { | ||||||
|  |   const messageContainer = document.querySelector("#payment-message") | ||||||
|  | 
 | ||||||
|  |   messageContainer.classList.remove("hidden") | ||||||
|  |   messageContainer.textContent = messageText | ||||||
|  | 
 | ||||||
|  |   setTimeout(() => { | ||||||
|  |     messageContainer.classList.add("hidden") | ||||||
|  |     messageContainer.textContent = "" | ||||||
|  |   }, 4000) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Show a spinner on payment submission | ||||||
|  | const setLoading = (isLoading) => { | ||||||
|  |   if (isLoading) { | ||||||
|  |     // Disable the button and show a spinner | ||||||
|  |     document.querySelector("#submit").disabled = true | ||||||
|  |     document.querySelector("#spinner").classList.remove("hidden") | ||||||
|  |     document.querySelector("#button-text").classList.add("hidden") | ||||||
|  |   } else { | ||||||
|  |     document.querySelector("#submit").disabled = false | ||||||
|  |     document.querySelector("#spinner").classList.add("hidden") | ||||||
|  |     document.querySelector("#button-text").classList.remove("hidden") | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style scoped> | ||||||
|  | .stripe-container { | ||||||
|  |   font-family: -apple-system, BlinkMacSystemFont, sans-serif; | ||||||
|  |   font-size: 16px; | ||||||
|  |   -webkit-font-smoothing: antialiased; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   justify-content: center; | ||||||
|  |   align-content: center; | ||||||
|  |   height: 100vh; | ||||||
|  |   width: 100vw; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | form { | ||||||
|  |   width: 30vw; | ||||||
|  |   min-width: 500px; | ||||||
|  |   align-self: center; | ||||||
|  |   box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1), | ||||||
|  |     0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07); | ||||||
|  |   border-radius: 7px; | ||||||
|  |   padding: 40px; | ||||||
|  |   margin-top: auto; | ||||||
|  |   margin-bottom: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .hidden { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #payment-message { | ||||||
|  |   color: rgb(105, 115, 134); | ||||||
|  |   font-size: 16px; | ||||||
|  |   line-height: 20px; | ||||||
|  |   padding-top: 12px; | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #payment-element { | ||||||
|  |   margin-bottom: 24px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | button { | ||||||
|  |   background: #0055DE; | ||||||
|  |   font-family: Arial, sans-serif; | ||||||
|  |   color: #ffffff; | ||||||
|  |   border-radius: 4px; | ||||||
|  |   border: 0; | ||||||
|  |   padding: 12px 16px; | ||||||
|  |   font-size: 16px; | ||||||
|  |   font-weight: 600; | ||||||
|  |   cursor: pointer; | ||||||
|  |   display: block; | ||||||
|  |   transition: all 0.2s ease; | ||||||
|  |   box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07); | ||||||
|  |   width: 100%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | button:hover { | ||||||
|  |   filter: contrast(115%); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | button:disabled { | ||||||
|  |   opacity: 0.5; | ||||||
|  |   cursor: default; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .spinner, | ||||||
|  | .spinner:before, | ||||||
|  | .spinner:after { | ||||||
|  |   border-radius: 50%; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .spinner { | ||||||
|  |   color: #ffffff; | ||||||
|  |   font-size: 22px; | ||||||
|  |   text-indent: -99999px; | ||||||
|  |   margin: 0px auto; | ||||||
|  |   position: relative; | ||||||
|  |   width: 20px; | ||||||
|  |   height: 20px; | ||||||
|  |   box-shadow: inset 0 0 0 2px; | ||||||
|  |   -webkit-transform: translateZ(0); | ||||||
|  |   -ms-transform: translateZ(0); | ||||||
|  |   transform: translateZ(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .spinner:before, | ||||||
|  | .spinner:after { | ||||||
|  |   position: absolute; | ||||||
|  |   content: ""; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .spinner:before { | ||||||
|  |   width: 10.4px; | ||||||
|  |   height: 20.4px; | ||||||
|  |   background: #0055DE; | ||||||
|  |   border-radius: 20.4px 0 0 20.4px; | ||||||
|  |   top: -0.2px; | ||||||
|  |   left: -0.2px; | ||||||
|  |   -webkit-transform-origin: 10.4px 10.2px; | ||||||
|  |   transform-origin: 10.4px 10.2px; | ||||||
|  |   -webkit-animation: loading 2s infinite ease 1.5s; | ||||||
|  |   animation: loading 2s infinite ease 1.5s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .spinner:after { | ||||||
|  |   width: 10.4px; | ||||||
|  |   height: 10.2px; | ||||||
|  |   background: #0055DE; | ||||||
|  |   border-radius: 0 10.2px 10.2px 0; | ||||||
|  |   top: -0.1px; | ||||||
|  |   left: 10.2px; | ||||||
|  |   -webkit-transform-origin: 0px 10.2px; | ||||||
|  |   transform-origin: 0px 10.2px; | ||||||
|  |   -webkit-animation: loading 2s infinite ease; | ||||||
|  |   animation: loading 2s infinite ease; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @-webkit-keyframes loading { | ||||||
|  |   0% { | ||||||
|  |     -webkit-transform: rotate(0deg); | ||||||
|  |     transform: rotate(0deg); | ||||||
|  |   } | ||||||
|  |   100% { | ||||||
|  |     -webkit-transform: rotate(360deg); | ||||||
|  |     transform: rotate(360deg); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @keyframes loading { | ||||||
|  |   0% { | ||||||
|  |     -webkit-transform: rotate(0deg); | ||||||
|  |     transform: rotate(0deg); | ||||||
|  |   } | ||||||
|  |   100% { | ||||||
|  |     -webkit-transform: rotate(360deg); | ||||||
|  |     transform: rotate(360deg); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media only screen and (max-width: 600px) { | ||||||
|  |   form { | ||||||
|  |     width: 80vw; | ||||||
|  |     min-width: initial; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style>  | ||||||
| @ -18,7 +18,6 @@ let container = null        // DOM容器元素 | |||||||
|  */ |  */ | ||||||
| export const showMinWindow1 = (props = {}) => { | export const showMinWindow1 = (props = {}) => { | ||||||
|     // 服务端渲染时直接返回
 |     // 服务端渲染时直接返回
 | ||||||
|     console.log('!process.client',!process.client) |  | ||||||
|     if (!process.client) return null |     if (!process.client) return null | ||||||
| 
 | 
 | ||||||
|     // 如果实例已存在,避免重复创建
 |     // 如果实例已存在,避免重复创建
 | ||||||
| @ -60,7 +59,6 @@ export const showMinWindow1 = (props = {}) => { | |||||||
|          |          | ||||||
|         return minWindowInstance |         return minWindowInstance | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('创建浮动气泡时发生错误:', error) |  | ||||||
|         // 发生错误时确保清理资源
 |         // 发生错误时确保清理资源
 | ||||||
|         hideMinWindow1() |         hideMinWindow1() | ||||||
|         return null |         return null | ||||||
| @ -72,7 +70,7 @@ export const showMinWindow1 = (props = {}) => { | |||||||
|  * 清理所有相关资源和DOM元素 |  * 清理所有相关资源和DOM元素 | ||||||
|  */ |  */ | ||||||
| export const hideMinWindow1 = () => { | export const hideMinWindow1 = () => { | ||||||
|     console.log('!minWindowApp && !container', !minWindowApp && !container); |      | ||||||
|      |      | ||||||
|     if (!minWindowApp && !container) return |     if (!minWindowApp && !container) return | ||||||
| 
 | 
 | ||||||
| @ -93,7 +91,6 @@ export const hideMinWindow1 = () => { | |||||||
|             document.body.removeChild(existingContainer) |             document.body.removeChild(existingContainer) | ||||||
|         } |         } | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('清理浮动气泡时发生错误:', error) |  | ||||||
|         } finally { |         } finally { | ||||||
|         // 重置所有状态
 |         // 重置所有状态
 | ||||||
|         minWindowApp = null |         minWindowApp = null | ||||||
|  | |||||||
| @ -28,7 +28,6 @@ export const showMinWindow = (snapshot, props = {}) => { | |||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   app.config.errorHandler = (err) => { |   app.config.errorHandler = (err) => { | ||||||
|     console.error('MinWindow Error:', err) |  | ||||||
|     hideMinWindow() |     hideMinWindow() | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,7 +15,6 @@ 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 router = useRouter(); | const router = useRouter(); | ||||||
| @ -59,8 +58,7 @@ const goPay=()=>{ | |||||||
|   }else if (detail.value.status===4){ |   }else if (detail.value.status===4){ | ||||||
|     router.push('/payment') |     router.push('/payment') | ||||||
|   } |   } | ||||||
|   console.log('detail',detail.value) |   //router.push('/payment') | ||||||
| //router.push('/payment') |  | ||||||
| } | } | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|   document.addEventListener('mousemove', onDrag) |   document.addEventListener('mousemove', onDrag) | ||||||
|  | |||||||
| @ -1,26 +1,72 @@ | |||||||
| <script setup> | <script setup> | ||||||
| import { onMounted, ref } from 'vue' | import { onMounted, ref } from 'vue' | ||||||
| import {authStore} from "~/stores/auth/index.js"; | import {authStore} from "~/stores/auth/index.js"; | ||||||
| const {checkoutSessionUrl,payUid}= authStore() | import {orderQuery} from "~/api/goods/index.js"; | ||||||
|  | import { WebSocketClient } from '@/utils/websocket' | ||||||
| const config = useRuntimeConfig() | const config = useRuntimeConfig() | ||||||
| definePageMeta({ | definePageMeta({ | ||||||
|   layout: 'default', |   layout: 'default', | ||||||
|   title: 'Stripe支付' |   title: 'Stripe支付' | ||||||
| }) | }) | ||||||
| console.log('config.public.NUXT_PUBLIC_PKEY',config.public.NUXT_PUBLIC_PKEY); | 
 | ||||||
| const stripe = Stripe(config.public.NUXT_PUBLIC_PKEY) | const stripe = Stripe(config.public.NUXT_PUBLIC_PKEY) | ||||||
| 
 | const route = useRoute() | ||||||
| 
 | const baseURL = config.public.NUXT_PUBLIC_API_BASE | ||||||
| const items = [{ id: "xl-tshirt", amount: 1000 }] | const items = [{ id: "xl-tshirt", amount: 1000 }] | ||||||
| const elements = ref(null) | const elements = ref(null) | ||||||
| const paymentMessage = ref('') | const paymentMessage = ref('') | ||||||
| const isLoading = ref(false) | const isLoading = ref(false) | ||||||
| const showSpinner = ref(false) | const showSpinner = ref(false) | ||||||
|  | let pollTimer = null | ||||||
|  | let timeoutTimer = null | ||||||
|  | const router = useRouter() | ||||||
|  | const startPolling = () => { | ||||||
|  |   pollTimer = setInterval(async () => { | ||||||
|  |     const res = await orderQuery({ | ||||||
|  |       orderNo: route.query.payUid | ||||||
|  |     }) | ||||||
|  |     if (res.status === 0) { | ||||||
|  |       if (res.data.status !== 3) { | ||||||
|  |         clearInterval(pollTimer) | ||||||
|  |         clearTimeout(timeoutTimer) | ||||||
|  |         router.replace({ | ||||||
|  |           path: route.query.returnUrl, | ||||||
|  |           query: { | ||||||
|  |             orderNo: route.query.payUid | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, 1000) | ||||||
| 
 | 
 | ||||||
|  | /*  timeoutTimer = setTimeout(() => { | ||||||
|  |     clearInterval(pollTimer) | ||||||
|  |     setLoading(false) | ||||||
|  |   }, 180000)*/ | ||||||
|  | } | ||||||
|  | let wsClient=null | ||||||
|  | const watchWebSocket = () => { | ||||||
|  |    wsClient = new WebSocketClient( | ||||||
|  |     config.public.NUXT_PUBLIC_SOCKET_URL | ||||||
|  |   ) | ||||||
|  |   const ws = wsClient.connect('/api/v1/order/ws/v2', { | ||||||
|  |     PayUid: route.query.payUid, | ||||||
|  |   }) | ||||||
|  |   ws.onOpen(() => { | ||||||
|  |             }) | ||||||
|  |         ws.onMessage((event) => { | ||||||
|  |             router.replace({ | ||||||
|  |           path: route.query.returnUrl, | ||||||
|  |           query: { | ||||||
|  |             orderNo: route.query.payUid | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |         }) | ||||||
|  |         ws.onClose(() => { | ||||||
|  |             }) | ||||||
|  | } | ||||||
| async function initialize() { | async function initialize() { | ||||||
|   const clientSecret = checkoutSessionUrl.value |   const clientSecret = route.query.stripeKey | ||||||
|   console.log('clientSecret',clientSecret); |  | ||||||
|    |  | ||||||
|   const appearance = { |   const appearance = { | ||||||
|     theme: 'stripe', |     theme: 'stripe', | ||||||
|   } |   } | ||||||
| @ -38,20 +84,25 @@ async function handleSubmit(e) { | |||||||
|   e.preventDefault() |   e.preventDefault() | ||||||
|   setLoading(true) |   setLoading(true) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|   const { error } = await stripe.confirmPayment({ |   const { error } = await stripe.confirmPayment({ | ||||||
|     elements: elements.value, |     elements: elements.value, | ||||||
|     confirmParams: { |     confirmParams: { | ||||||
|       return_url: "http://192.168.88.68:3000/payment/result?orderNo="+payUid.value, |       return_url: `${baseURL}${route.query.returnUrl}?orderNo=${route.query.payUid}`, | ||||||
|     }, |     }, | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|  |   if (error) { | ||||||
|  |  /*   clearInterval(pollTimer) | ||||||
|  |     clearTimeout(timeoutTimer)*/ | ||||||
|     if (error.type === "card_error" || error.type === "validation_error") { |     if (error.type === "card_error" || error.type === "validation_error") { | ||||||
|       showMessage(error.message) |       showMessage(error.message) | ||||||
|     } else { |     } else { | ||||||
|       showMessage("An unexpected error occurred.") |       showMessage("An unexpected error occurred.") | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     setLoading(false) |     setLoading(false) | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function showMessage(messageText) { | function showMessage(messageText) { | ||||||
| @ -66,8 +117,17 @@ function setLoading(loading) { | |||||||
|   showSpinner.value = loading |   showSpinner.value = loading | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | onUnmounted(()=>{ | ||||||
|  |   wsClient.disconnect() | ||||||
|  |   clearTimeout(timeoutTimer) | ||||||
|  |   clearInterval(pollTimer) | ||||||
|  | 
 | ||||||
|  | }) | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|  |   watchWebSocket() | ||||||
|   initialize() |   initialize() | ||||||
|  |   startPolling() | ||||||
| }) | }) | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| @ -8,7 +8,7 @@ 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, codeToken, fingerprint} = codeAuthStore() | ||||||
| const router = useRouter(); | const router = useRouter(); | ||||||
| const route = useRoute(); | const route = useRoute(); | ||||||
| const {locale} = useI18n() | const {locale} = useI18n() | ||||||
| @ -36,7 +36,6 @@ const countdown = ref(0); | |||||||
| const phoneNum = ref('') | const phoneNum = ref('') | ||||||
| const code = ref('') | const code = ref('') | ||||||
| const pane = ref(0) | const pane = ref(0) | ||||||
| const showKeyboard = ref(false); |  | ||||||
| const getFingerprint = async () => { | const getFingerprint = async () => { | ||||||
|   const fp = await FingerprintJS.load() |   const fp = await FingerprintJS.load() | ||||||
|   const result = await fp.get() |   const result = await fp.get() | ||||||
| @ -50,36 +49,29 @@ const checkFingerprint = async () => { | |||||||
|     await router.push('/collectCode/mine') |     await router.push('/collectCode/mine') | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | const codeInput = ref(null) | ||||||
|  | const isFocused = ref(false) | ||||||
| checkFingerprint() | checkFingerprint() | ||||||
| const vanSwipeRef = ref(null) | const vanSwipeRef = ref(null) | ||||||
| const getCode = async () => { | const getCode = async () => { | ||||||
|   loadingRef.value.loading1 = true |   loadingRef.value.loading1 = true | ||||||
|  |   try { | ||||||
|     const res = await checkPhone({ |     const res = await checkPhone({ | ||||||
|       tel: phoneNum.value, |       tel: phoneNum.value, | ||||||
|     }) |     }) | ||||||
|  |     if (res.status === 0) { | ||||||
|  |       const sendRes = await userSend({telNum: phoneNum.value, zone: '+86'}) | ||||||
|  |       startCountdown() | ||||||
|  |         pane.value = 1 | ||||||
|  |         await nextTick() | ||||||
|  |         vanSwipeRef.value?.swipeTo(pane.value) | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  |   } catch (error) { | ||||||
|  |     console.error('获取验证码失败:', error) | ||||||
|  |   } finally { | ||||||
|     loadingRef.value.loading1 = false |     loadingRef.value.loading1 = false | ||||||
|   if (res.status === 0) { |  | ||||||
|     const res = await userSend({telNum: phoneNum.value, zone: '+86'}) |  | ||||||
|     if (res.status === 0) { |  | ||||||
|       pane.value = 1 |  | ||||||
|       vanSwipeRef.value?.swipeTo(pane.value) |  | ||||||
|       showKeyboard.value = true |  | ||||||
|   } |   } | ||||||
|   } |  | ||||||
|   /*  loadingRef.value.loading1 = false |  | ||||||
|     if (res.status === 0) { |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
|     pane.value = 1 |  | ||||||
|     vanSwipeRef.value?.swipeTo(pane.value) |  | ||||||
|     showKeyboard.value = true |  | ||||||
|     startCountdown();*/ |  | ||||||
|   /*  pane.value = 1 |  | ||||||
|     vanSwipeRef.value?.swipeTo(pane.value) |  | ||||||
|     showKeyboard.value=true |  | ||||||
|     startCountdown();*/ |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
| const changeToPwd = async () => { | const changeToPwd = async () => { | ||||||
|   loginType.value = loginType.value === 0 ? 1 : 0 |   loginType.value = loginType.value === 0 ? 1 : 0 | ||||||
| @ -98,7 +90,7 @@ const goLogin = async () => { | |||||||
|   }) |   }) | ||||||
|   if (res.status === 0) { |   if (res.status === 0) { | ||||||
|     userInfo.value = res.data.accountInfo |     userInfo.value = res.data.accountInfo | ||||||
|     token.value = res.data.token |     codeToken.value = res.data.token | ||||||
|     fingerprint.value = await getFingerprint() |     fingerprint.value = await getFingerprint() | ||||||
| 
 | 
 | ||||||
|     await router.push('/collectCode/mine'); |     await router.push('/collectCode/mine'); | ||||||
| @ -114,14 +106,15 @@ const togglePasswordVisibility = () => { | |||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <div class="h-[100vh] w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-cover px-[31px] pt-[86px]"> |   <div class="grow-1 w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-bottom bg-cover px-[31px] pt-[86px]"> | ||||||
|     <div class="w-full flex justify-center mb-[100px] flex-col items-center"> |     <div class="w-full flex justify-center mb-[100px] flex-col items-center"> | ||||||
|       <img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt=""> |       <img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt=""> | ||||||
|       <img class="h-[29px] w-[108px]" src="@/static/images/qrcodetext.png" alt=""> |       <img class="h-[29px] w-[108px]" src="@/static/images/qrcodetext.png" alt=""> | ||||||
|     </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> | ||||||
|             <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="$t('collectCode.login.phoneNumberPlaceholder')"> |                 <van-field v-model="phoneNum" clearable :placeholder="$t('collectCode.login.phoneNumberPlaceholder')"> | ||||||
| @ -132,7 +125,7 @@ const togglePasswordVisibility = () => { | |||||||
|                   </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-if="loginType === 1"> | ||||||
|                 <van-field |                 <van-field | ||||||
|                     v-model="password" |                     v-model="password" | ||||||
|                     :type="showPassword ? 'text' : 'password'" |                     :type="showPassword ? 'text' : 'password'" | ||||||
| @ -160,31 +153,56 @@ const togglePasswordVisibility = () => { | |||||||
|                   {{ loginType === 0 ? $t('collectCode.login.passwordLogin') : $t('collectCode.login.codeLogin') }} |                   {{ loginType === 0 ? $t('collectCode.login.passwordLogin') : $t('collectCode.login.codeLogin') }} | ||||||
|                 </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="$t('collectCode.login.getCode')" |                 <van-button :loading="loadingRef.loading1" v-if="phoneNum" :loading-text="$t('collectCode.login.getCode')" | ||||||
|                           type="primary" block style="height: 48px" @click="getCode">{{ $t('collectCode.login.getCode') }} |                             type="primary" block style="height: 48px" @click="getCode">{{ | ||||||
|  |                     $t('collectCode.login.getCode') | ||||||
|  |                   }} | ||||||
|  |                 </van-button> | ||||||
|  |                 <van-button v-else type="primary" color="#D3D3D3" block style="height: 48px"> | ||||||
|  |                   {{ $t('collectCode.login.getCode') }} | ||||||
|                 </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="$t('collectCode.login.login')" |                 <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">{{ $t('collectCode.login.login') }} |                             style="height: 48px;margin-top:10px" @click="goLogin">{{ $t('collectCode.login.login') }} | ||||||
|                 </van-button> |                 </van-button> | ||||||
|               <van-button v-else type="primary" color="#D3D3D3" block style="height: 48px">{{ $t('collectCode.login.login') }}</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> |         </div> | ||||||
|       </van-swipe-item> |       </van-swipe-item> | ||||||
|       <van-swipe-item> |       <van-swipe-item> | ||||||
|         <div v-show="pane === 1"> |         <div v-if="pane == 1"> | ||||||
|  |           <div> | ||||||
|             <div class="flex mb-[16px]"> |             <div class="flex mb-[16px]"> | ||||||
|               <div class="text-[16px] text-[#BDBDBD] mr-[10px]">{{ $t('collectCode.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"/> |             <div class="relative"> | ||||||
|  |               <van-password-input | ||||||
|  |                   :value="code" | ||||||
|  |                   :gutter="10" | ||||||
|  |                   :mask="false" | ||||||
|  |                   :focused="isFocused" | ||||||
|  |               /> | ||||||
|  |               <input | ||||||
|  |                   v-model="code" | ||||||
|  |                   type="tel" | ||||||
|  |                   maxlength="6" | ||||||
|  |                   ref="codeInput" | ||||||
|  |                   class="opacity-0 absolute top-0 left-0 h-full w-full z-999" | ||||||
|  |                   @input="code = $event.target.value.replace(/\D/g, '').slice(0, 6)" | ||||||
|  |                   @focus="isFocused = true" | ||||||
|  |                   @blur="isFocused = false" | ||||||
|  |               /> | ||||||
|  |             </div> | ||||||
|             <div class="flex justify-between"> |             <div class="flex justify-between"> | ||||||
|               <div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'}  text-14px`"> |               <div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'}  text-14px`"> | ||||||
|                 {{ $t('collectCode.login.reSend') }}<span v-if="countdown>0">({{ countdown }})</span> |                 {{ $t('collectCode.login.reSend') }}<span v-if="countdown>0">({{ countdown }})</span> | ||||||
| @ -203,9 +221,9 @@ const togglePasswordVisibility = () => { | |||||||
|               </van-button> |               </van-button> | ||||||
|             </div> |             </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"/> |  | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,7 +33,6 @@ const getQRBase64 = async () => { | |||||||
|       errorCorrectionLevel: 'H' |       errorCorrectionLevel: 'H' | ||||||
|     }) |     }) | ||||||
|   } catch (err) { |   } catch (err) { | ||||||
|     console.error('生成二维码失败:', err) |  | ||||||
|     return null |     return null | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -45,7 +44,26 @@ const openQrCode=async ()=>{ | |||||||
|   QRUrl.value=base64 |   QRUrl.value=base64 | ||||||
|   show.value=true |   show.value=true | ||||||
| } | } | ||||||
|  | /** | ||||||
|  |  * 将数字格式化为"250XX"格式,其中XX是两位数 | ||||||
|  |  * @param {number} num - 要格式化的数字 | ||||||
|  |  * @return {string} - 格式化后的字符串 | ||||||
|  |  */ | ||||||
|  | function formatNumber(num) { | ||||||
|  |   // 确保输入是有效数字 | ||||||
|  |   if (typeof num !== 'number' && isNaN(Number(num))) { | ||||||
|  |     throw new Error('输入必须是有效数字'); | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|  |   // 转换为数字类型(以防输入是字符串数字) | ||||||
|  |   const number = Number(num); | ||||||
|  | 
 | ||||||
|  |   // 数字部分格式化为两位数,不足补0 | ||||||
|  |   const formattedNum = number.toString().padStart(2, '0'); | ||||||
|  | 
 | ||||||
|  |   // 添加前缀"250"并返回结果 | ||||||
|  |   return `250${formattedNum}`; | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
| @ -59,7 +77,7 @@ 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>{{ $t('collectCode.qrcode.card.lotNo') }}{{ data.lotNo }}</div> |         <div>{{ $t('collectCode.qrcode.card.lotNo') }}{{ formatNumber(data.lotNo) }}</div> | ||||||
|         <div>{{ $t('collectCode.qrcode.card.creator') }}{{ data.userName }}</div> |         <div>{{ $t('collectCode.qrcode.card.creator') }}{{ data.userName }}</div> | ||||||
|         <div>{{ $t('collectCode.qrcode.card.createTime') }}{{data.createdAt}}</div> |         <div>{{ $t('collectCode.qrcode.card.createTime') }}{{data.createdAt}}</div> | ||||||
|       </div> |       </div> | ||||||
|  | |||||||
| @ -30,7 +30,6 @@ const initData = async () => { | |||||||
| } | } | ||||||
| const show=ref(false) | const show=ref(false) | ||||||
| const close=()=>{ | const close=()=>{ | ||||||
|   console.log('show',show.value) |  | ||||||
|   show.value=false |   show.value=false | ||||||
| } | } | ||||||
| const logOut=()=>{ | const logOut=()=>{ | ||||||
| @ -81,8 +80,11 @@ const loadMore = async () => { | |||||||
| const abnormal=ref(false) | const abnormal=ref(false) | ||||||
| const abnormalRow=ref({}) | const abnormalRow=ref({}) | ||||||
| const inputLotNo=async (data)=>{ | const inputLotNo=async (data)=>{ | ||||||
|  |   if (createForm.value.lotNo<=25000){ | ||||||
|  |     return | ||||||
|  |   } | ||||||
| const res=await offlineQrcodeList({ | const res=await offlineQrcodeList({ | ||||||
|   lotNo:createForm.value.lotNo |   lotNo:createForm.value.lotNo-25000 | ||||||
| }) | }) | ||||||
|   if (res.status===0){ |   if (res.status===0){ | ||||||
|     if (res.data.Data?.length>0){ |     if (res.data.Data?.length>0){ | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ import {codeAuthStore} from "~/stores-collect-code/auth/index.js"; | |||||||
| import {useI18n} from "vue-i18n"; | import {useI18n} from "vue-i18n"; | ||||||
| 
 | 
 | ||||||
| const {t} = useI18n(); | const {t} = useI18n(); | ||||||
| const {checkoutSessionUrl,qrUid,qrData} = codeAuthStore() | const {checkoutSessionUrl,qrUid,qrData,codePKey,codePayUid} = codeAuthStore() | ||||||
| const payStatus = ref(0) | const payStatus = ref(0) | ||||||
| definePageMeta({ | definePageMeta({ | ||||||
|   i18n: 'payment.title' |   i18n: 'payment.title' | ||||||
| @ -19,6 +19,7 @@ const changePayStatus = () => { | |||||||
|   payStatus.value = payStatus.value === 0 ? 1 : 0 |   payStatus.value = payStatus.value === 0 ? 1 : 0 | ||||||
| } | } | ||||||
| const amount = ref('') | const amount = ref('') | ||||||
|  | const router = useRouter() | ||||||
| const confirmPay = async () => { | const confirmPay = async () => { | ||||||
|   if (payStatus.value === 1 && !amount.value) { |   if (payStatus.value === 1 && !amount.value) { | ||||||
|     message.warning(t('collectCode.payment.enterAmount')) |     message.warning(t('collectCode.payment.enterAmount')) | ||||||
| @ -40,7 +41,18 @@ const confirmPay = async () => { | |||||||
|     testReturnEndPoint: '/collectCode/payment/result' |     testReturnEndPoint: '/collectCode/payment/result' | ||||||
|   }) |   }) | ||||||
|   if (res.status === 0) { |   if (res.status === 0) { | ||||||
|     window.location.href = res.data.checkoutSessionUrl |     codePKey.value=res.data.checkoutSessionUrl | ||||||
|  |     codePayUid.value=res.data.payUid | ||||||
|  |     router.push({ | ||||||
|  |       path:'/checkoutPage', | ||||||
|  |       query:{ | ||||||
|  |         payUid:res.data.payUid, | ||||||
|  |         returnUrl:'/collectCode/payment/result', | ||||||
|  |         stripeKey:res.data.checkoutSessionUrl | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  | 
 | ||||||
|  |    | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -76,7 +88,7 @@ const handleInput = (e) => { | |||||||
|     </div> |     </div> | ||||||
|     <div class="mb-12px" v-else> |     <div class="mb-12px" v-else> | ||||||
|              <input v-model="amount" class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" |              <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"> |              :placeholder="`${$t('collectCode.payment.maxAmount')} ${qrData.currency} ${qrData?.leftPrice}`" @input="handleInput"> | ||||||
|     </div> |     </div> | ||||||
|     <div class="text-#2B53AC text-14px" @click="changePayStatus">{{ payStatus === 1 ? $t('collectCode.payment.fullPayment') : $t('collectCode.payment.partialPayment') }}</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"> |     <div class="w-full mt-auto mb-40px"> | ||||||
|  | |||||||
| @ -39,7 +39,6 @@ const fetchPmblPdf = async () => { | |||||||
|     }) |     }) | ||||||
|     pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中 |     pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中 | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('获取拍卖笔录失败:', error) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,7 +8,6 @@ definePageMeta({ | |||||||
|   i18n: 'countryRegion.title', |   i18n: 'countryRegion.title', | ||||||
| }) | }) | ||||||
| const router = useRouter() | const router = useRouter() | ||||||
| console.log('router',router) |  | ||||||
| const { t, locale } = useI18n() | const { t, locale } = useI18n() | ||||||
| const value = ref(''); | const value = ref(''); | ||||||
| const alphabet = computed(() => { | const alphabet = computed(() => { | ||||||
| @ -144,7 +143,6 @@ const handleCountrySelect = (country) => { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| initData() | initData() | ||||||
| console.log('searchCountry',searchCountry.value) |  | ||||||
| // 监听语言变化,重新初始化数据 | // 监听语言变化,重新初始化数据 | ||||||
| watch(locale, () => { | watch(locale, () => { | ||||||
|   initData() |   initData() | ||||||
|  | |||||||
| @ -40,6 +40,26 @@ const openShow = async (item) => { | |||||||
|   localState.value.showDetail = true |   localState.value.showDetail = true | ||||||
|   currentItem.value = item |   currentItem.value = item | ||||||
| } | } | ||||||
|  | /** | ||||||
|  |  * 将数字格式化为"250XX"格式,其中XX是两位数 | ||||||
|  |  * @param {number} num - 要格式化的数字 | ||||||
|  |  * @return {string} - 格式化后的字符串 | ||||||
|  |  */ | ||||||
|  |  function formatNumber(num) { | ||||||
|  |   // 确保输入是有效数字 | ||||||
|  |   if (typeof num !== 'number' && isNaN(Number(num))) { | ||||||
|  |     throw new Error('输入必须是有效数字'); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // 转换为数字类型(以防输入是字符串数字) | ||||||
|  |   const number = Number(num); | ||||||
|  |    | ||||||
|  |   // 数字部分格式化为两位数,不足补0 | ||||||
|  |   const formattedNum = number.toString().padStart(2, '0'); | ||||||
|  |    | ||||||
|  |   // 添加前缀"250"并返回结果 | ||||||
|  |   return `250${formattedNum}`; | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
| @ -73,7 +93,7 @@ const openShow = async (item) => { | |||||||
|                   <div |                   <div | ||||||
|                       class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[55px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]" |                       class="absolute rounded-2px overflow-hidden line-height-12px left-[8px] top-[8px] h-[17px] w-[55px] flex items-center justify-center bg-[#2b53ac] text-[12px] text-[#fff]" | ||||||
|                   > |                   > | ||||||
|                     Lot{{ item.index }} |                     Lot{{ formatNumber(item.index) }} | ||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                 </div> | ||||||
|                 <div class="pt-[8px]"> |                 <div class="pt-[8px]"> | ||||||
|  | |||||||
| @ -30,7 +30,6 @@ const captureVideoFrame = () => { | |||||||
|   try { |   try { | ||||||
|     const video = document.querySelector('#J_prismPlayer video') |     const video = document.querySelector('#J_prismPlayer video') | ||||||
|     if (!video) { |     if (!video) { | ||||||
|       console.error('未找到视频元素') |  | ||||||
|       return null |       return null | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -42,7 +41,6 @@ const captureVideoFrame = () => { | |||||||
|     ctx.drawImage(video, 0, 0, canvas.width, canvas.height) |     ctx.drawImage(video, 0, 0, canvas.width, canvas.height) | ||||||
|     return canvas.toDataURL('image/jpeg', 0.9) |     return canvas.toDataURL('image/jpeg', 0.9) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('获取视频截图失败:', error) |  | ||||||
|     return null |     return null | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -118,7 +118,6 @@ const captureVideoFrame = () => { | |||||||
|   try { |   try { | ||||||
|     const video = document.querySelector('#J_prismPlayer video') |     const video = document.querySelector('#J_prismPlayer video') | ||||||
|     if (!video) { |     if (!video) { | ||||||
|       console.error('未找到视频元素') |  | ||||||
|       return null |       return null | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -130,7 +129,6 @@ const captureVideoFrame = () => { | |||||||
|     ctx.drawImage(video, 0, 0, canvas.width, canvas.height) |     ctx.drawImage(video, 0, 0, canvas.width, canvas.height) | ||||||
|     return canvas.toDataURL('image/jpeg', 0.9) |     return canvas.toDataURL('image/jpeg', 0.9) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('获取视频截图失败:', error) |  | ||||||
|     return null |     return null | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -144,7 +142,6 @@ const handleCapture = () => { | |||||||
|       onClick:()=>{ |       onClick:()=>{ | ||||||
|         router.replace('/') |         router.replace('/') | ||||||
|         fullLive.value=true |         fullLive.value=true | ||||||
|         console.log('执行') |  | ||||||
|         } |         } | ||||||
|     })*!/ |     })*!/ | ||||||
|   }*/ |   }*/ | ||||||
|  | |||||||
| @ -66,8 +66,7 @@ const loadMore = async () => { | |||||||
| watch(()=>{ | watch(()=>{ | ||||||
|   return auctionData.value?.artwork?.index |   return auctionData.value?.artwork?.index | ||||||
| },(newValue)=>{ | },(newValue)=>{ | ||||||
|   console.log('newValue',newValue) |   }) | ||||||
| }) |  | ||||||
| watch(()=>props.show,(newValue)=>{ | watch(()=>props.show,(newValue)=>{ | ||||||
|   if (newValue){ |   if (newValue){ | ||||||
|  nextTick(()=>{ |  nextTick(()=>{ | ||||||
|  | |||||||
| @ -19,7 +19,6 @@ 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 pullLink = ref('') | const pullLink = ref('') | ||||||
| const handlePlayerError = (error) => { | const handlePlayerError = (error) => { | ||||||
|   console.error('播放器错误:', error) |  | ||||||
|   showConfirmDialog({ |   showConfirmDialog({ | ||||||
|     message: t('live_room.error_mess'), |     message: t('live_room.error_mess'), | ||||||
|     showCancelButton: true |     showCancelButton: true | ||||||
| @ -81,7 +80,6 @@ const initializePlayer = async () => { | |||||||
| 
 | 
 | ||||||
|     }) |     }) | ||||||
|     player.value.on('loading', () => { |     player.value.on('loading', () => { | ||||||
|       console.log('loading') |  | ||||||
|       }) |       }) | ||||||
|     player.value.on('error', handlePlayerError) |     player.value.on('error', handlePlayerError) | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
| @ -92,7 +90,6 @@ const initializePlayer = async () => { | |||||||
|      initializePlayer() |      initializePlayer() | ||||||
|     }).catch(() => { |     }).catch(() => { | ||||||
|     }) |     }) | ||||||
|     console.error('播放器初始化失败:', error) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ const loadingRef=ref({ | |||||||
| }) | }) | ||||||
| const isExist=ref(false)//帐号是否存在  true存在 | const isExist=ref(false)//帐号是否存在  true存在 | ||||||
| const isReal=ref(false) //isReal 是否实名过 | const isReal=ref(false) //isReal 是否实名过 | ||||||
|  | const codeInput=ref(null) | ||||||
| function goToPage() { | function goToPage() { | ||||||
|   router.push('/countryRegion'); |   router.push('/countryRegion'); | ||||||
| } | } | ||||||
| @ -40,11 +41,9 @@ const countdown = ref(0); | |||||||
| const phoneNum = ref('') | const phoneNum = ref('') | ||||||
| const code = ref('') | const code = ref('') | ||||||
| const pane = ref(0) | const pane = ref(0) | ||||||
| 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' | ||||||
| @ -74,7 +73,6 @@ const defaultCountry = getDefaultCountry() | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| const selectedCountry = ref(route.query.countryName || defaultCountry.name) | const selectedCountry = ref(route.query.countryName || defaultCountry.name) | ||||||
| console.log('selectedCountry',selectedCountry.value) |  | ||||||
| onMounted(()=>{ | onMounted(()=>{ | ||||||
|   selectedZone.value=route.query.zone || defaultCountry.zone |   selectedZone.value=route.query.zone || defaultCountry.zone | ||||||
| }) | }) | ||||||
| @ -100,13 +98,8 @@ const getCode =async () => { | |||||||
|   } |   } | ||||||
|   pane.value = 1 |   pane.value = 1 | ||||||
|   vanSwipeRef.value?.swipeTo(pane.value) |   vanSwipeRef.value?.swipeTo(pane.value) | ||||||
|   showKeyboard.value=true |  | ||||||
|   startCountdown(); |  | ||||||
| /*  pane.value = 1 |  | ||||||
|   vanSwipeRef.value?.swipeTo(pane.value) |  | ||||||
|   showKeyboard.value=true |  | ||||||
|   startCountdown();*/ |  | ||||||
|   |   | ||||||
|  |   startCountdown(); | ||||||
| } | } | ||||||
| const goBack = () => { | const goBack = () => { | ||||||
|   code.value = '' |   code.value = '' | ||||||
| @ -136,7 +129,6 @@ const goLogin =async () => { | |||||||
|       if (res1.status===0){ |       if (res1.status===0){ | ||||||
|         window.location.href=res1.data.h5Url |         window.location.href=res1.data.h5Url | ||||||
|       } |       } | ||||||
|       console.log('123') |  | ||||||
|       }else { |       }else { | ||||||
|       await router.push('/'); |       await router.push('/'); | ||||||
|     } |     } | ||||||
| @ -145,7 +137,7 @@ const goLogin =async () => { | |||||||
| } | } | ||||||
| const isKeyboardVisible = ref(false) | const isKeyboardVisible = ref(false) | ||||||
| const windowHeight = ref(window.innerHeight) | const windowHeight = ref(window.innerHeight) | ||||||
| 
 | const isFocused = ref(false) | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|   // 记录初始窗口高度 |   // 记录初始窗口高度 | ||||||
|   windowHeight.value = window.innerHeight |   windowHeight.value = window.innerHeight | ||||||
| @ -163,7 +155,7 @@ onUnmounted(() => { | |||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <div class="h-screen-nav w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-cover px-[31px] pt-[86px]"> |   <div class="w-[100vw] bg-[url('@/static/images/asdfsdd.png')] bg-bottom bg-cover grow-1 px-[31px] pt-[86px]"> | ||||||
|     <div class="w-full flex justify-center mb-[100px]"> |     <div class="w-full flex justify-center mb-[100px]"> | ||||||
|       <img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt=""> |       <img class="h-[105px] w-[189px]" src="@/static/images/ghfggff.png" alt=""> | ||||||
|     </div> |     </div> | ||||||
| @ -186,7 +178,6 @@ onUnmounted(() => { | |||||||
|                 </template> |                 </template> | ||||||
|               </van-field> |               </van-field> | ||||||
|             </div> |             </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> |             <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> | ||||||
| @ -200,7 +191,24 @@ onUnmounted(() => { | |||||||
|             <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" /> |           <div class="relative"> | ||||||
|  |         <van-password-input | ||||||
|  |   :value="code" | ||||||
|  |   :gutter="10" | ||||||
|  |   :mask="false" | ||||||
|  |   :focused="isFocused" | ||||||
|  | /> | ||||||
|  | <input | ||||||
|  |   v-model="code" | ||||||
|  |   type="tel" | ||||||
|  |   maxlength="6" | ||||||
|  |    ref="codeInput" | ||||||
|  |   class="opacity-0 absolute top-0 left-0 h-full w-full" | ||||||
|  |   @input="code = $event.target.value.replace(/\D/g, '').slice(0, 6)" | ||||||
|  |   @focus="isFocused = true" | ||||||
|  |   @blur="isFocused = false" | ||||||
|  | /> | ||||||
|  |       </div> | ||||||
|           <div class="flex justify-between"> |           <div class="flex justify-between"> | ||||||
|             <div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'}  text-14px`"> |             <div :class="`${countdown>0?'text-#BDBDBD':'text-#2B53AC'}  text-14px`"> | ||||||
|               {{ $t('login.reSend') }}<span v-if="countdown>0">({{countdown}})</span> |               {{ $t('login.reSend') }}<span v-if="countdown>0">({{countdown}})</span> | ||||||
| @ -216,7 +224,6 @@ onUnmounted(() => { | |||||||
|         </div> |         </div> | ||||||
|       </van-swipe-item> |       </van-swipe-item> | ||||||
|     </van-swipe> |     </van-swipe> | ||||||
|     <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"> |     <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> |       {{ $t('login.agreement') }}<span class="text-#3454AF " @click="$router.push('/privacyPolicy')">{{ $t('login.privacyPolicy') }}</span> | ||||||
|     </div> |     </div> | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ import {createBuyOrder} from "~/api/goods/index.js"; | |||||||
| import {goodStore} from "~/stores/goods/index.js"; | import {goodStore} from "~/stores/goods/index.js"; | ||||||
| import { showLoadingToast ,closeToast} from 'vant'; | import { showLoadingToast ,closeToast} from 'vant'; | ||||||
| import {authStore} from "~/stores/auth/index.js"; | import {authStore} from "~/stores/auth/index.js"; | ||||||
|  | 
 | ||||||
| import {message} from "~/components/x-message/useMessage.js"; | import {message} from "~/components/x-message/useMessage.js"; | ||||||
| const {checkoutSessionUrl,payment,payUid}= authStore() | const {checkoutSessionUrl,payment,payUid}= authStore() | ||||||
| const payStatus=ref(0) | const payStatus=ref(0) | ||||||
| @ -38,14 +39,18 @@ const confirmPay=async ()=>{ | |||||||
|    testReturnHost:window.location.origin, |    testReturnHost:window.location.origin, | ||||||
|    testReturnEndPoint:'/payment/result' |    testReturnEndPoint:'/payment/result' | ||||||
|  }) |  }) | ||||||
|  console.log('res',res); | 
 | ||||||
|  if (res.status===0){ |  if (res.status===0){ | ||||||
|   // if (res.status===0){ |  | ||||||
|   //   window.location.href=res.data.checkoutSessionUrl |  | ||||||
|   // } |  | ||||||
|   checkoutSessionUrl.value=res.data.checkoutSessionUrl |   checkoutSessionUrl.value=res.data.checkoutSessionUrl | ||||||
|   payUid.value=res.data.payUid |   payUid.value=res.data.payUid | ||||||
|   router.push('/payment/checkoutPage') |   router.push({ | ||||||
|  |     path:'/checkoutPage', | ||||||
|  |     query:{ | ||||||
|  |       payUid:res.data.payUid, | ||||||
|  |       returnUrl:'/payment/result', | ||||||
|  |       stripeKey:res.data.checkoutSessionUrl | ||||||
|  |     } | ||||||
|  |   }) | ||||||
| } | } | ||||||
| } | } | ||||||
| const handleInput = (e) => { | const handleInput = (e) => { | ||||||
|  | |||||||
| @ -14,6 +14,13 @@ let timer = null | |||||||
| let startTime = Date.now() | let startTime = Date.now() | ||||||
| 
 | 
 | ||||||
| const queryOrder = async () => { | const queryOrder = async () => { | ||||||
|  |   // 首先检查是否已经超过5秒 | ||||||
|  |   if (Date.now() - startTime > 5000) { | ||||||
|  |     clearInterval(timer) | ||||||
|  |     closeToast() | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   showLoadingToast({ |   showLoadingToast({ | ||||||
|     message: '加载中...', |     message: '加载中...', | ||||||
|     forbidClick: true, |     forbidClick: true, | ||||||
| @ -27,8 +34,8 @@ const queryOrder = async () => { | |||||||
|     if (res.status === 0) { |     if (res.status === 0) { | ||||||
|       resData.value = res.data |       resData.value = res.data | ||||||
| 
 | 
 | ||||||
|       // 如果状态为1或者超过5秒,停止轮询 |       // 只在支付成功时停止轮询 | ||||||
|       if (resData.value.status === 1 || Date.now() - startTime > 5000) { |       if (resData.value.status === 1) { | ||||||
|         clearInterval(timer) |         clearInterval(timer) | ||||||
|         closeToast() |         closeToast() | ||||||
|       } |       } | ||||||
| @ -68,11 +75,12 @@ const goHome = () => { | |||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|   <div class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px"> |   <div | ||||||
|  |       class="w-[100vw] h-screen-nav bg-[url('@/static/images/3532@2x.png')] bg-cover grow-1 flex flex-col items-center px-30px"> | ||||||
|     <div class="flex flex-col items-center mt-150px"> |     <div class="flex flex-col items-center mt-150px"> | ||||||
|       <img class="w-119px h-120px mb-36px" src="@/static/images/5554@2x1.png" alt=""> |       <img 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-#000 text-16px mb-25px">{{ statusLabel[resData.status] }}!</div> | ||||||
|       <div class="text-#999 text-16px">{{resData.currency}}{{resData.money}}</div> |       <div class="text-#999 text-16px">{{ resData.currency }}{{ resData.money }}</div> | ||||||
|     </div> |     </div> | ||||||
|     <div class="w-full mt-auto mb-40px"> |     <div class="w-full mt-auto mb-40px"> | ||||||
|       <van-button type="primary" block @click="goHome"> |       <van-button type="primary" block @click="goHome"> | ||||||
|  | |||||||
| @ -37,7 +37,6 @@ const fetchData = async () => { | |||||||
|       showMyList.value = groupByDate(res.data.data) |       showMyList.value = groupByDate(res.data.data) | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('获取数据失败:', error) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -33,7 +33,6 @@ const fetchPmblPdf = async () => { | |||||||
|     }) |     }) | ||||||
|     pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中 |     pmblUrl.value = res.data?.viewUrl // 假设接口返回的PDF URL在data字段中 | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('获取拍卖笔录失败:', error) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| import { setupHttp } from '@/api/http' | import { setupHttp } from '@/api/http' | ||||||
| 
 | import { setupHttp as  setupHttp1} from '@/api-collect-code/http' | ||||||
| export default defineNuxtPlugin(() => { | export default defineNuxtPlugin(() => { | ||||||
|   setupHttp() |   setupHttp() | ||||||
|  |   setupHttp1() | ||||||
| }) | }) | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| import { createGlobalState,useLocalStorage } from '@vueuse/core' | import { createGlobalState,useLocalStorage } from '@vueuse/core' | ||||||
| export const codeAuthStore = createGlobalState(() => { | export const codeAuthStore = createGlobalState(() => { | ||||||
|     const token=useLocalStorage('token','') |     const codeToken=useLocalStorage('codeToken','') | ||||||
|     const RefreshToken=useLocalStorage('RefreshToken','') |     const RefreshToken=useLocalStorage('RefreshToken','') | ||||||
|     const userInfo=useLocalStorage('userInfo',{}) |     const userInfo=useLocalStorage('userInfo',{}) | ||||||
|     const fingerprint=useLocalStorage('fingerprint','') |     const fingerprint=useLocalStorage('fingerprint','') | ||||||
| @ -26,7 +26,11 @@ export const codeAuthStore = createGlobalState(() => { | |||||||
|         currency:'' |         currency:'' | ||||||
|     }) |     }) | ||||||
|     const qrData=useLocalStorage('qrData',{}) |     const qrData=useLocalStorage('qrData',{}) | ||||||
|  |     const codePKey=useLocalStorage('codePKey','') | ||||||
|  |     const codePayUid=useLocalStorage('codePayUid','') | ||||||
|     return{ |     return{ | ||||||
|  |         codePKey, | ||||||
|  |         codePayUid, | ||||||
|         qrData, |         qrData, | ||||||
|         qrUid, |         qrUid, | ||||||
|         cpayment, |         cpayment, | ||||||
| @ -37,7 +41,7 @@ export const codeAuthStore = createGlobalState(() => { | |||||||
|         formData, |         formData, | ||||||
|         userInfo, |         userInfo, | ||||||
|         RefreshToken, |         RefreshToken, | ||||||
|         token, |         codeToken, | ||||||
|         fingerprint |         fingerprint | ||||||
|     } |     } | ||||||
| }) | }) | ||||||
| @ -1,4 +1,7 @@ | |||||||
| import { createGlobalState,useLocalStorage } from '@vueuse/core' | import { createGlobalState,useLocalStorage } from '@vueuse/core' | ||||||
|  | import { WebSocketClient } from '@/utils/websocket' | ||||||
|  | import {message} from "~/components/x-message/useMessage.js"; | ||||||
|  | 
 | ||||||
| export const authStore = createGlobalState(() => { | export const authStore = createGlobalState(() => { | ||||||
|     const token=useLocalStorage('token','') |     const token=useLocalStorage('token','') | ||||||
|     const RefreshToken=useLocalStorage('RefreshToken','') |     const RefreshToken=useLocalStorage('RefreshToken','') | ||||||
|  | |||||||
| @ -34,7 +34,6 @@ export const goodStore = createGlobalState(() => { | |||||||
|                 auctionDetail.value = res.data |                 auctionDetail.value = res.data | ||||||
|             } |             } | ||||||
|         } catch (err) { |         } catch (err) { | ||||||
|             console.error('获取拍卖详情错误:', err) |  | ||||||
|             } finally { |             } finally { | ||||||
|             loading.value = false |             loading.value = false | ||||||
|         } |         } | ||||||
| @ -69,7 +68,6 @@ export const goodStore = createGlobalState(() => { | |||||||
|             } |             } | ||||||
|             return { finished: true, items: [] } |             return { finished: true, items: [] } | ||||||
|         } catch (err) { |         } catch (err) { | ||||||
|             console.error('获取艺术品列表错误:', err) |  | ||||||
|             return { finished: true, items: [] } |             return { finished: true, items: [] } | ||||||
|         } finally { |         } finally { | ||||||
|             loading.value = false |             loading.value = false | ||||||
| @ -85,7 +83,6 @@ export const goodStore = createGlobalState(() => { | |||||||
|                 artWorkDetail.value = res.data |                 artWorkDetail.value = res.data | ||||||
|             } |             } | ||||||
|         } catch (err) { |         } catch (err) { | ||||||
|             console.error('获取艺术品详情错误:', err) |  | ||||||
|             } finally { |             } finally { | ||||||
|             loading.value = false |             loading.value = false | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -197,12 +197,10 @@ export const liveStore = createGlobalState(() => { | |||||||
| 
 | 
 | ||||||
|         // WebSocket 事件处理
 |         // WebSocket 事件处理
 | ||||||
|         ws.onOpen(() => { |         ws.onOpen(() => { | ||||||
|             console.log('WebSocket connected') |  | ||||||
|             }) |             }) | ||||||
| 
 | 
 | ||||||
|         ws.onMessage((data) => { |         ws.onMessage((data) => { | ||||||
|             auctionData.value = data.data |             auctionData.value = data.data | ||||||
|             console.log(' auctionData.value', auctionData.value) |  | ||||||
|             const { wsType, tip } = data.data || {} |             const { wsType, tip } = data.data || {} | ||||||
| 
 | 
 | ||||||
|             switch (wsType) { |             switch (wsType) { | ||||||
| @ -210,13 +208,11 @@ export const liveStore = createGlobalState(() => { | |||||||
|                     handleTipMessage(tip?.tipType) |                     handleTipMessage(tip?.tipType) | ||||||
|                     break |                     break | ||||||
|                 case WS_TYPES.STOP_ARTWORK: |                 case WS_TYPES.STOP_ARTWORK: | ||||||
|                     console.log('changeQuote',quoteStatus.value) |  | ||||||
|                     //quoteStatus.value = false
 |                     //quoteStatus.value = false
 | ||||||
|                     break |                     break | ||||||
|                 case WS_TYPES.OVER: |                 case WS_TYPES.OVER: | ||||||
| 
 | 
 | ||||||
|                     quoteStatus.value = false |                     quoteStatus.value = false | ||||||
|                     console.log('changeQuote',quoteStatus.value) |  | ||||||
|                     message.success(createMessageConfig( |                     message.success(createMessageConfig( | ||||||
|                         t('live_room.text10'), |                         t('live_room.text10'), | ||||||
|                         '#575757', |                         '#575757', | ||||||
| @ -230,15 +226,12 @@ export const liveStore = createGlobalState(() => { | |||||||
|                     break |                     break | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             console.log('onmessage', data) |  | ||||||
|             }) |             }) | ||||||
| 
 | 
 | ||||||
|         ws.onClose(() => { |         ws.onClose(() => { | ||||||
|             console.log('WebSocket disconnected') |  | ||||||
|             }) |             }) | ||||||
| 
 | 
 | ||||||
|         ws.onError((error) => { |         ws.onError((error) => { | ||||||
|             console.error('WebSocket error:', error) |  | ||||||
|             }) |             }) | ||||||
|     } |     } | ||||||
|     const changeStatus = () => { |     const changeStatus = () => { | ||||||
| @ -249,7 +242,6 @@ export const liveStore = createGlobalState(() => { | |||||||
|                 quoteStatus.value = false |                 quoteStatus.value = false | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         console.log('changeQuote',quoteStatus.value) |  | ||||||
|         } |         } | ||||||
|     return{ |     return{ | ||||||
|         fullLive, |         fullLive, | ||||||
|  | |||||||
| @ -423,7 +423,7 @@ | |||||||
|       "fullPayment": "Pay in Full", |       "fullPayment": "Pay in Full", | ||||||
|       "partialPayment": "Partial Payment", |       "partialPayment": "Partial Payment", | ||||||
|       "confirmPayment": "Confirm Payment", |       "confirmPayment": "Confirm Payment", | ||||||
|       "maxAmount": "Maximum {currency}{price}", |       "maxAmount": "most", | ||||||
|       "enterAmount": "Please enter amount", |       "enterAmount": "Please enter amount", | ||||||
|       "exceedTotal": "Cannot exceed total amount" |       "exceedTotal": "Cannot exceed total amount" | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -423,7 +423,7 @@ | |||||||
|       "fullPayment": "全額支払い", |       "fullPayment": "全額支払い", | ||||||
|       "partialPayment": "一部支払い", |       "partialPayment": "一部支払い", | ||||||
|       "confirmPayment": "支払い確認", |       "confirmPayment": "支払い確認", | ||||||
|       "maxAmount": "最大 {currency}{price}", |       "maxAmount": "ほとんど", | ||||||
|       "enterAmount": "金額を入力してください", |       "enterAmount": "金額を入力してください", | ||||||
|       "exceedTotal": "合計金額を超えることはできません" |       "exceedTotal": "合計金額を超えることはできません" | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -426,7 +426,8 @@ | |||||||
|       "confirmPayment": "确认支付", |       "confirmPayment": "确认支付", | ||||||
|       "text1": "最多", |       "text1": "最多", | ||||||
|       "enterAmount": "请输入金额", |       "enterAmount": "请输入金额", | ||||||
|       "exceedTotal": "不得高于全部金额" |       "exceedTotal": "不得高于全部金额", | ||||||
|  |       "maxAmount": "最多" | ||||||
|     }, |     }, | ||||||
|     "signature": { |     "signature": { | ||||||
|       "resultText": "领取您的专属号牌", |       "resultText": "领取您的专属号牌", | ||||||
|  | |||||||
| @ -423,7 +423,7 @@ | |||||||
|       "fullPayment": "支付全部", |       "fullPayment": "支付全部", | ||||||
|       "partialPayment": "支付部分", |       "partialPayment": "支付部分", | ||||||
|       "confirmPayment": "確認支付", |       "confirmPayment": "確認支付", | ||||||
|       "maxAmount": "最多{currency}{price}", |       "maxAmount": "最多", | ||||||
|       "enterAmount": "請輸入金額", |       "enterAmount": "請輸入金額", | ||||||
|       "exceedTotal": "不得高於全部金額" |       "exceedTotal": "不得高於全部金額" | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| import dotenv from 'dotenv' | import dotenv from 'dotenv' | ||||||
| import process from 'node:process' | import process from 'node:process' | ||||||
| import { currentLocales } from './i18n/i18n' | import { currentLocales } from './i18n/i18n' | ||||||
|  | import fs from 'fs' | ||||||
|  | import path from 'path' | ||||||
| const envFile = process.env.ENV_FILE || '.env.test' | const envFile = process.env.ENV_FILE || '.env.test' | ||||||
| dotenv.config({ path: `./env/${envFile}` }) | dotenv.config({ path: `./env/${envFile}` }) | ||||||
| const publicConfig = Object.entries(process.env) | const publicConfig = Object.entries(process.env) | ||||||
| @ -10,6 +12,19 @@ const publicConfig = Object.entries(process.env) | |||||||
|       return config |       return config | ||||||
|     }, {}) |     }, {}) | ||||||
| 
 | 
 | ||||||
|  | let httpsOptions = {} | ||||||
|  | 
 | ||||||
|  | try { | ||||||
|  |   // 读取文件并转换为字符串
 | ||||||
|  |   const key = fs.readFileSync(path.resolve(__dirname, 'ssl/localhost-key.pem'), 'utf-8') | ||||||
|  |   const cert = fs.readFileSync(path.resolve(__dirname, 'ssl/localhost.pem'), 'utf-8') | ||||||
|  |    | ||||||
|  |   httpsOptions = { key, cert } | ||||||
|  |   } catch (error) { | ||||||
|  |   // 失败时使用HTTP
 | ||||||
|  |   httpsOptions = false | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default defineNuxtConfig({ | export default defineNuxtConfig({ | ||||||
|   modules: [ |   modules: [ | ||||||
|     '@vant/nuxt', |     '@vant/nuxt', | ||||||
| @ -136,7 +151,8 @@ export default defineNuxtConfig({ | |||||||
|   // 指定 Nuxt 应用程序的兼容性日期,确保应用程序在未来的 Nuxt 版本中保持稳定性
 |   // 指定 Nuxt 应用程序的兼容性日期,确保应用程序在未来的 Nuxt 版本中保持稳定性
 | ||||||
|   compatibilityDate: '2025-02-28', |   compatibilityDate: '2025-02-28', | ||||||
|   devServer: { |   devServer: { | ||||||
|     host: '0.0.0.0', // Set the host to 'localhost'
 |     // https: httpsOptions,
 | ||||||
|     port: 3000,        // Set the port to 3000 or any other port you prefer
 |     host: '0.0.0.0', | ||||||
|  |     port: 3000, | ||||||
|   }, |   }, | ||||||
| }) | }) | ||||||
							
								
								
									
										25
									
								
								server/middleware/stripe.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								server/middleware/stripe.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | export default defineEventHandler(async (event) => { | ||||||
|  |   const url = getRequestURL(event) | ||||||
|  |    | ||||||
|  |   // 只处理 create-payment-intent 请求
 | ||||||
|  |   if (url.pathname === '/create-payment-intent' && event.method === 'POST') { | ||||||
|  |     try { | ||||||
|  |       const body = await readBody(event) | ||||||
|  |       const { items } = body | ||||||
|  |        | ||||||
|  |       // 计算总金额
 | ||||||
|  |       const amount = items.reduce((total: number, item: any) => total + item.amount, 0) | ||||||
|  |        | ||||||
|  |       // 模拟创建支付意向的响应
 | ||||||
|  |       // 注意:clientSecret 格式应该类似于 'pi_xxxxx_secret_xxxxx'
 | ||||||
|  |       return { | ||||||
|  |         clientSecret: `pi_${Math.random().toString(36).substring(2)}_secret_${Math.random().toString(36).substring(2)}` | ||||||
|  |       } | ||||||
|  |     } catch (error) { | ||||||
|  |       throw createError({ | ||||||
|  |         statusCode: 500, | ||||||
|  |         message: '创建支付意向失败' | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | })  | ||||||
							
								
								
									
										28
									
								
								ssl/localhost-key.pem
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								ssl/localhost-key.pem
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | -----BEGIN PRIVATE KEY----- | ||||||
|  | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFtE2AWs1o0X/A | ||||||
|  | 0+506WAG49xbO3KJQTWKwHl5pfeP0GieVjV3qKXkHXl9Fyhg9oJnCAz2nzxzavAP | ||||||
|  | W9NevDbX7KdEiZQjDhpgO+V9IGUqqJKEQnpVk57G3fHBX40nQ4zAQ/S1Vj4Aw9Tk | ||||||
|  | iqNFgLRX3HTAT0NO3eXENJbsDdGxtOuLn5h+DWThrqCaUK2Xnkee3eG/VwgKJKVH | ||||||
|  | LWuC8xyb1NydtchaRFBjoO9oT6Tb/MGeBOrNH9e7Ndh9mCFepXUhzNxrN1fKjn9s | ||||||
|  | 107pSEeZb4il2K7GqE0W6r6Y3eeBR2+mEBRqeFnZObT0JkBLI2QIrAwOnFO6ObQC | ||||||
|  | ZaEjwHcZAgMBAAECggEASMZB8Ql7qyXS3OwmTqrJSj/+ESck1hlG2DhZfsn1At84 | ||||||
|  | Y3BgZheSWRHwcndfybFz9vEjtHSRD/tBOqYWfDzUA099kuEBwpWiZ+Ika5bNJpK+ | ||||||
|  | vCisV2vrelCgeQnvL5DR8sQRA98nG6j6aNYPm7nwqJbh8xg6MoHD3iFtnJ7JnZvQ | ||||||
|  | pSa6Z9qq4Po+cp63/U3yEzFeiVVDTMQJMVClANUCX3jLHs8B85WMbb1eKKFe/xCA | ||||||
|  | n2BWlFVI7Hld+hxhKWkc71+kafC5hUz1w88FcBaN2W/DAtJgKC0dHYATwLCUGC4Z | ||||||
|  | CoCZfB7b3JOzK4mGJ/XxxUcBUk+oweExOrYwCfW4MQKBgQDJbTM4qgW2ca/Xc7cp | ||||||
|  | zKvclgtkJ8rWbVZqMYW6fpXoOdhhxjJSx+LfeGk1whz3Xj04EdSZbRI6zYVaHfHa | ||||||
|  | HFkA2Na/Wi9hboid4WVXUi5RXzthVTOYi1jAJNmK4R25wuSdcGVoYxSrSLyDcHbx | ||||||
|  | MF2cFdQ4A386L+RcoDYzImWCXwKBgQD7RO4DZJgkqDng6YFrYqIdQkJn6keXl4yW | ||||||
|  | Hq1FGaa7XDjlun/X2jT0xJJPFcwLQLbWwrkwmUYN/VQEbYwYlyB0MegF9VflfILl | ||||||
|  | /leCXC8/9WEknQkPqu8N1JiYhajIKLxfQX35nW/oK+S5prJOBxNw+3Of/S43R5Xe | ||||||
|  | 60EEI9iphwKBgQCrs/Sn5vd7sKnOpYuLjDcskJMhS3JzGz1AxPpUIbgz/6tenY8k | ||||||
|  | VdQl3wUAmHoMvD6/XyO1re6ORcfZLBGQdf3A5RcagwxEp+65dvvmVd256844iGK1 | ||||||
|  | NIPxNvhilMe8JFCxjLBFLcDeyeA4w1QBAdOqTEldfk2kElM+SiwppraVTQKBgCUP | ||||||
|  | O5OgiJgPf8neZsox1/s8xJKTCVAgeAnEKIYijGbh6Tpo0WZCtsDLJVEow9l9B/qQ | ||||||
|  | 6cNzN9PkYznr9lfCInVAzxnh377nKF9Hrhx6ADYMuPEvgCChc3S0wHTuccBj0bSy | ||||||
|  | 8iOYxuKVZrzDC1Va0dE+JQWZz/EzS7V/OS2lI9WNAoGBAKujoPDn36/hJ/Zr8XAM | ||||||
|  | CEbOi0q0N7I37aRKO8Wm55SCGDYWtBlu+NiIMqk3gzgomtm/cVF+fUNv0BOKc+hx | ||||||
|  | x6PQE98AEn5LdGeqLpDY66vhyR8WGUyCBPB+Dn8OFFT+njL2E8NcQi0kS3t/YlR/ | ||||||
|  | oobyxGhm4M1fM8HtGwqQJX60 | ||||||
|  | -----END PRIVATE KEY----- | ||||||
							
								
								
									
										26
									
								
								ssl/localhost.pem
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								ssl/localhost.pem
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | -----BEGIN CERTIFICATE----- | ||||||
|  | MIIEbjCCAtagAwIBAgIRAJjJaJNy+AO5JPuasTslJMQwDQYJKoZIhvcNAQELBQAw | ||||||
|  | gZ8xHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTE6MDgGA1UECwwxREVT | ||||||
|  | S1RPUC1DOTVCMVIzXDM3MzYzQERFU0tUT1AtQzk1QjFSMyAo6YKi6Zuo5p2oKTFB | ||||||
|  | MD8GA1UEAww4bWtjZXJ0IERFU0tUT1AtQzk1QjFSM1wzNzM2M0BERVNLVE9QLUM5 | ||||||
|  | NUIxUjMgKOmCoumbqOadqCkwHhcNMjUwMzAyMDIzMzM3WhcNMjcwNjAyMDIzMzM3 | ||||||
|  | WjBlMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUxOjA4 | ||||||
|  | BgNVBAsMMURFU0tUT1AtQzk1QjFSM1wzNzM2M0BERVNLVE9QLUM5NUIxUjMgKOmC | ||||||
|  | oumbqOadqCkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFtE2AWs1o | ||||||
|  | 0X/A0+506WAG49xbO3KJQTWKwHl5pfeP0GieVjV3qKXkHXl9Fyhg9oJnCAz2nzxz | ||||||
|  | avAPW9NevDbX7KdEiZQjDhpgO+V9IGUqqJKEQnpVk57G3fHBX40nQ4zAQ/S1Vj4A | ||||||
|  | w9TkiqNFgLRX3HTAT0NO3eXENJbsDdGxtOuLn5h+DWThrqCaUK2Xnkee3eG/VwgK | ||||||
|  | JKVHLWuC8xyb1NydtchaRFBjoO9oT6Tb/MGeBOrNH9e7Ndh9mCFepXUhzNxrN1fK | ||||||
|  | jn9s107pSEeZb4il2K7GqE0W6r6Y3eeBR2+mEBRqeFnZObT0JkBLI2QIrAwOnFO6 | ||||||
|  | ObQCZaEjwHcZAgMBAAGjXjBcMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr | ||||||
|  | BgEFBQcDATAfBgNVHSMEGDAWgBQVJpbTujNcXUH/91CnxLerp/gKbDAUBgNVHREE | ||||||
|  | DTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggGBAERAae9YDQgjnVtDQUWL | ||||||
|  | kIbMowvN6BospgO2srV+aXCDLbB22jnq4cGsTpVjxo80Nl6M0iSRz29K+jy4YFsL | ||||||
|  | efTOeks1EpVQB/UnYuo391p5wzevXwa3s7dH7Oc+917y8JDiLNnSVEct+tk4zeOZ | ||||||
|  | QbVzx6Gexiii7k1uSG/G1NYrRiXf3ggM93Fyu5NM+u8CzZvWm46ix9reYimVqfPa | ||||||
|  | VjHsiQnmKbh+CD6iDWm9y1jUxqBay4cAbo2AVxIvBDdsC9KSCTsbP4hBPx9foy1U | ||||||
|  | cLRxUGsWTVPPS2BmP8o6CSa2tNPeVNCWSP89tanY2mzGErfVXLV8t5E4awF0ea+a | ||||||
|  | kbjyG3svVC6/rLo8LpFPonr4mQWfGcFntmGUC314d5z1ZCCS5ENEWAGZ3b3XzPsU | ||||||
|  | Yh2QQnt4gtvWaTRqwqhSL9DLFp106/tok3hq8MyDFcxTxWKyDZsgaieoRGnF11EW | ||||||
|  | tdIqnK9nwVOyAzaO603SuEoMiGBpb9nj/cAFsvm56YUVrg== | ||||||
|  | -----END CERTIFICATE----- | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user