popup-platenumber.vue 10.9 KB
<template>
	<tui-bottom-popup :show="visible" @close="onClose">
    <div class="popup-platenumber">
      <div class="popup-platenumber__header">
        <u-button v-if="limit.includes('normal')" :type="type === 'normal' ? 'primary' : undefined" @click="type = 'normal'">普通车牌</u-button>
        <u-button v-if="limit.includes('new')" :type="type === 'new' ? 'primary' : undefined" @click="type = 'new'">新能源车牌</u-button>
        <u-button v-if="limit.includes('trailer')" :type="type === 'trailer' ? 'primary' : undefined" @click="type = 'trailer'">挂车牌</u-button>
      </div>
      <div class="popup-platenumber__body">
        <div class="input-box" :class="{ active: currentInputIndex == 0 }" @click="currentInputIndex = 0">{{ currentInputValue[0] }}</div>
        <div class="input-box" :class="{ active: currentInputIndex == 1 }" @click="currentInputIndex = 1">{{ currentInputValue[1] }}</div>
        <div class="split-dot"></div>
        <div class="input-box" :class="{ active: currentInputIndex == 2 }" @click="currentInputIndex = 2">{{ currentInputValue[2] }}</div>
        <div class="input-box" :class="{ active: currentInputIndex == 3 }" @click="currentInputIndex = 3">{{ currentInputValue[3] }}</div>
        <div class="input-box" :class="{ active: currentInputIndex == 4 }" @click="currentInputIndex = 4">{{ currentInputValue[4] }}</div>
        <div class="input-box" :class="{ active: currentInputIndex == 5 }" @click="currentInputIndex = 5">{{ currentInputValue[5] }}</div>
        <div v-if="['normal', 'new'].includes(type)" class="input-box" :class="{ active: currentInputIndex == 6 }" @click="currentInputIndex = 6">{{ currentInputValue[6] }}</div>
        <div v-if="type == 'new'" class="input-box" :class="{ active: currentInputIndex == 7 }" @click="currentInputIndex = 7">{{ currentInputValue[7] }}</div>
        <div v-if="type == 'trailer'" class="input-box">挂</div>
      </div>
      <div class="popup-platenumber__keyboard">
        <template v-if="inputType == 1">
          <div class="key-text" v-for="key of provinceText" :key="key" @click="onChoose(key)">{{ key }}</div>
          <div class="key-text fill-block"></div>
        </template>
        <template v-if="inputType >= 3">
          <div class="key-text" v-for="key of numberText" :key="key" @click="onChoose(key)">{{ key }}</div>
        </template>
        <template v-if="inputType >= 2">
          <div class="key-text" v-for="key of wordText" :key="key" @click="onChoose(key)">{{ key }}</div>
        </template>
        <template v-if="[2, 3, 4].includes(inputType)">
          <span v-for="num of 6" :key="num" class="key-text fill-block"></span>
        </template>
        <template v-if="inputType === 2">
          <span v-for="num of 10" :key="num" class="key-text fill-block"></span>
        </template>
      </div>
      <div class="popup-platenumber__footer" v-safe-bottom>
        <div class="popup-platenumber__footer-left">
          <u-button @click="onClose">取消</u-button>
          <u-button @click="onReset">清空</u-button>
        </div>
        <div class="popup-platenumber__footer-right">
          <u-button @click="onDelete">删除</u-button>
          <u-button type="primary" @click="onConfirm">完成</u-button>
        </div>
      </div>
    </div>
  </tui-bottom-popup>
</template>

<script>

export default {
  name: 'PopupPlatenumber',
  components: {
  },
  props: {
    visible: Boolean,
    value: {
      type: String,
      default: '',
    },
    limit: {
      type: Array,
      default: () => ['normal', 'new', 'trailer'],
    },
  },
  data() {
    return {
      type: this.limit[0], // 车牌类型
      currentInputIndex: 0, // 当前编辑的输入框
      currentInputValue: ['', '', '', '', '', '', ''],
      provinceText: [
        '京',
        '冀',
        '沪',
        '津',
        '晋',
        '蒙',
        '辽',
        '吉',
        '黑',
        '苏',
        '浙',
        '皖',
        '闽',
        '赣',
        '鲁',
        '豫',
        '鄂',
        '湘',
        '粤',
        '桂',
        '琼',
        '渝',
        '川',
        '贵',
        '云',
        '青',
        '藏',
        '陕',
        '甘',
        '宁',
        '新',
      ],
      numberText: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
      wordText: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'],
      lastWordText: ['挂'],
    };
  },
  computed: {
    // 输入框类型
    inputType({ type, limit, currentInputIndex }) {
      const options = {
        0: 1,
        1: 2,
        2: 3,
        3: 3,
        4: 3,
        5: 3,
        6: limit.includes('trailer') && type !== 'new' ? 4 : 3,
        7: limit.includes('trailer') ? 4 : 3,
      };
      return options[currentInputIndex] || 1;
    },
  },
  watch: {
    limit(value) {
      this.type = value ? value[0] : 'normal';
    },
    type(value) {
      this.onReset(value);
    },
    value(val) {
      if (val) {
        this.initPlate();
      } else {
        this.onReset();
      }
    },
  },
  mounted() {
    this.initPlate();
  },
  methods: {
    onReset() {
      const type = this.type;
      this.currentInputIndex = 0;
      if (type === 'normal') {
        // 普通车牌
        this.currentInputValue = ['', '', '', '', '', '', ''];
      } else if (type === 'new') {
        // 新能源车牌
        this.currentInputValue = ['', '', '', '', '', '', '', ''];
      } else if (type === 'trailer') {
        // 挂车牌
        this.currentInputValue = ['', '', '', '', '', ''];
      }
    },
    initPlate() {
      const plateKey = this.value.split('');
      const isTrailer = plateKey[plateKey.length - 1] === '挂';
      if (plateKey.length === 7) {
        this.type = 'normal';
        if (isTrailer) {
          this.type = 'trailer';
        }
      } else if (plateKey.length === 8) {
        this.type = 'new';
      }
      this.$nextTick(() => {
        if (isTrailer) {
          this.type = 'trailer';
          const trailerKeys = plateKey.filter(key => key !== '挂');
          this.currentInputValue = trailerKeys;
          this.currentInputIndex = trailerKeys.length === 0 ? trailerKeys.length : trailerKeys.length - 1;
        } else {
          this.currentInputValue = plateKey;
          this.currentInputIndex = plateKey.length === 0 ? plateKey.length : plateKey.length - 1;
        }
      });
    },
    onClose() {
      this.$emit('update:visible', false);
    },
    onChoose(value) {
      this.$set(this.currentInputValue, this.currentInputIndex, value);
      if (this.type == 'normal' && this.currentInputIndex < 6) {
        this.currentInputIndex++;
      }
      if (this.type == 'new' && this.currentInputIndex < 7) {
        this.currentInputIndex++;
      }
      if (this.type == 'trailer' && this.currentInputIndex < 5) {
        this.currentInputIndex++;
      }
    },
    onDelete() {
      if (this.currentInputIndex === 0) {
        // 首位
        this.$set(this.currentInputValue, this.currentInputIndex, '');
      } else if (this.currentInputIndex === this.currentInputValue.length - 1) {
        // 末位
        if (this.currentInputValue[this.currentInputIndex] !== '') {
          this.$set(this.currentInputValue, this.currentInputIndex, '');
        } else {
          this.currentInputIndex--;
          this.$set(this.currentInputValue, this.currentInputIndex, '');
        }
      } else {
        // 中间位
        this.currentInputIndex--;
        this.$set(this.currentInputValue, this.currentInputIndex, '');
      }
    },
    onConfirm() {
      const plate = this.currentInputValue.join('');
      let err = false;
      if (this.type === 'normal' && plate.length !== 7) {
        err = true;
      } else if (this.type === 'new' && plate.length !== 8) {
        err = true;
      } else if (this.type === 'trailer' && plate.length !== 6) {
        err = true;
      }
      if (plate.length <= 0) {
        err = false;
      }
      if (err) {
        api.toast({ msg: '请输入完整的车牌号码' });
      } else {
        if (this.type === 'trailer') {
          const trailerPlate = [...this.currentInputValue, '挂'].join('');
          this.$emit('input', trailerPlate === '挂' ? '' : trailerPlate);
          this.$emit('confirm', trailerPlate === '挂' ? '' : trailerPlate);
        } else {
          this.$emit('input', plate);
          this.$emit('confirm', plate);
        }
        this.onClose();
      }
    },
  },
};
</script>

<style lang="scss">
.popup-platenumber {
	background-color: $color-white;
	&__header {
		display: flex;
		align-items: center;
		padding: $padding-sm;
		padding-top: 20px;
		.u-button {
			box-sizing: border-box;
			padding: 2px 8px;
			width: 90px;
			height: 28px;
			border-radius: 7px;
			white-space: nowrap;
			word-break: break-all;
			color: $color-text;
			background: #eaeaea;
			margin-right: $padding-base;
			&--primary {
				background: #fede47;
				color: #604300;
			}
		}
	}
	&__body {
		box-sizing: border-box;
		padding: $padding-sm;
		display: flex;
		justify-content: space-between;
		align-items: center;
		.split-dot {
			width: 4px;
			height: 4px;
			background: $color-text-minor;
			border-radius: 50%;
		}
		.input-box {
			border-radius: $radius-md;
			height: $padding-md * 2;
			width: $padding-md * 2;
			min-width: $padding-md * 2;
			box-sizing: border-box;
			display: inline-flex;
			align-items: center;
			justify-content: center;
			border: 1px solid $color-border;
			font-weight: bold;
			font-size: $font-lg;
			&.active {
				border-color: $color-blue;
				box-shadow: 0 0 4px rgba($color-blue, 0.5);
			}
		}
	}
	&__keyboard {
		padding: $padding-sm;
		box-sizing: border-box;
		transition: all 0.3s;
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;
		background-color: $color-bg-base;
		.key-text {
			display: block;
			background: $color-white;
			border-radius: $radius-md;
			width: $padding-md * 2;
			height: $padding-md * 2;
			margin: $padding-base 0;
			font-size: $font-md;
			display: flex;
			align-items: center;
			justify-content: center;
			position: relative;
			border: 1px solid $color-border;
			&.fill-block {
				width: $padding-md * 2;
				height: $padding-md * 2;
				background: none;
				box-shadow: none;
				border-color: transparent;
			}
		}
	}
	&__footer {
		display: flex;
		justify-content: space-between;
		background: $color-white;
		box-sizing: border-box;
		padding: $padding-sm;
		padding-bottom: 20px;
		.u-button {
			box-sizing: border-box;
			padding: 2px 8px;
			width: 70px;
			height: 32px;
			border-radius: 7px;
			white-space: nowrap;
			word-break: break-all;
			color: $color-white;
			background: #333333;
			&--primary {
				background: #fede47;
				color: #604300;
			}
		}
		&-left,
		&-right {
			display: flex;
			align-items: center;
			.u-button {
				padding: $padding-base $padding-md;
			}
		}
		&-left {
			.u-button {
				margin-right: $padding-xs;
			}
		}
		&-right {
			.u-button {
				margin-left: $padding-xs;
			}
		}
	}
}
</style>