123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- <template>
- <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 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)}"
- :id="'positioning'+index"
- :style="{'width': width+'%'}"
- @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 v-if="!Object.keys(select).length" class="color-warning text-center mt-15 font-size-20">请选择要充值的金额</div>
- <div v-if="payType && payQrCodeTxt" id="codeBox" class="code pa-5 resume-box my-5">
- <!-- <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?.payPrice || 0) }}元
- </div>
- </div>
- <div class="code-left">
- <QrCode :text="payQrCodeTxt" :disabled="!remainderTimer" :width="170" @refresh="refreshQRCode" />
- </div>
- <div class="mt-5" style="color: var(--v-error-base);">
- 扫码支付时请勿离开
- <span v-if="remainderZhShow">{{ remainderZhShow }}</span>
- </div>
- </div>
- </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()
- const inputValue = ref('')
- const payQrCodeTxt = ref('')
- const remainderZhShow = ref('') // 倒计时展示
- const select = ref({})
- const width = ref(15)
- const list = ref([])
- const getData = async () => {
- const data = await getEnterpriseRechargePackageList()
- const end = { name: '自定义金额', id: 'custom', placeholder: '请输入', custom: true }
- list.value = data ? [...data, end] : [end]
- width.value = 100/list.value.length
- }
- 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 + 12
- const codeItemHalfWidth = codeItemOffsetWidth/2
- const calcNum = menuHalfWidth+menuHalfWidth*2*index - codeItemHalfWidth
- //
- 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 handleClick = (index, item) => {
- payQrCodeTxt.value = ''
- 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),
- packageId: select.value.id,
- }
- 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 || '' // 生成二维码内容
- calcStyle(current.value-1)
- 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 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')
- }
- const mlArr = [119, 344, 567, 791, 1298, 1298, 1298, 1298]
- </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: 1328px;
- max-width: 100%;
- 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>
|