SmartParks_uniapp/pages/sys/user/myPayment/myPayment.vue

537 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-wrapper">
<!-- 顶部title栏 -->
<view class="pay-container">
<!-- 未绑定车牌状态 -->
<view v-if="status === 'unbound'" class="pay-unbound">
<image src="/static/ic_my_payment_01.png" class="pay-empty-img" />
<view class="pay-unbound-tip">你还未绑定车牌哦~</view>
<view class="pay-unbound-link" @click="showBindDialog = true">现在去绑定</view>
</view>
<!-- 已绑定车牌状态 -->
<view v-else class="pay-binded">
<view class="pay-car-card">
<view class="pay-car-row">
<image src="/static/ic_my_payment_02.png" class="pay-car-icon" />
<view class="pay-car-num">{{ carInfo.number }}</view>
<view class="pay-car-status">{{ carInfo.status }}</view>
</view>
<view class="pay-car-addr">{{ carInfo.addr }}</view>
<view class="pay-car-info">
<view class="pay-car-time">
<view>停放时长</view>
<view class="pay-car-info-val">{{ carInfo.duration }}</view>
</view>
<view class="pay-car-fee">
<view>预计费用</view>
<view class="pay-car-fee-val">¥{{ carInfo.fee }}</view>
</view>
</view>
<button class="pay-car-btn">立即缴费</button>
</view>
<view class="pay-list-entry">
<view class="pay-list-item">缴费标准
<image class="mine-list-arrow" src="/static/ic_arrow_gray.webp" />
</view>
<view class="pay-list-item" @click="goToRecords">缴费记录
<image class="mine-list-arrow" src="/static/ic_arrow_gray.webp"/>
</view>
</view>
<button class="pay-add-btn">新增停车</button>
</view>
<!-- 绑定车牌弹窗 -->
<view v-if="showBindDialog" class="pay-dialog-mask" @click.self="showBindDialog = false">
<view class="pay-dialog-box">
<view class="pay-dialog-title-row">
<view class="pay-dialog-title">输入车牌号</view>
<image src="/static/ic_close_01.png" class="pay-dialog-close" @click="showBindDialog = false" />
</view>
<view class="pay-dialog-input-row">
<!-- 省份简称输入框 -->
<input class="pay-dialog-input province-input" :value="carNumArr[0]" readonly
:focus="focusIndex === -1" @click="showProvinceKeyboard = true; focusIndex = -1" />
<!-- 后6位 -->
<input v-for="(item, idx) in 6" :key="idx" maxlength="1" class="pay-dialog-input"
v-model="carNumArr[idx+1]" :focus="focusIndex === idx" @input="onCarInput($event, idx)"
@keydown.native="onCarKeydown($event, idx)" @paste="onCarPaste($event)" />
</view>
<button class="pay-dialog-btn" @click="bindCar">保存</button>
</view>
</view>
<!-- 省份简称自定义键盘弹窗 -->
<view v-if="showProvinceKeyboard" class="province-keyboard-mask" @click.self="showProvinceKeyboard = false">
<view class="province-keyboard-box">
<view class="province-keyboard-title">选择省份简称</view>
<view class="province-keyboard-grid">
<view v-for="(item, idx) in provinceList" :key="idx" class="province-keyboard-btn"
@click="selectProvince(item)">{{ item }}</view>
</view>
<button class="province-keyboard-cancel" @click="showProvinceKeyboard = false">取消</button>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
status: 'unbound', // unbound, binded
showBindDialog: false,
carNumArr: ['渝', '', '', '', '', '', ''],
showProvinceKeyboard: false,
focusIndex: 0,
isBackspace: false,
// 假数据
carInfo: {
number: '渝A-65891',
status: '停放中',
addr: '服务中心1栋A区五层-018号',
duration: '01:25:33',
fee: 12
},
provinceList: [
'京', '津', '沪', '渝', '冀', '豫', '云', '辽', '黑', '湘',
'皖', '鲁', '新', '苏', '浙', '赣', '鄂', '桂', '甘', '晋',
'蒙', '陕', '吉', '闽', '贵', '粤', '青', '藏', '川', '宁', '琼'
]
}
},
methods: {
bindCar() {
this.showBindDialog = false;
this.status = 'binded';
},
goBack() {
uni.navigateBack();
},
onCarInput(e, idx) {
let val = e.detail.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
this.$set(this.carNumArr, idx + 1, val);
// 只在输入时自动跳到下一个,避免键盘频繁弹出
if (val && idx < 5) {
this.focusIndex = idx + 1;
}
},
onCarKeydown(e, idx) {
// 记录是否是删除键,但删除时不自动回退聚焦
this.isBackspace = (e.key === 'Backspace' || e.keyCode === 8);
},
onCarPaste(e) {
let paste = (e.clipboardData || window.clipboardData).getData('text').toUpperCase().replace(/[^A-Z0-9]/g,
'');
if (paste.length > 0) {
for (let i = 0; i < 6; i++) {
this.$set(this.carNumArr, i + 1, paste[i] || '');
}
this.focusIndex = 5;
}
e.preventDefault();
},
selectProvince(item) {
this.$set(this.carNumArr, 0, item);
this.showProvinceKeyboard = false;
// 自动聚焦第二位
this.focusIndex = 0;
},
goToRecords() {
uni.navigateTo({
url: '/pages/sys/user/myPayment/paymentRecords'
});
}
}
}
</script>
<style scoped>
.page-wrapper {
height: 100vh;
display: flex;
flex-direction: column;
}
.pay-navbar {
width: 100%;
height: 160rpx;
padding-top: 70rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
background: #fff;
flex-shrink: 0;
}
.pay-back {
position: absolute;
left: 37rpx;
width: 15rpx;
height: 33rpx;
}
.pay-title {
font-size: 36rpx;
color: #000;
}
.pay-container {
background: #F7F8FA;
padding-bottom: 120rpx;
display: flex;
flex-direction: column;
flex: 1;
overflow-y: auto;
}
.pay-unbound {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 160rpx;
}
.pay-empty-img {
width: 320rpx;
height: 180rpx;
margin-bottom: 40rpx;
}
.pay-unbound-tip {
font-size: 30rpx;
color: #222;
margin-bottom: 18rpx;
}
.pay-unbound-link {
color: #0090FF;
font-size: 30rpx;
font-weight: bold;
margin-top: 10rpx;
}
.pay-binded {
margin-top: 80rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.pay-car-card {
position: relative;
width: 80vw;
background: #fff;
border-radius: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
padding: 56rpx 40rpx 30rpx 40rpx;
margin-bottom: 40rpx;
}
.pay-car-row {
display: flex;
align-items: center;
margin-bottom: 54rpx;
}
.pay-car-icon {
width: 43rpx;
height: 35rpx;
margin-right: 18rpx;
}
.pay-car-num {
font-size: 32rpx;
font-weight: 600;
color: #000;
margin-right: 18rpx;
}
.pay-car-status {
font-size: 24rpx;
color: #FEFEFE;
background: linear-gradient(90deg, #05C58C 0%, #73FFC9 100%);
border-radius: 12rpx;
padding: 8rpx 20rpx;
margin-left: auto;
}
.pay-car-addr {
position: absolute;
top: 94rpx;
left: 98rpx;
font-size: 24rpx;
color: #878787;
}
.pay-car-info {
position: relative;
width: 70vw;
height: 113rpx;
display: flex;
align-items: center;
margin-bottom: 54rpx;
background: #E9F4FF;
border: 1rpx solid #2E93FF;
border-radius: 10rpx;
margin-left: auto;
margin-right: auto;
}
.pay-car-time {
position: absolute;
top: 16rpx;
left: 33rpx;
align-items: center;
display: flex;
flex-direction: column;
align-items: center;
}
.pay-car-info-val {
font-size: 28rpx;
color: #222;
font-weight: bold;
margin-top: 8rpx;
}
.pay-car-fee {
position: absolute;
top: 16rpx;
right: 58rpx;
align-items: center;
display: flex;
flex-direction: column;
align-items: center;
}
.pay-car-fee-val {
color: #F3831F;
font-size: 28rpx;
font-weight: bold;
margin-top: 8rpx;
}
.pay-car-btn {
width: 283rpx;
height: 57rpx;
background: linear-gradient(90deg, #005DE9 0%, #4B9BFF 100%);
color: #fff;
font-size: 28rpx;
border-radius: 15rpx;
font-weight: 600;
text-align: center;
/* 新增flex居中 */
display: flex;
align-items: center;
justify-content: center;
}
.pay-list-entry {
width: 92vw;
}
.pay-list-item {
background: #fff;
border-radius: 12rpx;
font-size: 28rpx;
color: #222;
padding: 28rpx 32rpx;
margin-bottom: 18rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.pay-list-arrow {
color: #bbb;
font-size: 32rpx;
}
.pay-add-btn {
width: 90vw;
height: 80rpx;
background: #0090FF;
color: #fff;
font-size: 32rpx;
border: none;
border-radius: 40rpx;
position: fixed;
left: 0;
right: 0;
bottom: 200rpx;
margin: 0 auto;
display: block;
font-weight: bold;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.18);
z-index: 100;
}
.pay-dialog-mask {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.pay-dialog-box {
width: 70vw;
background: #fff;
border-radius: 28rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
padding: 48rpx 36rpx 36rpx 36rpx;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
}
.pay-dialog-title-row {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
position: relative;
margin-bottom: 80rpx;
}
.pay-dialog-title {
font-size: 36rpx;
color: #000;
}
.pay-dialog-close {
position: absolute;
right: 0;
top: 0;
width: 32rpx;
height: 32rpx;
}
.pay-dialog-input-row {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 80rpx;
gap: 28rpx;
}
.pay-dialog-input {
width: 43rpx;
height: 53rpx;
background: #EEEEEE;
border-radius: 5rpx;
font-size: 32rpx;
color: #222;
text-align: center;
border: none;
outline: none;
}
.pay-dialog-btn {
width: 320rpx;
height: 70rpx;
margin-bottom: 40rpx;
background: linear-gradient(90deg, #0090FF 0%, #2E9FFF 100%);
color: #fff;
font-size: 28rpx;
border: none;
border-radius: 35rpx;
display: block;
font-weight: bold;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.12);
}
.province-input {
background: #EEEEEE;
border-radius: 5rpx;
width: 43rpx;
height: 53rpx;
margin-right: 28rpx;
text-align: center;
font-size: 32rpx;
color: #222;
border: none;
}
.province-keyboard-mask {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.4);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.province-keyboard-box {
width: 600rpx;
background: #fff;
border-radius: 28rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
padding: 48rpx 36rpx 36rpx 36rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.province-keyboard-title {
font-size: 32rpx;
color: #222;
font-weight: bold;
margin-bottom: 32rpx;
}
.province-keyboard-grid {
display: flex;
flex-wrap: wrap;
gap: 18rpx;
justify-content: center;
margin-bottom: 32rpx;
}
.province-keyboard-btn {
width: 80rpx;
height: 60rpx;
background: #F7F8FA;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
color: #222;
margin-bottom: 8rpx;
cursor: pointer;
border: 1rpx solid #eee;
transition: background 0.2s;
}
.province-keyboard-btn:active {
background: #e6f0ff;
}
.province-keyboard-cancel {
width: 320rpx;
height: 60rpx;
background: #eee;
color: #222;
font-size: 28rpx;
border: none;
border-radius: 30rpx;
margin-top: 10rpx;
}
.mine-list-arrow {
width: 18rpx;
height: 28rpx;
margin-right: 24rpx;
}
</style>