|
@@ -0,0 +1,200 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="code pa-5 resume-box">
|
|
|
|
+ <div class="resume-header">
|
|
|
|
+ <div class="resume-title">扫码支付</div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="d-flex align-end mt-3">
|
|
|
|
+ <div class="code-left">
|
|
|
|
+ <QrCode :text="props.qrCode" :disabled="props.disabled" :width="170" @refresh="refreshQRCode" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="code-right ml-5">
|
|
|
|
+ <div class="price">
|
|
|
|
+ <span class="font-size-13">¥</span>
|
|
|
|
+ {{ props.payPrice }}
|
|
|
|
+ </div>
|
|
|
|
+ <div class="mt-3 d-flex align-center">
|
|
|
|
+ <span class="color-666 font-weight-bold mr-5">支付方式</span>
|
|
|
|
+ <v-chip-group v-model="payType" selected-class="text-primary" column mandatory @update:modelValue="payTypeChange">
|
|
|
|
+ <v-chip filter v-for="k in payTypeList" :key="k.code" :value="k.code" class="mr-3" label>
|
|
|
|
+ {{ k.name }}
|
|
|
|
+ <svg-icon v-if="k.icon" class="ml-1" :name="k.icon" :size="k.size"></svg-icon>
|
|
|
|
+ </v-chip>
|
|
|
|
+ </v-chip-group>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div
|
|
|
|
+ class="mt-5 ml-2"
|
|
|
|
+ style="color: var(--v-error-base);"
|
|
|
|
+ >
|
|
|
|
+ 扫码支付时请勿离开
|
|
|
|
+ <span v-if="remainderZhShow">{{ remainderZhShow }}</span>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup>
|
|
|
|
+import QrCode from '@/components/QrCode'
|
|
|
|
+import { ref, watch, onUnmounted } from 'vue'
|
|
|
|
+import { definePayTypeList } from '@/utils/payType'
|
|
|
|
+import { getEnableCodeList } from '@/api/common'
|
|
|
|
+const emit = defineEmits(['refreshQrCode'])
|
|
|
|
+const props = defineProps({
|
|
|
|
+ // 价格
|
|
|
|
+ payPrice: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 0
|
|
|
|
+ },
|
|
|
|
+ // 渠道id
|
|
|
|
+ appId: {
|
|
|
|
+ type: Number,
|
|
|
|
+ default: 8 // 8:个人微信付款
|
|
|
|
+ },
|
|
|
|
+ // 二维码text
|
|
|
|
+ qrCode: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ disabled: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false
|
|
|
|
+ },
|
|
|
|
+ payChannelCode: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: 'wx_native'
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const payType = ref(props.payChannelCode)
|
|
|
|
+const payTypeList = ref([])
|
|
|
|
+const codeList = ref([])
|
|
|
|
+
|
|
|
|
+const remainderZhShow = ref(0)
|
|
|
|
+
|
|
|
|
+let interTimer = null
|
|
|
|
+
|
|
|
|
+let _checkPayStatus = checkPayStatus()
|
|
|
|
+
|
|
|
|
+// 计时器
|
|
|
|
+const initIntervalFun = () => {
|
|
|
|
+
|
|
|
|
+ let remainder = 60000*5 // 倒计时五分钟
|
|
|
|
+ if (interTimer) {
|
|
|
|
+ clearInterval(interTimer)
|
|
|
|
+ }
|
|
|
|
+ remainderZhShow.value = formatDuration(remainder)
|
|
|
|
+ interTimer = setInterval(() => {
|
|
|
|
+ remainder -= 1000
|
|
|
|
+ remainderZhShow.value = formatDuration(remainder)
|
|
|
|
+ // 查询是否已经支付
|
|
|
|
+ _checkPayStatus()
|
|
|
|
+ if (remainder <= 0) {
|
|
|
|
+ // 倒计时结束,二维码过期
|
|
|
|
+ emit('overdue')
|
|
|
|
+ clearInterval(interTimer)
|
|
|
|
+ }
|
|
|
|
+ }, 1000)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 检测付款状态
|
|
|
|
+async function checkPayStatus() {
|
|
|
|
+ let statusLoading = false
|
|
|
|
+ return async (params) => {
|
|
|
|
+ if (!statusLoading) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ statusLoading = true
|
|
|
|
+ try {
|
|
|
|
+ console.log(params)
|
|
|
|
+ // const { data } = await ApiName
|
|
|
|
+ // console.log(data)
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(error)
|
|
|
|
+ } finally {
|
|
|
|
+ statusLoading = false
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+const formatDuration = (remainder) => {
|
|
|
|
+ // 将毫秒转换为秒
|
|
|
|
+ var seconds = Math.floor(remainder / 1000)
|
|
|
|
+ // 计算分钟和剩余的秒数
|
|
|
|
+ var minutes = Math.floor(seconds / 60)
|
|
|
|
+ var remainingSeconds = seconds % 60
|
|
|
|
+ // 格式化分钟和秒数,确保秒数为两位数(如果小于10,则前面补0)
|
|
|
|
+ minutes = minutes.toString().padStart(2, '0')
|
|
|
|
+ remainingSeconds = remainingSeconds.toString().padStart(2, '0')
|
|
|
|
+ // 返回格式化的字符串
|
|
|
|
+ return `${minutes}分${remainingSeconds}秒`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 获取支付渠道
|
|
|
|
+async function getCodeList () {
|
|
|
|
+ try {
|
|
|
|
+ const list = await getEnableCodeList({appId: props.appId})
|
|
|
|
+ console.log(list)
|
|
|
|
+ codeList.value = list || []
|
|
|
|
+ if (!codeList.value.length) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ payTypeList.value.push(...definePayTypeList.filter(d => list.includes(d.code)))
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(error)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 刷新二维码
|
|
|
|
+function refreshQRCode(){
|
|
|
|
+ emit('refreshQrCode', payType.value)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function payTypeChange (val) {
|
|
|
|
+ payType.value = val
|
|
|
|
+ refreshQRCode()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+watch(
|
|
|
|
+ () => props.qrCode,
|
|
|
|
+ (val) => {
|
|
|
|
+ if (!val) {
|
|
|
|
+ if (interTimer) {
|
|
|
|
+ clearInterval(interTimer)
|
|
|
|
+ }
|
|
|
|
+ remainderZhShow.value = null
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ initIntervalFun()
|
|
|
|
+ }
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+onUnmounted(() => {
|
|
|
|
+ // 回收
|
|
|
|
+ _checkPayStatus = null
|
|
|
|
+ clearInterval(interTimer)
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+initIntervalFun()
|
|
|
|
+getCodeList()
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
+.code {
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ background-color: #f7f8fa;
|
|
|
|
+ &-left {
|
|
|
|
+ border: 1px solid #00897B;
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ padding: 5px;
|
|
|
|
+ }
|
|
|
|
+ &-right {
|
|
|
|
+ .price {
|
|
|
|
+ font-size: 30px;
|
|
|
|
+ font-weight: 700;
|
|
|
|
+ color: var(--v-error-base);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+</style>
|