|
@@ -1,355 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="d-flex list mb-3">
|
|
|
- <div v-for="(val, index) in list" :key="index" :id="'positioning'+index" class="list-item text-center cursor-pointer" :class="{'active': index === current}" @click="handleClick(index, val)">
|
|
|
- <template v-if="val.id === 'custom'">
|
|
|
- <div class="d-flex flex-column algin-center justify-center" style="height: 100%">
|
|
|
- <div>需要发布更多职位</div>
|
|
|
- <div>请联系门墩儿购买企业套餐</div>
|
|
|
- <div style="width: 100%; position: relative;">
|
|
|
- <div style="width: 80px; height: 80px; margin: auto; opacity: 0.5;">
|
|
|
- <v-img src="https://minio.menduner.com/dev/menduner/contact.png" width="80" height="80"></v-img>
|
|
|
- </div>
|
|
|
- <!-- <div style="opacity: 0.5;"><v-icon size="60">mdi-qrcode</v-icon></div> -->
|
|
|
- <div class="absolute-center" style="color: #444; margin: 3px 0 0 2px;"><v-icon size="30">mdi-magnify-plus-outline</v-icon></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <template v-else>
|
|
|
- <h4 class="mt-5">{{ val.name }}</h4>
|
|
|
- <div class="color-primary">
|
|
|
- <span>¥</span>
|
|
|
- <span style="font-size: 35px;">{{ val.price / 100 }}</span>
|
|
|
- <span> 元</span>
|
|
|
- </div>
|
|
|
- <div class="text-decoration-line-through color-666">原价:{{ val.originalPrice / 100 }}元</div>
|
|
|
- <div class="font-size-14 color-999 mt-3 periodValidity py-2">有效期:{{ val.day }}天</div>
|
|
|
- </template>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div v-if="!Object.keys(select).length && !showCustom" class="color-warning text-center mt-15 font-size-20">请选择要购买的套餐</div>
|
|
|
- <div v-if="payType && payQrCodeTxt" id="codeBox" class="code pa-5 resume-box">
|
|
|
- <!-- <div class="resume-header">
|
|
|
- <div class="resume-title">扫码支付</div>
|
|
|
- </div> -->
|
|
|
- <div class="d-flex" :style="{'margin-left': offsetCalc + 'px'}">
|
|
|
- <div id="codeItem" class="d-flex flex-column align-center my-2">
|
|
|
- <div class="d-flex align-center">
|
|
|
- <span class="color-666 font-weight-bold">支付方式:</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 class="code-right">
|
|
|
- <div class="price">
|
|
|
- <span class="font-size-13">¥</span>
|
|
|
- {{ FenYuanTransform(select?.price || 0) }}元
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="code-left">
|
|
|
- <QrCode :text="payQrCodeTxt" :disabled="!remainderTimer" :width="170" @refresh="refreshQRCode" />
|
|
|
- </div>
|
|
|
- <div class="mt-52" style="color: var(--v-error-base);">
|
|
|
- 扫码支付时请勿离开
|
|
|
- <span v-if="remainderZhShow">{{ remainderZhShow }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div v-if="showCustom" id="codeBox" class="code pa-5 resume-box">
|
|
|
- <div style="width: 100%;">
|
|
|
- <div class="text-center">请扫码添加下方企业微信联系我们:</div>
|
|
|
- <div class="my-3" style="width: 180px; height: 180px; margin: auto;">
|
|
|
- <v-img src="https://minio.menduner.com/dev/menduner/contact.png" width="180" height="180"></v-img>
|
|
|
- </div>
|
|
|
- <div class="text-center mt-2">潘青海先生(Peter Pan)</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup>
|
|
|
-defineOptions({ name: 'membershipPackageDynamicPackage' })
|
|
|
-import { ref, onUnmounted, nextTick } from 'vue'
|
|
|
-import { getEnterprisePackageList } from '@/api/enterprise'
|
|
|
-import { FenYuanTransform } from '@/utils/position'
|
|
|
-import { getEnableCodeList, payOrderSubmit, getOrderPayStatus, getUnpaidOrder } from '@/api/common'
|
|
|
-import { definePayTypeList, qrCodePay } from '@/utils/payType'
|
|
|
-import { useUserStore } from '@/store/user'; const store = useUserStore()
|
|
|
-import Snackbar from '@/plugins/snackbar'
|
|
|
-import { createTradeOrder } from '@/api/position'
|
|
|
-import { useRoute } from 'vue-router'; const route = useRoute()
|
|
|
-import { useRouter } from 'vue-router'; const router = useRouter()
|
|
|
-import Confirm from '@/plugins/confirm'
|
|
|
-import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
|
|
|
-
|
|
|
-const current = ref()
|
|
|
-const select = ref({})
|
|
|
-
|
|
|
-// 套餐列表
|
|
|
-const list = ref([])
|
|
|
-const getPackageList = async () => {
|
|
|
- const data = await getEnterprisePackageList()
|
|
|
- list.value = data
|
|
|
- list.value.push({id:'custom'})
|
|
|
-}
|
|
|
-
|
|
|
-const offsetCalc = ref(0)
|
|
|
-let codeItemOffsetWidth = null
|
|
|
-const codeBoxPx = 40 // codeBox左右内边距
|
|
|
-const calcStyle = (index) => {
|
|
|
- nextTick(() => {
|
|
|
- const codeBox = document.getElementById('codeBox')
|
|
|
- const codeBoxOffsetWidth = codeBox.offsetWidth - codeBoxPx
|
|
|
- if (!codeItemOffsetWidth) {
|
|
|
- const codeItem = document.getElementById('codeItem')
|
|
|
- codeItemOffsetWidth = codeItem.offsetWidth
|
|
|
- }
|
|
|
- //
|
|
|
- const menu = document.getElementById(`positioning${index}`)
|
|
|
- offsetCalc.value = 0
|
|
|
- if (menu && codeBoxOffsetWidth && codeItemOffsetWidth) {
|
|
|
- const menuHalfWidth= menu.offsetWidth/2
|
|
|
- const codeItemHalfWidth = codeItemOffsetWidth/2
|
|
|
- const calcNum = (menuHalfWidth+menuHalfWidth*2*index - codeItemHalfWidth) + (index ? 6 : 0)
|
|
|
- //
|
|
|
- if (calcNum+codeItemOffsetWidth > codeBoxOffsetWidth) { // 超出右侧,取最大
|
|
|
- offsetCalc.value = codeBoxOffsetWidth-codeItemOffsetWidth
|
|
|
- } else if (calcNum < 0) { // 超出左侧,取最小
|
|
|
- offsetCalc.value = 0
|
|
|
- } else {
|
|
|
- offsetCalc.value = calcNum-20 > 0 ? calcNum-20 : 0
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const showCustom = ref(false)
|
|
|
-const handleClick = (index, val) => {
|
|
|
- if (val.id == 'custom') {
|
|
|
- payQrCodeTxt.value = ''
|
|
|
- showCustom.value = true
|
|
|
- return
|
|
|
- }
|
|
|
- showCustom.value = false
|
|
|
- payQrCodeTxt.value = ''
|
|
|
- current.value = index
|
|
|
- select.value = val
|
|
|
- getUnpaidOrderList()
|
|
|
-}
|
|
|
-
|
|
|
-const payQrCodeTxt = ref('')
|
|
|
-
|
|
|
-// 2.发起充值
|
|
|
-const loading = ref(true)
|
|
|
-const payOrder = ref({})
|
|
|
-let maxCount = 0
|
|
|
-const getUnpaidOrderList = async () => {
|
|
|
- const data = await getUnpaidOrder({ spuId: select.value.id, type: 4 })
|
|
|
- if (!data) {
|
|
|
- await createTradeOrder({ price: (select.value.price-0), spuId: select.value.id, spuName: select.value.name, type: 4 })
|
|
|
- if (maxCount > 3) return // 避免死循环
|
|
|
- maxCount++
|
|
|
- setTimeout(() => {
|
|
|
- getUnpaidOrderList()
|
|
|
- }, 1000)
|
|
|
- }
|
|
|
- payOrder.value = data?.payOrder || null
|
|
|
- paySubmit()
|
|
|
-}
|
|
|
-
|
|
|
-const payTypeChange = (val) => {
|
|
|
- payType.value = val
|
|
|
- getUnpaidOrderList()
|
|
|
-}
|
|
|
-const timer = ref(null)
|
|
|
-onUnmounted(() => {
|
|
|
- if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
-})
|
|
|
-
|
|
|
-// 更新职位可发布数量
|
|
|
-const updateAccountInfo = async (init = false) => {
|
|
|
- await store.getEnterpriseInfo(true)
|
|
|
- if (init) return
|
|
|
- loading.value = false
|
|
|
-}
|
|
|
-
|
|
|
-const fromName = ref(route.query?.fromName || '')
|
|
|
-const callBackUrl = () => {
|
|
|
- // if (!fromName.value) return
|
|
|
- const urls = {
|
|
|
- position: '/recruit/enterprise/position',
|
|
|
- positionPay: '/recruit/enterprise/position?tab=0',
|
|
|
- }
|
|
|
- const texts = {
|
|
|
- position: '职位管理页面',
|
|
|
- positionPay: '职位管理待发布页面'
|
|
|
- }
|
|
|
- const url = fromName.value ? urls[fromName.value] : -1
|
|
|
- const text = fromName.value ? texts[fromName.value] : '购买前页面'
|
|
|
- //
|
|
|
- Confirm(t('common.confirmTitle'), `支付成功!是否返回${text}?`).then(() => {
|
|
|
- router.push(url)
|
|
|
- })
|
|
|
-}
|
|
|
-// callBackUrl() 测试
|
|
|
-
|
|
|
-const payStatus = async () => {
|
|
|
- try {
|
|
|
- const data = await getOrderPayStatus({ id: payOrder.value.id })
|
|
|
- if ((data?.status - 0) === 10) {
|
|
|
- // 支付成功
|
|
|
- if (timer.value) clearInterval(timer.value); timer.value = null
|
|
|
- setTimeout(() => {
|
|
|
- // 更新点数(充值、发布职位)
|
|
|
- updateAccountInfo()
|
|
|
- // 清除定时器
|
|
|
- clearTimer()
|
|
|
- // 支付成功
|
|
|
- if (fromName.value) callBackUrl()
|
|
|
- else Snackbar.success('支付成功')
|
|
|
- }, 2000);
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.log(error)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const paySubmit = async () => {
|
|
|
- if (!payType.value) return
|
|
|
- try {
|
|
|
- // 提交支付订单
|
|
|
- const params = {
|
|
|
- channelCode: payType.value, // 支付渠道
|
|
|
- id: payOrder.value.id
|
|
|
- }
|
|
|
- const res = await payOrderSubmit(params)
|
|
|
- payQrCodeTxt.value = res?.displayContent || '' // 生成二维码内容
|
|
|
- calcStyle(current.value)
|
|
|
- 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) payType.value = code
|
|
|
- }
|
|
|
- payTypeList.value.push(item)
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-nextTick(async () => {
|
|
|
- await getPackageList()
|
|
|
- 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 remainderZhShow = ref('')
|
|
|
-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()
|
|
|
-}
|
|
|
-
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped lang="scss">
|
|
|
-.list {
|
|
|
- &-item {
|
|
|
- width: 25%;
|
|
|
- height: 172px;
|
|
|
- background-color: #fcfcfd;
|
|
|
- border: 1px solid #f3f3f3;
|
|
|
- border-radius: 8px;
|
|
|
- margin-right: 12px;
|
|
|
- &:last-child {
|
|
|
- margin-right: 0;
|
|
|
- }
|
|
|
- .periodValidity {
|
|
|
- background-color: #f2f4f7;
|
|
|
- border-radius: 0 0 8px 8px;
|
|
|
- }
|
|
|
- }
|
|
|
- .active {
|
|
|
- border: 1px solid #00B760;
|
|
|
- }
|
|
|
-}
|
|
|
-.code {
|
|
|
- background-color: #f7f8fa;
|
|
|
- border-radius: 6px;
|
|
|
- margin: 0 auto;
|
|
|
- &-left {
|
|
|
- border: 1px solid #00B760;
|
|
|
- border-radius: 6px;
|
|
|
- padding: 5px;
|
|
|
- }
|
|
|
- &-right {
|
|
|
- .price {
|
|
|
- font-size: 30px;
|
|
|
- font-weight: 700;
|
|
|
- color: var(--v-error-base);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|