239 lines
7.1 KiB
Vue
239 lines
7.1 KiB
Vue
<template>
|
||
<uni-nav-bar
|
||
left-icon="left"
|
||
title="兑换福利卡"
|
||
@clickLeft="goBack"
|
||
fixed
|
||
color="#8B2316"
|
||
height="140rpx"
|
||
:border="false"
|
||
backgroundColor="#eeeeee"
|
||
></uni-nav-bar>
|
||
|
||
<view class="exchange-page">
|
||
<!-- 顶部红色横幅 -->
|
||
<view class="top-banner">
|
||
<view class="banner-text">
|
||
<view class="line1">已兑换{{ exchangedCount }}张</view>
|
||
<view class="line2" @click="goMyWelfare">查看现有权益</view>
|
||
</view>
|
||
<view class="help-btn" @click="showHelp">帮助说明</view>
|
||
</view>
|
||
|
||
<!-- 使用统一的自定义居中模态框 -->
|
||
<view v-if="centerVisible" class="center-modal" @click.self="closeCenter">
|
||
<view class="center-modal-content">
|
||
<view class="center-title">{{ centerHelp ? '帮助说明' : '提示' }}</view>
|
||
<view v-if="centerHelp" class="help-content center-help">
|
||
<text>1、点击“兑换福利卡”,输入密码即可兑换相应权益</text>
|
||
<text>2、每张福利卡仅限兑换一次,兑换后权益可在“我的福利-使用福利”中查看</text>
|
||
<text>3、福利卡长期有效,福利卡不能退换或者折现</text>
|
||
<text>4、查找文献权益不限文献类型,如指南共识、论文、电子书、课件或者视频</text>
|
||
</view>
|
||
<view v-else class="center-body">{{ centerText }}</view>
|
||
<view class="center-actions">
|
||
<button class="center-btn" @click="closeCenter">知道了</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 输入提示 -->
|
||
<view class="tips">请输入16位福利卡密码(不区分大小写)<text class="paste-action" @click="pasteFromClipboard">粘贴</text></view>
|
||
|
||
<!-- 四段输入框 -->
|
||
<view class="code-inputs">
|
||
<input class="code-box" type="text" v-model="code1" maxlength="4" placeholder="" :focus="f1" @input="handleInput(1, $event)" @paste="handlePaste"/>
|
||
<input class="code-box" type="text" v-model="code2" maxlength="4" placeholder="" :focus="f2" @input="handleInput(2, $event)"/>
|
||
<input class="code-box" type="text" v-model="code3" maxlength="4" placeholder="" :focus="f3" @input="handleInput(3, $event)"/>
|
||
<input class="code-box" type="text" v-model="code4" maxlength="4" placeholder="" :focus="f4" @input="handleInput(4, $event)"/>
|
||
</view>
|
||
|
||
<!-- 按钮 -->
|
||
<view class="btn-wrapper">
|
||
<button class="submit-btn" :disabled="!isFull" @click="submit">立即兑换</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed, nextTick } from 'vue'
|
||
import api from '@/api/api';
|
||
const exchangedCount = ref(5)
|
||
const code1 = ref('')
|
||
const code2 = ref('')
|
||
const code3 = ref('')
|
||
const code4 = ref('')
|
||
const f1 = ref(true)
|
||
const f2 = ref(false)
|
||
const f3 = ref(false)
|
||
const f4 = ref(false)
|
||
const helpVisible = ref(false)
|
||
const centerVisible = ref(false)
|
||
const centerText = ref('')
|
||
const centerHelp = ref(false)
|
||
const isFull = computed(() => (code1.value+code2.value+code3.value+code4.value).length === 16)
|
||
|
||
const goBack = () => {
|
||
uni.navigateBack({
|
||
fail() {
|
||
uni.redirectTo({ url: '/pages/index/index' })
|
||
}
|
||
})
|
||
}
|
||
const showHelp = () => {
|
||
centerHelp.value = true
|
||
centerVisible.value = true
|
||
}
|
||
|
||
// 通用模态框
|
||
const openCenter = (text) => {
|
||
centerText.value = text
|
||
centerHelp.value = false
|
||
centerVisible.value = true
|
||
}
|
||
const closeCenter = () => {
|
||
centerVisible.value = false
|
||
centerHelp.value = false
|
||
}
|
||
const setFocus = (idx) => {
|
||
f1.value = idx === 1
|
||
f2.value = idx === 2
|
||
f3.value = idx === 3
|
||
f4.value = idx === 4
|
||
}
|
||
const handleInput = (idx, e) => {
|
||
const raw = (e.detail && e.detail.value) || ''
|
||
const sanitized = raw.replace(/[^a-zA-Z0-9]/g, '')
|
||
if (idx === 1) code1.value = sanitized
|
||
if (idx === 2) code2.value = sanitized
|
||
if (idx === 3) code3.value = sanitized
|
||
if (idx === 4) code4.value = sanitized
|
||
if (sanitized.length === 4 && idx < 4) {
|
||
nextTick(() => setFocus(idx + 1))
|
||
}
|
||
}
|
||
const submit = () => {
|
||
if (!isFull.value) return
|
||
const code = (code1.value+code2.value+code3.value+code4.value).toUpperCase()
|
||
uni.showToast({ title: '兑换中: '+ code, icon: 'none' })
|
||
api.exchangeWelfareCard({password: code}).then(res => {
|
||
console.log(res)
|
||
if (res.code == 200) {
|
||
uni.showToast({ title: '兑换成功', icon: 'success' })
|
||
uni.navigateBack()
|
||
}
|
||
})
|
||
}
|
||
|
||
const goMyWelfare = () => {
|
||
uni.navigateTo({ url: '/pages_app/myWelfare/myWelfare' })
|
||
}
|
||
|
||
// 处理粘贴(H5等支持paste事件的平台)
|
||
const handlePaste = (e) => {
|
||
const text = (e.clipboardData && e.clipboardData.getData('text')) || ''
|
||
fillByText(text)
|
||
// 阻止默认粘贴到单个输入框
|
||
e && e.preventDefault && e.preventDefault()
|
||
}
|
||
|
||
// 从剪贴板读取(App、小程序)
|
||
const pasteFromClipboard = () => {
|
||
uni.getClipboardData({
|
||
success: (res) => {
|
||
fillByText(res.data || '')
|
||
}
|
||
})
|
||
}
|
||
|
||
const fillByText = (raw) => {
|
||
const v = String(raw || '').replace(/[^a-zA-Z0-9]/g, '').toUpperCase().slice(0, 16)
|
||
code1.value = v.slice(0, 4)
|
||
code2.value = v.slice(4, 8)
|
||
code3.value = v.slice(8, 12)
|
||
code4.value = v.slice(12, 16)
|
||
nextTick(() => setFocus(v.length >= 16 ? 4 : Math.floor((v.length)/4) + 1))
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
$nav-height: 140rpx;
|
||
.exchange-page{
|
||
min-height: 100vh;
|
||
background: #f5f6f7;
|
||
}
|
||
.top-banner{
|
||
position: relative;
|
||
height: 280rpx;
|
||
background: linear-gradient(180deg,#ff6a4a 0%, #e93b2d 100%);
|
||
border-bottom-left-radius: 40rpx;
|
||
border-bottom-right-radius: 40rpx;
|
||
.banner-text{
|
||
position: absolute;
|
||
left: 48rpx;
|
||
top: 120rpx;
|
||
color: #fff;
|
||
.line1{font-size: 44rpx;font-weight: 600;}
|
||
.line2{font-size: 36rpx;margin-top: 12rpx;}
|
||
}
|
||
.help-btn{
|
||
position: absolute;
|
||
right: 40rpx;
|
||
top: 90rpx;
|
||
background: rgba(255,255,255,.95);
|
||
color: #e04835;
|
||
border-radius: 999rpx;
|
||
padding: 10rpx 24rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
.tips{
|
||
margin: 48rpx;
|
||
color: #333;
|
||
font-size: 32rpx;
|
||
.paste-action{
|
||
color: #007aff;
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
.code-inputs{
|
||
display: flex;
|
||
gap: 30rpx;
|
||
padding: 0 48rpx;
|
||
.code-box{
|
||
flex: 1;
|
||
height: 96rpx;
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
text-align: center;
|
||
font-size: 36rpx;
|
||
}
|
||
}
|
||
.btn-wrapper{
|
||
padding: 80rpx 48rpx 0;
|
||
.submit-btn{
|
||
width: 100%;
|
||
height: 100rpx;
|
||
background: linear-gradient(90deg,#ff4d2e,#e93b2d);
|
||
border-radius: 60rpx;
|
||
color: #fff;
|
||
font-size: 36rpx;
|
||
}
|
||
.submit-btn[disabled]{
|
||
opacity: .6;
|
||
}
|
||
}
|
||
|
||
/* 帮助弹层样式 */
|
||
.center-help{padding: 0 32rpx;display:flex;flex-direction:column;align-items:center;gap: 16rpx;color:#333;font-size:28rpx;line-height:1.6;}
|
||
|
||
/* 自定义通用模态框 */
|
||
.center-modal{position: fixed;left:0;right:0;top:0;bottom:0;background: rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index: 9999;}
|
||
.center-modal-content{width: 640rpx;background:#fff;border-radius:24rpx;overflow:hidden;}
|
||
.center-title{font-size: 32rpx;color:#333;text-align:center;padding:28rpx 24rpx 12rpx;font-weight:600;}
|
||
.center-body{padding:0 32rpx 12rpx;color:#333;font-size:28rpx;line-height:1.7;text-align:center;}
|
||
.center-actions{padding: 24rpx 24rpx 28rpx;}
|
||
.center-btn{width:100%;height:88rpx;border-radius:999rpx;background:#e93b2d;color:#fff;font-size:30rpx;}
|
||
|
||
</style>
|