Преглед на файлове

AI优化绑定车牌页面

skyline преди 4 месеца
родител
ревизия
722e6b741a
променени са 1 файла, в които са добавени 351 реда и са изтрити 91 реда
  1. 351 91
      src/pages-user/profile/index.vue

+ 351 - 91
src/pages-user/profile/index.vue

@@ -1,126 +1,386 @@
 <template>
-  <uv-list>
-    <uv-list-item title="车牌号"
-                  :show-arrow="true"
-                  clickable :rightText="plateNo"
-                  @click="handleChoosePlate"></uv-list-item>
-  </uv-list>
-
-<!--  <view class="logout-btn">
-    <uv-button :custom-style="customStyle" type="error" @click="logoutUser">退出登录</uv-button>
-  </view>-->
+  <view class="plate-page">
+    <!-- 车牌输入区域 -->
+    <view class="plate-input-section">
+      <view class="plate-input-header">
+        <text class="plate-label">车牌号码:</text>
+        <view class="default-checkbox">
+          <uv-checkbox v-model="isDefault" shape="circle"></uv-checkbox>
+          <text class="default-text">设为默认车辆</text>
+        </view>
+      </view>
+      
+      <view class="plate-input-hint">
+        <text>添加车牌后部分站点可享停车减免权益,临牌减免权益请查看站点详细减免规则</text>
+      </view>
+      
+      <!-- 车牌输入框 -->
+      <view class="plate-input-container">
+        <!-- 省份输入 -->
+        <input class="plate-item plate-region"
+               v-model="plateChars[0]"
+               maxlength="1"
+               type="text"
+               inputmode="none"
+               readonly
+               @focus="onPlateFocus(0); $event.preventDefault();"
+               @click="toggleRegionPicker"
+               @touchstart.prevent="toggleRegionPicker"/>
+        
+        <!-- 城市输入 -->
+        <input class="plate-item plate-region"
+               v-model="plateChars[1]"
+               maxlength="1"
+               type="text"
+               inputmode="text"
+               @input="onPlateInput"
+               @focus="onPlateFocus(1)"/>
+        
+        <!-- 分隔符 -->
+        <view class="plate-divider">
+          <text>·</text>
+        </view>
+        
+        <!-- 字母数字输入框 -->
+        <input v-for="(char, index) in plateChars.slice(2)" 
+               :key="index + 2" 
+               class="plate-item"
+               :class="{ 'new-energy': index === 5 }"
+               v-model="plateChars[index + 2]"
+               maxlength="1"
+               placeholder-class="placeholder"
+               :placeholder="index === 5 ? '新能源' : ''"
+               type="text"
+               inputmode="text"
+               @input="onPlateInput"
+               @focus="onPlateFocus(index + 2)"/>
+      </view>
+      
+      <!-- 保存按钮 -->
+      <view class="save-btn-container">
+        <uv-button type="primary" color="#C6171E" shape="circle" :disabled="!isPlateValid" @click="savePlate">保存</uv-button>
+      </view>
+      
+      <!-- 地区选择器 -->
+      <view v-if="showRegionPicker" class="region-picker-container">
+        <!-- 完成按钮 -->
+        <view class="region-picker-header">
+          <uv-button type="default" size="small" @click="toggleRegionPicker">完成</uv-button>
+        </view>
+        
+        <!-- 地区网格 -->
+        <view class="region-grid">
+          <view v-for="region in regions" :key="region" 
+                class="region-item" 
+                @click="selectRegion(region)">
+            <text>{{ region }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+  </view>
 </template>
 
-<script setup lang="ts">
+<script setup>
 import {onLoad, onShow} from "@dcloudio/uni-app";
-import {ref} from "vue";
-import {body, get, upload} from "@/utils/https";
-import {clearToken} from "@/utils/auth"
-
-const plateNo = ref("未绑定")
-
-const customStyle = () => {
-  return {
-    height: '80rpx',
-    borderRadius: '40rpx',
-    fontSize: '30rpx',
-    lineHeight: '80rpx',
-    background: '#FF6D00',
-    color: '#fff',
-    fontWeight: '500',
-    width: '60%',
+import {ref, computed} from "vue";
+import {body} from "@/utils/https";
+
+// 页面状态
+const plateNo = ref("未绑定");
+const plateChars = ref(['粤', 'B', '', '', '', '', '', '']);
+const isDefault = ref(false);
+const currentInputIndex = ref(2);
+const showRegionPicker = ref(false);
+
+// 地区列表
+const regions = ['京', '津', '渝', '沪', '冀', '晋', '辽', '吉', '黑', '苏', '浙', '皖', '闽', '赣', '鲁', '豫', '鄂', '湘', '粤', '琼', '川', '贵', '云', '陕', '甘', '青', '蒙', '桂', '宁', '新', '藏', '使', '领', '警', '学', '港', '澳'];
+
+// 计算属性
+const isPlateValid = computed(() => {
+  const validChars = plateChars.value.filter(char => char !== '');
+  return validChars.length >= 7;
+});
+
+// 输入事件处理
+const onPlateInput = () => {
+  // 自动大写输入内容
+  for (let i = 0; i < plateChars.value.length; i++) {
+    plateChars.value[i] = plateChars.value[i].toUpperCase();
   }
-}
+};
 
+// 焦点事件处理
+const onPlateFocus = (index) => {
+  currentInputIndex.value = index;
+};
 
-const handleChoosePlate = () => {
-  uni.chooseLicensePlate({
-    success: (res) => {
-      plateNo.value = res.plateNumber;
-      save({
-        defaultPlateNo: res.plateNumber,
-      });
-    },
-    fail: (err) => {
-      console.log(err);
-    },
-  });
-}
+// 地区选择器方法
+const toggleRegionPicker = () => {
+  showRegionPicker.value = !showRegionPicker.value;
+};
 
+const selectRegion = (region) => {
+  plateChars.value[0] = region;
+  toggleRegionPicker();
+  if (plateChars.value[1] === '') {
+    currentInputIndex.value = 1;
+  }
+};
+
+const savePlate = () => {
+  const newPlateNo = plateChars.value.filter(char => char !== '').join('');
+  if (newPlateNo.length < 7) {
+    uni.showToast({
+      title: '请输入完整车牌号',
+      icon: 'none'
+    });
+    return;
+  }
+  
+  // 保存到服务器
+  save({
+    defaultPlateNo: newPlateNo,
+  });
+};
 
-const save = (form: Record<string, any>) => {
-  console.log(form)
+const save = (form) => {
+  console.log(form);
   uni.showLoading({
     title: "保存中",
   });
   body(`/user/updateUser`, form).then(() => {
     uni.hideLoading();
-    getApp<any>().globalData.user.defaultPlateNo = form.defaultPlateNo;
+    getApp().globalData.user.defaultPlateNo = form.defaultPlateNo;
+    plateNo.value = form.defaultPlateNo;
     uni.showToast({
       icon: "success",
       title: "保存成功",
     });
-  }).catch((err: any) => {
+    setTimeout(() => {
+      uni.navigateBack();
+    }, 1500);
+  }).catch((err) => {
     uni.hideLoading();
-  })
-};
-
-
-const logoutUser = () => {
-  uni.showModal({
-    title: "温馨提示",
-    content: "确定退出登录吗?",
-    confirmColor: "#2d9e95",
-    confirmText: "确定退出",
-    cancelText: "手滑了",
-    success: (res) => {
-      if (res.confirm) {
-        uni.showLoading({
-          title: "退出中",
-        });
-
-        get(`/user/logout`).then(() => {
-          uni.hideLoading();
-          uni.showToast({
-            icon: "success",
-            title: "已退出",
-          });
-
-          clearToken();
-          setTimeout(() => {
-            uni.reLaunch({
-              url: "/pages/index/index",
-            });
-          }, 1500);
-
-        })
-      }
-    },
+    uni.showToast({
+      title: "保存失败",
+      icon: "none"
+    });
   });
 };
 
-
 onLoad(() => {
-  if (getApp<any>().globalData.user) {
-    const user = getApp<any>().globalData.user;
+  if (getApp().globalData.user) {
+    const user = getApp().globalData.user;
     plateNo.value = user.defaultPlateNo || "未绑定";
+    if (user.defaultPlateNo) {
+      // 初始化已有车牌号
+      const plate = user.defaultPlateNo;
+      plateChars.value = ['粤', 'B', '', '', '', '', '', ''];
+      for (let i = 0; i < plate.length && i < plateChars.value.length; i++) {
+        plateChars.value[i] = plate[i];
+      }
+    }
   }
 });
 
-
 onShow(() => {
-  if (getApp<any>().globalData.user) {
-    const user = getApp<any>().globalData.user;
+  if (getApp().globalData.user) {
+    const user = getApp().globalData.user;
     plateNo.value = user.defaultPlateNo || "未绑定";
   }
-
-
 });
 </script>
 
 <style lang="scss">
-.logout-btn{
-  width: calc(100vw - 60rpx);
-  margin: 60rpx auto;
+.plate-page {
+  background-color: #f5f5f5;
+  min-height: 100vh;
+  box-sizing: border-box;
+  padding-bottom: 200rpx;
+}
+
+.plate-input-section {
+  background-color: #fff;
+  padding: 30rpx;
+  box-sizing: border-box;
+  margin-bottom: 20rpx;
+}
+
+.plate-input-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 10rpx;
+}
+
+.plate-label {
+  font-size: 32rpx;
+  font-weight: 600;
+  color: #333;
+}
+
+.default-checkbox {
+  display: flex;
+  align-items: center;
+  gap: 8rpx;
+}
+
+.default-text {
+  font-size: 28rpx;
+  color: #666;
+}
+
+.plate-input-hint {
+  margin-bottom: 30rpx;
+}
+
+.plate-input-hint text {
+  font-size: 24rpx;
+  color: #999;
+  line-height: 1.5;
+}
+
+.plate-input-container {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 40rpx;
+  gap: 4rpx;
+}
+
+.plate-item {
+  width: 64rpx;
+  height: 88rpx;
+  border: 2rpx solid #ddd;
+  border-radius: 4rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 36rpx;
+  font-weight: 600;
+  color: #333;
+  background-color: #fff;
+  transition: all 0.2s ease;
+  box-sizing: border-box;
+  text-align: center;
+}
+
+.plate-item.active {
+  border-color: #ff6d00;
+  background-color: #fff9f5;
+}
+
+.plate-item.new-energy {
+  border-color: #00c853;
+  background-color: #f1f8e9;
+}
+
+.plate-item.new-energy .placeholder {
+  color: #00c853;
+  font-size: 18rpx;
+  text-align: center;
+  line-height: 20rpx;
+}
+
+.plate-region {
+  background-color: #fafafa;
+  cursor: pointer;
+}
+
+/* 确保占位符文本也居中 */
+.placeholder {
+  text-align: center;
+}
+
+.plate-divider {
+  width: 24rpx;
+  height: 88rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 32rpx;
+  color: #666;
+}
+
+.save-btn-container {
+  margin-top: 20rpx;
+}
+
+.save-btn-container :deep(.uv-button) {
+  height: 80rpx;
+  font-size: 30rpx;
+  border-radius: 40rpx;
+  background-color: #C6171E;
+}
+
+.save-btn-container :deep(.uv-button--disabled) {
+  background-color: #e0e0e0;
+  color: #9e9e9e;
+}
+
+/* 地区选择器样式 */
+.region-picker-container {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background-color: #fff;
+  border-radius: 20rpx 20rpx 0 0;
+  padding: 15rpx;
+  box-sizing: border-box;
+  box-shadow: 0 -4rpx 12rpx rgba(0, 0, 0, 0.05);
+  z-index: 1000;
+  height: 38vh;
+  overflow-y: hidden;
+}
+
+.region-picker-header {
+  display: flex;
+  justify-content: flex-end;
+  margin-bottom: 5rpx;
+  padding: 0 5rpx;
+}
+
+.region-picker-header :deep(.uv-button) {
+  font-size: 30rpx;
+  color: #ff6d00;
+  background-color: transparent;
+  border: none;
+  padding: 5rpx 15rpx;
+}
+
+.region-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6rpx;
+  padding: 5rpx;
+  height: calc(38vh - 60rpx);
+  overflow-y: hidden;
+  justify-content: center;
+}
+
+.region-item {
+  width: 85rpx;
+  height: 65rpx;
+  background-color: #f8f8f8;
+  border-radius: 8rpx;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 40rpx;
+  font-weight: 600;
+  color: #333;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  margin: 0;
+  flex-shrink: 0;
+  flex-basis: calc(16.66% - 8rpx);
+}
+
+.region-item:active {
+  background-color: #ff6d00;
+  color: #fff;
+  transform: scale(0.95);
 }
-</style>
+</style>