feat(collect-code): 实现线下扫码支付功能
- 新增 offlineQrcode 和 createOrder 接口 - 实现个人资讯页面的数据获取和处理 - 添加支付页面,支持全款和部分款项支付 - 优化签名协议页面,使用新接口获取数据 - 新增支付结果页面,展示支付状态和金额
This commit is contained in:
parent
6836990825
commit
43b1afb8f0
@ -45,3 +45,19 @@ export async function sessionUserNoCreate(data) {
|
||||
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
|
||||
})
|
||||
}
|
@ -44,13 +44,16 @@ const displayText = computed(() => {
|
||||
const selected = props.columns.find(x => x.value === props.modelValue)
|
||||
return selected?.text || ''
|
||||
})
|
||||
const openPopup=()=>{
|
||||
show.value=true
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<van-field
|
||||
:model-value="displayText"
|
||||
@click="show = true"
|
||||
@click="openPopup"
|
||||
readonly
|
||||
:disabled="disabled"
|
||||
:required="required"
|
||||
@ -64,14 +67,14 @@ const displayText = computed(() => {
|
||||
v-model:show="show"
|
||||
destroy-on-close
|
||||
position="bottom"
|
||||
teleport="#__nuxt"
|
||||
teleport="body"
|
||||
safe-area-inset-bottom
|
||||
>
|
||||
<van-picker
|
||||
:columns="columns"
|
||||
@confirm="onConfirm"
|
||||
@cancel="show = false"
|
||||
:default-index="columns.findIndex(x => x.value === value)"
|
||||
:default-index="columns.findIndex(x => x.value === modelValue)"
|
||||
title="请选择"
|
||||
confirm-button-text="确定"
|
||||
cancel-button-text="取消"
|
||||
|
@ -4,7 +4,7 @@ import XImage from "@/components/x-image/index.vue";
|
||||
import {useRuntimeConfig} from "#app";
|
||||
import QRCode from 'qrcode'
|
||||
import { showImagePreview } from 'vant';
|
||||
import {offlineQrcodeDelete} from "~/api-collect-code/goods/index.js";
|
||||
import {offlineQrcode, offlineQrcodeDelete} from "~/api-collect-code/goods/index.js";
|
||||
|
||||
const statusLabel=[
|
||||
{label:'已付款',value:2,color:'#18A058'}, {label:'未付款',value:1,color:'#CF3050'}, {label:'已部分付款',value:4,color:'#F09F1F'}
|
||||
@ -22,8 +22,9 @@ const itemLabel=(data)=>{
|
||||
}
|
||||
const config = useRuntimeConfig()
|
||||
const getQRBase64 = async () => {
|
||||
console.log(`http://192.168.88.25:3000/collectCode/signature/personal-Info?number=2&auctionArtworkUuid=${openRo.value.auctionArtworkUuid}&qrUid=${props.data.qrUid}&price=${props.data.price}¤cy=${props.data.currency}`)
|
||||
try {
|
||||
return await QRCode.toDataURL(`${config.public.NUXT_PUBLIC_API_BASE}/collectCode/payment`, {
|
||||
return await QRCode.toDataURL(`http://192.168.88.25:3000/collectCode/signature/personal-Info?number=2&auctionArtworkUuid=${openRo.value.auctionArtworkUuid}&qrUid=${props.data.qrUid}&price=${props.data.price}¤cy=${props.data.currency}`, {
|
||||
width: 200,
|
||||
margin: 4,
|
||||
errorCorrectionLevel: 'H'
|
||||
@ -33,7 +34,15 @@ const getQRBase64 = async () => {
|
||||
return null
|
||||
}
|
||||
}
|
||||
const openQrCode=async ()=>{
|
||||
const openRo=ref({})
|
||||
const openQrCode=async (data)=>{
|
||||
const res=await offlineQrcode({
|
||||
qrUid:data.qrUid
|
||||
})
|
||||
if (res.status===0){
|
||||
openRo.value=res.data
|
||||
}
|
||||
console.log(res,'res')
|
||||
const base64=await getQRBase64()
|
||||
showImagePreview([base64])
|
||||
}
|
||||
@ -57,7 +66,7 @@ const openQrCode=async ()=>{
|
||||
</div>
|
||||
<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 @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">查看</div>
|
||||
<div >
|
||||
<img class="w-12px h-12px" src="@/static/images/icon-design-42@3x.png" alt="">
|
||||
</div>
|
||||
|
@ -1,41 +1,87 @@
|
||||
<script setup>
|
||||
const payStatus=ref(0)
|
||||
const changePayStatus=()=>{
|
||||
payStatus.value=payStatus.value===0?1:0
|
||||
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";
|
||||
import {createOrder} from "~/api-collect-code/goods/index.js";
|
||||
import {codeAuthStore} from "~/stores-collect-code/auth/index.js";
|
||||
const {checkoutSessionUrl,qrUid,qrData} = codeAuthStore()
|
||||
const payStatus = ref(0)
|
||||
definePageMeta({
|
||||
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('请输入金额')
|
||||
return
|
||||
}
|
||||
if (Number(qrData.value.price) < Number(amount.value)) {
|
||||
message.warning('不得高于全部金额')
|
||||
return
|
||||
}
|
||||
showLoadingToast({
|
||||
message: '加载中...',
|
||||
forbidClick: true,
|
||||
});
|
||||
const res = await createOrder({
|
||||
price: payStatus.value === 0 ? qrData.value.price : amount.value,
|
||||
currency: qrData.value.currency,
|
||||
qrUid:qrUid.value,
|
||||
testReturnHost: 'http://192.168.88.25:3000',
|
||||
testReturnEndPoint: '/collectCode/payment/result'
|
||||
})
|
||||
if (res.status === 0) {
|
||||
window.location.href = res.data.checkoutSessionUrl
|
||||
}
|
||||
}
|
||||
|
||||
const handleInput = (e) => {
|
||||
// 只允许数字和小数点,且只保留两位小数
|
||||
const value = e.target.value
|
||||
const char = String.fromCharCode(e.charCode)
|
||||
|
||||
if (!/[\d.]/.test(char)) {
|
||||
e.preventDefault()
|
||||
return
|
||||
// 清除非数字和小数点
|
||||
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')
|
||||
|
||||
if (char === '.' && (value.includes('.') || !value)) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
if (value.includes('.') && value.split('.')[1]?.length >= 2) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
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">
|
||||
<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?'支付全部':'支付部分'}}</div>
|
||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">RMB 5000</div>
|
||||
<div class="mb-12px">
|
||||
<input class="w-272px h-48px bg-#F3F3F3 px-11px text-16px" type="text" placeholder="最多RMB5,000" @keydown="validateInput">
|
||||
<div class="text-#1A1A1A text-16px mb-25px font-bold">{{ payStatus === 0 ? '支付全部' : '支付部分' }}</div>
|
||||
<div class="text-#999999 text-16px mb-24px font-bold" v-if="payStatus===0">{{ qrData.currency }}
|
||||
{{ qrData?.price }}
|
||||
</div>
|
||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{payStatus===1?'支付全部':'支付部分'}}</div>
|
||||
</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="`最多${qrData.currency}${qrData?.price}`" @input="handleInput">
|
||||
</div>
|
||||
<div class="text-#2B53AC text-14px" @click="changePayStatus">{{ payStatus === 1 ? '支付全部' : '支付部分' }}</div>
|
||||
<div class="w-full mt-auto mb-40px">
|
||||
<van-button type="primary" block @click="confirmPay">
|
||||
确认支付
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<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>
|
@ -4,9 +4,9 @@ import XVanSelect from '@/components/x-van-select/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} from "~/api-collect-code/goods/index.js";
|
||||
import {fddInfo, offlineQrcode} from "~/api-collect-code/goods/index.js";
|
||||
import {signOffline} from "~/api/goods/index.js";
|
||||
const {formData,number,auctionArtworkUuid}=codeAuthStore()
|
||||
const {formData,number,auctionArtworkUuid,qrUid,qrData}=codeAuthStore()
|
||||
definePageMeta({
|
||||
layout: 'default',
|
||||
i18n: 'menu.profile',
|
||||
@ -42,15 +42,24 @@ function isFormComplete(obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const initData=()=>{
|
||||
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.auctionArtworkUuid){
|
||||
auctionArtworkUuid.value=route.query.auctionArtworkUuid
|
||||
if (route.query.qrUid){
|
||||
qrUid.value=route.query.qrUid
|
||||
}
|
||||
if (route.query.lotNo){
|
||||
auctionArtworkUuid.value=route.query.lotNo
|
||||
await getData()
|
||||
if (qrData.value.payStatus===4){
|
||||
router.replace('/collectCode/payment')
|
||||
}
|
||||
if (route.query.zone){
|
||||
formData.value.countryCode=route.query.zone
|
||||
@ -115,13 +124,16 @@ initData()
|
||||
</template>
|
||||
</van-field>
|
||||
<van-field label="姓名" v-model="formData.userName" class="mb-10px" placeholder="请输入姓名"/>
|
||||
<x-van-select v-if="number===1" v-model="formData.gender" label="性别" :columns="columns"/>
|
||||
<x-van-date v-if="number===1" label="出生日期" v-model="formData.birthday" />
|
||||
<van-field v-if="number===1" label="家庭住址" v-model="formData.address" class="mb-10px" placeholder="请输入家庭住址"/>
|
||||
<van-field v-if="number===1" label="所属银行" v-model="formData.bankName" class="mb-10px" placeholder="请输入所属银行"/>
|
||||
<van-field v-if="number===1" label="银行卡号码" v-model="formData.bankNo" class="mb-10px" placeholder="请输入银行卡号码"/>
|
||||
<x-van-select v-if="number===1" v-model="formData.cardType" label="证件类型" :columns="columns1"/>
|
||||
<van-field v-if="number===1" label="证件号" v-model="formData.cardId" class="mb-10px" placeholder="请输入证件号"/>
|
||||
<template v-if="number===1">
|
||||
<x-van-select v-model="formData.gender" label="性别" :columns="columns"/>
|
||||
<x-van-date label="出生日期" v-model="formData.birthday" />
|
||||
<van-field label="家庭住址" v-model="formData.address" class="mb-10px" placeholder="请输入家庭住址"/>
|
||||
<van-field label="所属银行" v-model="formData.bankName" class="mb-10px" placeholder="请输入所属银行"/>
|
||||
<van-field label="银行卡号码" v-model="formData.bankNo" class="mb-10px" placeholder="请输入银行卡号码"/>
|
||||
<x-van-select v-model="formData.cardType" label="证件类型" :columns="columns1"/>
|
||||
<van-field label="证件号" v-model="formData.cardId" class="mb-10px" placeholder="请输入证件号"/>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<div class="h-81px bg-#fff flex justify-center pt-7px border-t shrink-0">
|
||||
<van-button color="#2B53AC" class="w-213px van-btn-h-38px" @click="nextClick">下一步</van-button>
|
||||
|
@ -7,13 +7,13 @@ definePageMeta({
|
||||
title:'签署'
|
||||
})
|
||||
const activeNames = ref(['1']);
|
||||
const {formData,number,lotNo,price}=codeAuthStore()
|
||||
const {formData,number,auctionArtworkUuid,qrData}=codeAuthStore()
|
||||
|
||||
const confirm=async ()=>{
|
||||
if (formData.value.countryCode==='86'&&formData.value.cardType===1){
|
||||
const res=await signOffline({
|
||||
userInfo:formData.value,
|
||||
bidNum:lotNo.value,
|
||||
bidPrice:price.value,
|
||||
auctionArtworkUuid:qrData.value.auctionArtworkUuid,
|
||||
signOrder:Number(number.value),
|
||||
})
|
||||
if (res.status===0){
|
||||
|
@ -20,7 +20,16 @@ export const codeAuthStore = createGlobalState(() => {
|
||||
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{
|
||||
qrData,
|
||||
qrUid,
|
||||
cpayment,
|
||||
lotNo,
|
||||
price,
|
||||
auctionArtworkUuid,
|
||||
|
@ -10,6 +10,7 @@ export const authStore = createGlobalState(() => {
|
||||
leftCurrency:'',
|
||||
buyUid:''
|
||||
})
|
||||
|
||||
return{
|
||||
payment,
|
||||
checkoutSessionUrl,
|
||||
|
Loading…
Reference in New Issue
Block a user