Sfoglia il codice sorgente

企业-购买招聘会门票

Xiao_123 2 mesi fa
parent
commit
e818fccf08
1 ha cambiato i file con 233 aggiunte e 6 eliminazioni
  1. 233 6
      src/views/recruit/enterprise/jobFair/index.vue

+ 233 - 6
src/views/recruit/enterprise/jobFair/index.vue

@@ -6,13 +6,58 @@
         <div class="px-5 py-3">
           <div class="color-666">活动时间:{{ timesTampChange(k.startTime, 'Y-M-D') }}至{{ timesTampChange(k.endTime, 'Y-M-D') }}</div>
           <div class="text-end">
-            <v-btn color="primary" variant="outlined" @click.stop="handleBlockEnterprise(k.id)">立即加入</v-btn>
+            <v-btn color="primary" variant="outlined" @click.stop="handleBlockEnterprise(k)">立即加入</v-btn>
           </div>
         </div>
       </v-card>
     </div>
-    <Empty v-else message="暂无进行中的招聘会,去看看其他吧~" />
+    <Empty v-else :elevation="false" message="暂无进行中的招聘会,去看看其他吧~" />
   </v-card>
+
+  <CtDialog
+    :visible="showDialog"
+    :widthType="3"
+    :footer="false"
+    titleClass="text-h6"
+    title="购买招聘会门票"
+    @close="handleClose"
+  >
+    <div class="color-warning mb-5">
+      <p>鉴于您当前没有参加招聘会的权限</p>
+      <p>您可以通过下方扫码购买招聘会门票参与~</p>
+    </div>
+    <div v-if="payType" id="codeBox" class="code pa-0 resume-box">
+      <div class="resume-header px-3 pt-5">
+        <div class="resume-title">扫码支付</div>
+      </div>
+      <div class="d-flex justify-center mt-3">
+        <div id="codeItem" class="d-flex flex-column align-center my-2">
+          <div class="d-flex align-center">
+            <div class="color-666 font-weight-bold">支付方式:</div>
+            <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(info?.admissionPrice || 0) }}元
+            </div>
+          </div>
+          <div class="code-left" v-if="payQrCodeTxt">
+            <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>
+  </CtDialog>
 </template>
 
 <script setup>
@@ -23,6 +68,10 @@ import { getJobFairList } from '@/api/recruit/enterprise/jobFair'
 import { getCheckJobFairPermission } from '@/api/recruit/enterprise/jobFair'
 import Snackbar from '@/plugins/snackbar'
 import { timesTampChange } from '@/utils/date'
+import { FenYuanTransform } from '@/utils/position'
+import { getEnableCodeList, payOrderSubmit, getOrderPayStatus, getUnpaidOrder } from '@/api/common'
+import { definePayTypeList, qrCodePay } from '@/utils/payType'
+import { createTradeOrder } from '@/api/position'
 
 const router = useRouter()
 const list = ref([])
@@ -33,11 +82,172 @@ const getList = async () => {
 }
 getList()
 
+const timer = ref(null)
+const showDialog = ref(false)
+
+// 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
+              getUnpaidOrderList()
+            }
+          }
+          payTypeList.value.push(item)
+        }
+      })
+    }
+  }
+}
+
+const payQrCodeTxt = ref('')
+
+// 2.发起充值
+const payOrder = ref({})
+let maxCount = 0
+const getUnpaidOrderList = async () => {
+  const data = await getUnpaidOrder({ spuId: info.value.id, type: 5 })
+  if (!data) {
+    await createTradeOrder({ price: (info.value.admissionPrice - 0), spuId: info.value.id, spuName: info.value.title, type: 5 })
+    if (maxCount > 3) return // 避免死循环
+    maxCount++
+    setTimeout(() => {
+      getUnpaidOrderList()
+    }, 1000)
+  }
+  payOrder.value = data?.payOrder || null
+  paySubmit()
+}
+
+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(() => {
+        // 清除定时器
+        clearTimer()
+        // 支付成功,跳转招聘会详情
+        Snackbar.success('购买成功')
+        handleBlockEnterprise(info.value)
+      }, 2000);
+    }
+  } catch (error) {
+    console.log(error)
+  }
+}
+
+const payTypeChange = (val) => {
+  payType.value = val
+  getUnpaidOrderList()
+}
+
+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 || '' // 生成二维码内容
+
+     // 弹窗关闭后不执行
+    if (!showDialog.value) {
+      if (timer.value) clearInterval(timer.value); timer.value = null
+      return
+    }
+
+    initIntervalFun()
+    if (timer.value) clearInterval(timer.value); timer.value = null
+    timer.value = setInterval(() => { payStatus() }, 1000) // 轮巡查询用户是否支付
+  } catch (error) {
+    console.log(error)
+  }
+}
+
+const refreshQRCode =() => { // 刷新二维码
+  getUnpaidOrderList()
+}
+
+const remainderTimer = ref(null)
+const countdownTime = 60000 * 3 // 倒计时三分钟
+let remainder = 0
+// 初始化倒计时
+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()
+}
+
+const handleClose = () => {
+  clearTimer()
+  payType.value = ''
+  payQrCodeTxt.value = ''
+  payTypeList.value = []
+  showDialog.value = false
+}
+
 // 立即加入
-const handleBlockEnterprise = async (id) => {
-  const data = await getCheckJobFairPermission(id)
-  if (!data) return Snackbar.warning('您没有权限参加该招聘会') // 只有返回true才能进入双选会
-  router.push(`/recruit/enterprise/jobFair/details/${id}`)
+const info = ref(0)
+const handleBlockEnterprise = async (val) => {
+  try {
+    const data = await getCheckJobFairPermission(val.id)
+    if (data) router.push(`/recruit/enterprise/jobFair/details/${val.id}`)
+  } catch {
+    // 购买门票
+    info.value = val
+    if (timer.value) clearInterval(timer.value); timer.value = null
+    await getCodeList()
+    showDialog.value = true
+  }
 }
 </script>
 
@@ -48,4 +258,21 @@ const handleBlockEnterprise = async (id) => {
   gap: 20px;
   min-height: auto;
 }
+.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>