123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- <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>
|