plate:
<template>
<view>
<view class="plate" :class="{show:show}">
<view :class="['item',{active:index===0}]" @click.stop="handleChange(0)">{{plate[0]}}</view>
<view :class="['item ml10',{active:index===1}]" @click="handleChange(1)">{{plate[1]}}</view>
<view>●</view>
<view :class="['item',{active:index===2}]" @click="handleChange(2)">{{plate[2]}}</view>
<view :class="['item ml10',{active:index===3}]" @click="handleChange(3)">{{plate[3]}}</view>
<view :class="['item ml10',{active:index===4}]" @click="handleChange(4)">{{plate[4]}}</view>
<view :class="['item ml10',{active:index===5}]" @click="handleChange(5)">{{plate[5]}}</view>
<view :class="['item ml10',{active:index===6}]" @click="handleChange(6)">{{plate[6]}}</view>
<view :class="['item ml10 column',{active:index===7}]" @click="handleChange(7)">
<template v-if="newEnergy">
<text>{{plate[7]}}</text>
</template>
<template v-else>
<u-icon name="plus-circle"></u-icon>
<view style="font-size: 20upx;">新能源</view>
</template>
</view>
</view>
<section class="panel" :class="{show:show}">
<view class="header">
<view class="p24" style="color: #267EF1;" @click="panelReset">重置</view>
<view src="/static/down.png" style="width: 140upx;" mode="widthFix" @click="panelHide" />
<view class="p24" @click="panelHide">关闭</view>
</view>
<view class="panelList clearfix">
<!-- <view class="item" v-for="(item,index) of currentDatas" @click.stop="clickKeyBoard(item)">{{item}}</view>-->
<!-- 其他组件内容 -->
<view v-for="(item, index) in currentDatas" :key="index">
<button
class="item"
:disabled="isDisabled(index)"
@click="!isDisabled(index) && clickKeyBoard(item)"
>
{{ item }}
</button>
</view>
</view>
<view class="backspace shadow" @click="backspace">
<u-icon name="backspace" color="#333" size="34"></u-icon>
</view>
</section>
</view>
</template>
<script>
export default {
name: "index",
props: {
characterDatas: {
type: Array,
default () {
return [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q',
'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '港', '澳', '学', '领'
]
}
},
areaDatas: {
type: Array,
default () {
return ['京', '沪', '粤', '津', '冀', '晋', '蒙', '黑', '吉', '辽', '苏', '浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '桂',
'琼', '渝', '川', '贵', '云', '藏',
'陕', '甘', '青', '宁', '新', '临', '领', '警', '学', '港', '澳'
]
}
},
defaultPlate:{
type:Array,
default () {
return Array.from({
length: 8
}, v => '')
}
}
},
data() {
return {
show: false,
index: -1,
newEnergy: false,
plate: this.defaultPlate
}
},
created() {
},
computed: {
currentDatas() {
return this.index === 0 ? this.areaDatas : this.characterDatas;
}
},
watch: {
defaultPlate(newValue) {
this.plate = newValue;
},
plate(value) {
this.$emit("listenPlateChange",value);
}
},
methods: {
panelShow() {
this.show = true;
},
panelHide() {
this.show = false;
},
handleChange(index) {
this.index = index;
if (index === 7) {
this.newEnergy = true;
}
this.panelShow();
},
clickKeyBoard(item) {
if (this.index < 7 || this.newEnergy) {
this.$set(this.plate, this.index, item);
}
if (this.index < 7) {
this.index++;
}
},
backspace() {
if (this.index > 0) {
this.$set(this.plate, this.index, '');
this.index--;
}
},
panelReset() {
this.index = 0;
this.plate = Array.from({
length: 8
}, v => '');
this.newEnergy = false;
},
isDisabled(index) {
if (this.index === 0) {
return index >= (this.areaDatas.length - 6);
}
else {
const lastFour = this.characterDatas.length - 4;
if (this.index === 1) {
return typeof this.characterDatas[index] === 'number' || index >= lastFour;
}
return index >= lastFour;
}
return false;
}
}
}
</script>
<style scoped lang='scss'>
.plate {
display: flex;
align-items: center;
justify-content: center;
.item {
width: calc(100% / 7 - 4rpx);
height: 90rpx;
background-color: #F2F3F5;
border: 1px solid #F2F3F5;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
&.ml10 {
margin-left: 10upx;
}
&.column {
flex-direction: column;
border: 1px dashed #4CB58E;
}
&.active {
background-color: #EDF7FF;
border: 1px solid #5294DB;
}
}
}
.panel {
position: fixed;
left: 0;
width: 100%;
bottom: 0;
z-index: 999;
box-sizing: border-box;
background-color: #EFEFEF;
transition: all 0.3s ease;
transform: translateY(100%);
.p24 {
padding: 24upx;
}
&.show {
transform: translateX(0);
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
height: 80upx;
border-top: 1px solid #c9cacd;
//border-bottom: 1px solid #c9cacd;
}
.panelList {
padding: 20upx;
text-align: center;
.item {
float: left;
width: calc(100% / 10 - 10rpx);
height: 76rpx;
background: #fff;
border-radius: 10rpx;
display: flex;
justify-content: center;
align-items: center;
margin: 0 10rpx 10rpx 0;
font-size: 32rpx;
font-weight: 600;
box-shadow: 0 0 4px 1px #e5e5e5;
}
}
.backspace {
position: absolute;
bottom: 25rpx;
right: 26rpx;
width: 100rpx;
height: 84rpx;
background-color: #cbcbcb;
border-radius: 10rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
.clearfix::before,
.clearfix::after {
content: ' ';
display: table;
height: 0;
line-height: 0;
visibility: hidden;
clear: both;
}
</style>
<template>
<view class="carPage" >
<view class="top" >
<image src="http://192.168.3.200:9090/iot//workLog/2024/09/11/ed115f5c9b7f4323a2f4f47d8e87190f.png" style="width: 100%; height: 340rpx; " />
</view>
<view class="card">
<view style="font-size: 18px;font-weight: 600;">车牌号码</view>
<view style="margin: 50rpx 0; ">
<plate @listenPlateChange="plateChange" :defaultPlate="plateNumber" />
</view>
<view style="margin-bottom: 20rpx;">
<u-button type="primary" text="下一步" @click="checkPark"></u-button>
</view>
</view>
</view>
</template>
<script>
import plate from '@/components/plate/index.vue'
import {checkPlate} from "../api";
import {mapGetters, mapMutations} from "vuex";
export default {
name: "carNumber",
components: {
plate
},
data() {
return {
plateNumber:[],
isCart: false, // 是否为月卡服务
}
},
props: {
isShow: {
type: Boolean,
default: false
}
},
onLoad(query) {
this.isCart = query.menu === 'wx-parking' ? true : false
},
computed: {
...mapGetters(['carInfo', 'freeCarInfo'])
},
methods: {
...mapMutations(['setCarInfo','setFreeCar']),
plateChange(val){
this.plateNumber = val // 获取车牌号
},
// 查询车牌号
checkPark() {
if(this.plateNumber.length <= 0) {
uni.$u.toast('请输入车牌号!')
return
}
const params = {
carLicense: this.plateNumber.join('')
}
// 判断是否为月卡服务,跳转相应页面
const path = this.isCart ? 'parkingFee' : 'payment'
checkPlate({params}).then(res => {
if (this.isCart) {
// 月卡,存储车辆信息,非系统用户存车牌号
if (res.rows.length === 0) {
this.setCarInfo({carLicense: this.plateNumber.join('')})
} else {
this.setCarInfo(res.rows[0])
}
} else {
// 缴费,存储车辆信息,非系统用户存车牌号
if (res.rows.length === 0) {
this.setFreeCar({carLicense: this.plateNumber.join('')})
} else {
this.setFreeCar(res.rows[0])
}
}
uni.navigateTo({
url: `/pages/home/functions/${path}/index`
})
})
},
},
onShow() {
// 非首次输入车牌号时,车牌号从缓存取并回显到输入框中
const carNo = this.carInfo.carLicense && this.isCart ? this.carInfo.carLicense.split('') : (this.freeCarInfo.carLicense && !this.isCart? this.freeCarInfo.carLicense.split('') : [])
this.plateNumber = [...carNo, ...Array(8 - carNo.length).fill('')];
}
}
</script>
<style lang="scss" scoped>
.carPage {
background: linear-gradient(to bottom, #cceaff, #f5f5f5);
padding-bottom: 20rpx;
width: 100vw;
position: relative;
.top {
width: 100vw;
}
.card {
background-color: #fff;
margin: 0 16rpx;
padding: 16rpx;
border-radius: 16rpx;
}
}
</style>
store:
import Vue from 'vue'
import Vuex from "vuex"
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
carInfo: {}, // 车辆信息
freeCarInfo: {}, // 缴费车辆信息
},
mutations: {
// 车辆信息
setCarInfo(state, data) {
state.carInfo = data
uni.setStorageSync('carInfo', data);
},
// 缴费车辆信息
setFreeCar(state, data) {
state.freeCarInfo = data
uni.setStorageSync('freeCarInfo', data);
}
},
getters: {
// 获取停车信息
carInfo(state) {
if (state.carInfo.carLicense) {
return state.carInfo
} else {
return uni.getStorageSync('carInfo')
}
},
// 获取停车缴费信息
freeCarInfo(state) {
if (state.freeCarInfo.carLicense) {
return state.freeCarInfo
} else {
return uni.getStorageSync('freeCarInfo')
}
}
}
})
export default store
实现效果: