|
@@ -0,0 +1,345 @@
|
|
|
|
+<template>
|
|
|
|
+ <div>
|
|
|
|
+ <div class="d-flex align-center justify-center mt-5">
|
|
|
|
+ <div
|
|
|
|
+ v-for="(item, index) in list"
|
|
|
|
+ :key="index"
|
|
|
|
+ class="packagesItem cursor-pointer mx-3"
|
|
|
|
+ :class="{'active': current === (index+1)}"
|
|
|
|
+ style="width: 200px;"
|
|
|
|
+ @click="handleClick(index, item)"
|
|
|
|
+ >
|
|
|
|
+ <div class="d-flex flex-column align-center pb-5" style="position: relative;">
|
|
|
|
+ <div class="my-5 font-size-16 font-weight-bold" style="z-index: 2;">{{ item.name }}</div>
|
|
|
|
+ <div class="priceBox mt-3" style="position: relative;">
|
|
|
|
+ <span v-if="item.custom">
|
|
|
|
+ <div v-if="inputValue" class="custom-point-show" style="position: absolute; top: -24px;">{{ inputValue }}M豆</div>
|
|
|
|
+ <input v-model="inputValue" @blur="inputChange" type="text" class="custom-input-num mr-1" :placeholder="item.placeholder">元
|
|
|
|
+ <div class="color-warning font-size-12 text-center mt-1">只能输入整数</div>
|
|
|
|
+ </span>
|
|
|
|
+ <span class="color-primary" v-else>
|
|
|
|
+ ¥
|
|
|
|
+ <span style="font-size: 25px;">{{ FenYuanTransform(item.payPrice) }}</span>
|
|
|
|
+ 元
|
|
|
|
+ </span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="vip">
|
|
|
|
+ <svg-icon name="diamond" size="50"></svg-icon>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="text-end color-primary my-3 text-decoration-underline cursor-pointer" @click="handleToOrder">充值记录<v-icon>mdi-chevron-double-right</v-icon></div>
|
|
|
|
+ <div v-if="payType && payQrCodeTxt" 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="payQrCodeTxt" :disabled="!remainderTimer" :width="170" @refresh="refreshQRCode" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="code-right ml-5">
|
|
|
|
+ <div class="price">
|
|
|
|
+ <span class="font-size-13">¥</span>
|
|
|
|
+ {{ FenYuanTransform(select?.payPrice || 0) }}元
|
|
|
|
+ </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>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup>
|
|
|
|
+defineOptions({ name: 'membershipPackageBalance' })
|
|
|
|
+import { ref, onUnmounted, nextTick, watch } from 'vue'
|
|
|
|
+import { FenYuanTransform } from '@/utils/position'
|
|
|
|
+import { getEnableCodeList, payOrderSubmit, getOrderPayStatus } from '@/api/common'
|
|
|
|
+import { definePayTypeList, qrCodePay } from '@/utils/payType'
|
|
|
|
+import { rechargeOrderCreate } from '@/api/recruit/enterprise/member/points'
|
|
|
|
+import { getEnterpriseRechargePackageList } from '@/api/recruit/enterprise/member/points'
|
|
|
|
+import { useUserStore } from '@/store/user'; const store = useUserStore()
|
|
|
|
+import Snackbar from '@/plugins/snackbar'
|
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
|
+
|
|
|
|
+const router = useRouter()
|
|
|
|
+const current = ref(1)
|
|
|
|
+const inputValue = ref('')
|
|
|
|
+const payQrCodeTxt = ref('')
|
|
|
|
+const remainderZhShow = ref('') // 倒计时展示
|
|
|
|
+const select = ref({})
|
|
|
|
+const list = ref([])
|
|
|
|
+const getData = async () => {
|
|
|
|
+ const data = await getEnterpriseRechargePackageList()
|
|
|
|
+ const end = { name: '自定义金额', id: 'custom', placeholder: '请输入', custom: true }
|
|
|
|
+ list.value = data ? [...data, end] : [end]
|
|
|
|
+ select.value = list.value[0]
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleClick = (index, item) => {
|
|
|
|
+ current.value = index + 1
|
|
|
|
+ select.value = item
|
|
|
|
+ getUnpaidOrderList()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const inputChange = () => {
|
|
|
|
+ if (!inputValue.value) return
|
|
|
|
+ current.value = list.value.length
|
|
|
|
+ const item = list.value[list.value.length-1]
|
|
|
|
+ item.payPrice = FenYuanTransform(inputValue.value, 'toCent')
|
|
|
|
+ item.id = 'custom' + inputValue.value
|
|
|
|
+ select.value = item
|
|
|
|
+ getUnpaidOrderList()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const timeout = ref(null)
|
|
|
|
+watch(
|
|
|
|
+ () => inputValue.value,
|
|
|
|
+ (val) => {
|
|
|
|
+ let num = val && val !=='0' ? (val.match(/\d+/g)?.join('') || null) : null
|
|
|
|
+ if (num > 100000000) {
|
|
|
|
+ num = '100000000'
|
|
|
|
+ Snackbar.warning('最多不可超过一亿元')
|
|
|
|
+ }
|
|
|
|
+ inputValue.value = num
|
|
|
|
+ clearTimeout(timeout.value)
|
|
|
|
+ timeout.value = setTimeout(() => inputChange(), 500) // 防抖
|
|
|
|
+ }
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// 2.发起充值
|
|
|
|
+const loading = ref(true)
|
|
|
|
+const payOrder = ref({})
|
|
|
|
+const getUnpaidOrderList = async () => {
|
|
|
|
+ if (select.value.payPrice === undefined) return payQrCodeTxt.value = ''
|
|
|
|
+ const params = {
|
|
|
|
+ payPrice: (select.value.payPrice-0),
|
|
|
|
+ }
|
|
|
|
+ if (typeof select.value.id === 'string' && !select.value.id.includes('custom')) params.packageId = select.value.id
|
|
|
|
+ const data = await rechargeOrderCreate(params)
|
|
|
|
+ payOrder.value = data || {}
|
|
|
|
+ paySubmit()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const payTypeChange = (val) => {
|
|
|
|
+ payType.value = val
|
|
|
|
+ paySubmit()
|
|
|
|
+}
|
|
|
|
+const timer = ref(null)
|
|
|
|
+onUnmounted(() => {
|
|
|
|
+ if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// 更新账户余额
|
|
|
|
+const updateAccountInfo = async (init = false) => {
|
|
|
|
+ await store.getEnterpriseUserAccountInfo()
|
|
|
|
+ if (init) return
|
|
|
|
+ loading.value = false
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const payStatus = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const data = await getOrderPayStatus({ id: payOrder.value.payOrderId })
|
|
|
|
+ if ((data?.status - 0) === 10) {
|
|
|
|
+ // 支付成功
|
|
|
|
+ if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
|
+ setTimeout(() => {
|
|
|
|
+ // 更新点数(充值、发布职位)
|
|
|
|
+ updateAccountInfo()
|
|
|
|
+ // 清除定时器
|
|
|
|
+ clearTimer()
|
|
|
|
+ // 支付成功
|
|
|
|
+ Snackbar.success('支付成功')
|
|
|
|
+ }, 2000);
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(error)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const paySubmit = async () => {
|
|
|
|
+ if (!payType.value) return
|
|
|
|
+ try {
|
|
|
|
+ if (payOrder.value) {
|
|
|
|
+ if (!payOrder.value?.payOrderId) return
|
|
|
|
+ // 提交支付订单
|
|
|
|
+ const params = {
|
|
|
|
+ channelCode: payType.value, // 支付渠道
|
|
|
|
+ id: payOrder.value.payOrderId // 支付单编号
|
|
|
|
+ }
|
|
|
|
+ const res = await payOrderSubmit(params)
|
|
|
|
+ payQrCodeTxt.value = res?.displayContent || '' // 生成二维码内容
|
|
|
|
+ initIntervalFun()
|
|
|
|
+ if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
|
+ timer.value = setInterval(() => { payStatus() }, 1000) // 轮巡查询用户是否支付
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(error)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 1.支付方式
|
|
|
|
+const payType = ref('')
|
|
|
|
+const payTypeList = ref([])
|
|
|
|
+const codeList = ref([])
|
|
|
|
+const getCodeList = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const list = await getEnableCodeList({ appId: 11 })
|
|
|
|
+ codeList.value = list || []
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.log(error)
|
|
|
|
+ } finally {
|
|
|
|
+ if (definePayTypeList?.length && codeList.value?.length) {
|
|
|
|
+ codeList.value.forEach(code => {
|
|
|
|
+ const item = definePayTypeList.find(p => p.code === code)
|
|
|
|
+ if (item) {
|
|
|
|
+ if (!payType.value) {
|
|
|
|
+ // 默认值赋值(暂时只支持扫码)
|
|
|
|
+ const bool = qrCodePay.includes(code)
|
|
|
|
+ if (bool) payTypeChange(code)
|
|
|
|
+ }
|
|
|
|
+ payTypeList.value.push(item)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ getUnpaidOrderList()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+nextTick(async () => {
|
|
|
|
+ await getData()
|
|
|
|
+ await getCodeList()
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+const refreshQRCode =() => { // 刷新二维码
|
|
|
|
+ getUnpaidOrderList()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const remainderTimer = ref(null)
|
|
|
|
+const countdownTime = 60000 * 3 // 倒计时三分钟
|
|
|
|
+let remainder = 0 // number
|
|
|
|
+// 初始化倒计时
|
|
|
|
+const initIntervalFun = () => {
|
|
|
|
+ remainder = countdownTime // 初始倒计时时间
|
|
|
|
+ if (remainderTimer.value) clearInterval(remainderTimer.value); remainderTimer.value = null // 每一次点击都清除上一个轮询
|
|
|
|
+ // 倒计时计算
|
|
|
|
+ remainderCalc()
|
|
|
|
+ remainderTimer.value = setInterval(() => { remainderCalc() }, 1000)
|
|
|
|
+
|
|
|
|
+ if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
|
+ timer.value = setInterval(() => { payStatus() }, 2000) // 轮巡查询用户是否支付
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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}秒`
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const clearTimer = () => {
|
|
|
|
+ if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
|
+ if (remainderTimer.value) clearInterval(remainderTimer.value); remainderTimer.value = null
|
|
|
|
+ remainderZhShow.value = ''
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const remainderCalc = () => {
|
|
|
|
+ remainder -= 1000
|
|
|
|
+ remainderZhShow.value = formatDuration(remainder)
|
|
|
|
+ if (remainder <= 0) clearTimer()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const handleToOrder = () => {
|
|
|
|
+ router.push('/recruit/enterprise/tradingOrder?key=tab_recharge')
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
+.packagesItem {
|
|
|
|
+ border: 1px solid var(--color-f3);
|
|
|
|
+ border-radius: 8px;
|
|
|
|
+ background-color: var(--color-f2f4f742);
|
|
|
|
+}
|
|
|
|
+.dailyPrice {
|
|
|
|
+ border-radius: 14px;
|
|
|
|
+ background-color: #dde3e94f;
|
|
|
|
+ padding: 2px 18px;
|
|
|
|
+ color: var(--color-666);
|
|
|
|
+}
|
|
|
|
+.active {
|
|
|
|
+ border: 2px solid #00897B;
|
|
|
|
+ .priceBox {
|
|
|
|
+ color: var(--v-primary-base);
|
|
|
|
+ }
|
|
|
|
+ .dailyPrice {
|
|
|
|
+ color: var(--v-error-base);
|
|
|
|
+ background-color: #fff4e7;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+.custom-input-num {
|
|
|
|
+ border: none;
|
|
|
|
+ outline: none;
|
|
|
|
+ background-color: transparent;
|
|
|
|
+ width: 120px;
|
|
|
|
+ max-width: 120px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ background-color: #d9d9d98c;
|
|
|
|
+ border-radius: 20px;
|
|
|
|
+ font-size: 20px;
|
|
|
|
+ color: var(--v-primary-base);
|
|
|
|
+}
|
|
|
|
+.code {
|
|
|
|
+ max-width: 1100px;
|
|
|
|
+ background-color: #f7f8fa;
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ margin: 0 auto;
|
|
|
|
+ &-left {
|
|
|
|
+ border: 1px solid #00897B;
|
|
|
|
+ border-radius: 6px;
|
|
|
|
+ padding: 5px;
|
|
|
|
+ }
|
|
|
|
+ &-right {
|
|
|
|
+ .price {
|
|
|
|
+ font-size: 30px;
|
|
|
|
+ font-weight: 700;
|
|
|
|
+ color: var(--v-error-base);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+.vip {
|
|
|
|
+ width: 50px;
|
|
|
|
+ height: 50px;
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0;
|
|
|
|
+ right: 0;
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ border-radius: 8px
|
|
|
|
+}
|
|
|
|
+.custom-point-show {
|
|
|
|
+ width: 100%;
|
|
|
|
+ text-align: center;
|
|
|
|
+ font-weight: normal;
|
|
|
|
+ color: gray;
|
|
|
|
+ font-size: 13px;
|
|
|
|
+}
|
|
|
|
+:deep(.v-slide-group__content) {
|
|
|
|
+ background: none !important;
|
|
|
|
+}
|
|
|
|
+</style>
|