Parcourir la source

feat(my): 添加个人中心页面及基础功能

- 新增个人中心页面布局与样式
- 实现用户登录状态管理与切换逻辑
- 添加修改手机号、修改密码、意见反馈等功能入口
- 集成扫一扫功能并处理扫描结果
- 添加日志上报和免责申明页面跳转
- 实现顶部信息栏展示用户基本信息
- 添加自定义底部导航组件集成
- 支持未登录状态下功能禁用与提示
- 页面间跳转动画效果统一设置为 slide-in-right
- 使用本地存储模拟用户登录凭证管理
nahida il y a 6 mois
Parent
commit
44b2596493
2 fichiers modifiés avec 395 ajouts et 0 suppressions
  1. 165 0
      src/pages/modify-phone/index.vue
  2. 230 0
      src/pages/my/index.vue

+ 165 - 0
src/pages/modify-phone/index.vue

@@ -0,0 +1,165 @@
+<template>
+  <view class="bg-gray-50 p-2">
+    <!-- 移除了左右外边距,使用full宽度 -->
+    <view class="bg-white rounded-xl shadow-sm p-8">
+      <!-- 表单内容 -->
+      <view class="space-y-6">
+        <!-- 密码输入框 -->
+        <view class="flex items-center border-solid border-0 border-b-1 border-gray-200 pb-2">
+          <text class="text-gray-700 text-sm w-1/3">密码:</text>
+          <view class="flex-1 flex items-center border-b border-gray-200 py-2">
+            <input
+                :type="showPassword ? 'text' : 'password'"
+                v-model="form.password"
+                placeholder="请输入密码"
+                class="flex-1 bg-transparent outline-none text-gray-900"
+            />
+            <view class="flex space-x-2">
+              <view v-if="form.password" class="w-36 h-36 flex items-center justify-center text-gray-400" @click="togglePasswordVisibility">
+                <image :src="showPassword ? '/static/eye-close.png' : '/static/eye.png'" class="w-full h-full" />
+              </view>
+              <view v-if="form.password" class="w-36 h-36 flex items-center justify-center text-gray-400" @click="clearPassword">
+                <image src="/static/clear.png" class="w-full h-full" />
+              </view>
+            </view>
+          </view>
+        </view>
+
+        <!-- 手机号输入框 -->
+        <view class="flex items-center border-solid border-0 border-b-1 border-gray-200 pb-2">
+          <text class="text-gray-700 text-sm w-1/3">手机号:</text>
+          <view class="flex-1 flex items-center border-b border-gray-200 py-2">
+            <input
+                type="number"
+                v-model="form.phone"
+                placeholder="请输入手机号"
+                class="flex-1 bg-transparent outline-none text-gray-900"
+            />
+            <view v-if="form.phone" class="w-36 h-36 flex items-center justify-center text-gray-400" @click="clearPhone">
+              <image src="/static/clear.png" class="w-full h-full" />
+            </view>
+          </view>
+        </view>
+
+        <!-- 图形验证码 -->
+        <view class="flex items-center border-solid border-0 border-b-1 border-gray-200 pb-2">
+          <text class="text-gray-700 text-sm w-1/3">图形验证码:</text>
+          <view class="flex-1 flex items-center border-b border-gray-200 py-2">
+            <input
+                type="text"
+                v-model="form.authCode"
+                placeholder="请输入图形验证码"
+                class="flex-1 bg-transparent outline-none text-gray-900"
+            />
+            <!-- 3个元素横向排列的色块验证码 -->
+            <view class="flex space-x-1 px-2 py-1 bg-gray-100 rounded">
+              <view class="w-10 h-10 bg-green-500 rounded-sm flex items-center justify-center text-white font-bold">3</view>
+              <view class="w-10 h-10 bg-blue-500 rounded-sm flex items-center justify-center text-white font-bold">6</view>
+              <view class="w-10 h-10 bg-purple-500 rounded-sm flex items-center justify-center text-white font-bold">1</view>
+            </view>
+          </view>
+        </view>
+
+        <!-- 短信验证码 -->
+        <view class="flex items-center border-solid border-0 border-b-1 border-gray-200 pb-2">
+          <text class="text-gray-700 text-sm w-1/3">短信验证码:</text>
+          <view class="flex-1 flex items-center border-b border-gray-200 py-2">
+            <input
+                type="text"
+                v-model="form.smsCode"
+                placeholder="请输入短信验证码"
+                class="flex-1 bg-transparent outline-none text-gray-900"
+            />
+            <view class="text-blue-500 text-sm border-0" @click="getSmsCode">
+              获取验证码
+            </view>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- 确认按钮在表单外部 - 蓝底白字+加深圆角 -->
+    <view class="mt-6 px-8">
+      <view
+          class="w-full text-center bg-blue-600 text-white py-3 rounded-2xl font-medium shadow-sm hover:bg-blue-700 transition-colors"
+          @click="submitForm"
+      >
+        <text>
+          确认
+        </text>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+
+// 表单数据
+const form = ref({
+  password: '',
+  phone: '',
+  authCode: '',
+  smsCode: ''
+})
+
+// 密码可见性控制
+const showPassword = ref(false)
+
+// 验证手机号格式
+const validatePhone = (phone) => {
+  const phoneRegex = /^1[3-9]\d{9}$/;
+  return phoneRegex.test(phone);
+}
+
+// 获取短信验证码
+const getSmsCode = () => {
+  // 首先检查手机号是否为空
+  if (!form.value.phone) {
+    uni.showToast({
+      title: '请输入手机号',
+      icon: 'none'
+    })
+    return
+  }
+
+  // 验证手机号格式
+  if (!validatePhone(form.value.phone)) {
+    uni.showToast({
+      title: '请输入正确的手机号',
+      icon: 'none'
+    })
+    return
+  }
+
+  // 实际项目中这里调用接口发送验证码
+  uni.showToast({
+    title: '验证码已发送',
+    icon: 'none'
+  })
+}
+
+// 清除密码
+const clearPassword = () => {
+  form.value.password = ''
+}
+
+// 清除手机号
+const clearPhone = () => {
+  form.value.phone = ''
+}
+
+// 切换密码可见性
+const togglePasswordVisibility = () => {
+  showPassword.value = !showPassword.value
+}
+
+// 提交表单
+const submitForm = () => {
+  console.log('表单提交数据:', form.value)
+  uni.showToast({
+    title: '表单已提交',
+    icon: 'none'
+  })
+}
+</script>

+ 230 - 0
src/pages/my/index.vue

@@ -0,0 +1,230 @@
+<template>
+  <!-- 顶部信息栏 -->
+  <view class="profile-header rounded-b-2xl bg-gradient-to-b from-blue-500 to-red-500 text-white py-6 px-4">
+    <view class="flex items-center gap-10 justify-around">
+      <!-- 头像 -->
+      <view class="flex flex-col gap-2 w-5/12">
+        <view class="w-120 h-120 rounded-full bg-gray-200 flex items-center justify-center mx-auto">
+          <image class="w-full h-full" src="/static/my/avatar.png"></image>
+        </view>
+        <view class="text-lg font-semibold text-center">{{ isLoggedIn ? '彭礼' : '游客' }}</view>
+      </view>
+      <!-- 个人信息 -->
+      <view class="w-7/12">
+        <view class="flex items-center mt-1" v-if="isLoggedIn">
+          <view class="text-xs mr-1 w-36 h-36">
+            <image class="w-full h-full" src="/static/my/phone.png"></image>
+          </view>
+          <text class="text-sm">15116297551</text>
+        </view>
+        <view v-if="!isLoggedIn">
+          <text class="text-sm">请登录后查看信息</text>
+        </view>
+        <view v-if="isLoggedIn">
+          上次登录系统时间:
+        </view>
+        <view class="flex items-center mt-1" v-if="isLoggedIn">
+          <view class="text-xs mr-1 w-36 h-36">
+            <image class="w-full h-full" src="/static/my/shad.png"></image>
+          </view>
+          <text class="text-sm">2025-10-29 15:11:41</text>
+        </view>
+      </view>
+    </view>
+  </view>
+
+  <!-- 功能列表 -->
+  <view class="profile-list bg-white">
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4" :class="{ 'opacity-50': !isLoggedIn }" @click="isLoggedIn && toModifyPhone()">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" src="/static/my/telphone.png"></image>
+        </view>
+        <text class="flex-1">修改号码</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4 " :class="{ 'opacity-50': !isLoggedIn }" @click="isLoggedIn && toModifyPassword()">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" src="/static/my/lock.png"></image>
+        </view>
+        <text class="flex-1">修改密码</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4" :class="{ 'opacity-50': !isLoggedIn }" @click="isLoggedIn && toFeedback()">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" src="/static/my/feedback.png"></image>
+        </view>
+        <text class="flex-1">意见反馈</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4" :class="{ 'opacity-50': !isLoggedIn }" @click="isLoggedIn && toLogReport()">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" src="/static/my/log.png"></image>
+        </view>
+        <text class="flex-1">日志上报</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4" :class="{ 'opacity-50': !isLoggedIn }" @click="isLoggedIn && scanQRCode()">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" src="/static/my/scan.png"></image>
+        </view>
+        <text class="flex-1">扫一扫</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4" :class="{ 'opacity-50': !isLoggedIn }" @click="isLoggedIn && toDisclaimer()">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" src="/static/my/info.png"></image>
+        </view>
+        <text class="flex-1">免责申明</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <view class="border-b border-gray-100 bg-#f3f8fd m-4 rounded-2">
+      <view class="flex items-center py-4 px-4" @click="toggleLoginStatus">
+        <view class="text-red-500 mr-2 w-36 h-36">
+          <image class="w-full h-full" :src="isLoggedIn ? '/static/my/logout.png' : '/static/my/login.png'"></image>
+        </view>
+        <text class="flex-1" :class="{ 'text-red-500': isLoggedIn }">{{ isLoggedIn ? '退出登录' : '立即登录' }}</text>
+        <text class="text-gray-400">></text>
+      </view>
+    </view>
+    <CustomTabBar :current="1" />
+  </view>
+
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import CustomTabBar from "@/components/CustomTabBar.vue";
+
+// 添加登录状态响应式变量
+const isLoggedIn = ref(true)
+
+// 模拟检查登录状态
+const checkLoginStatus = () => {
+  // 这里应该检查实际的登录状态,比如检查是否有token等
+  // 暂时从本地存储中检查登录状态
+  const token = uni.getStorageSync('token')
+  isLoggedIn.value = !!token
+}
+
+// 页面加载时检查登录状态
+onMounted(() => {
+  checkLoginStatus()
+})
+
+// 切换登录状态
+const toggleLoginStatus = () => {
+  if (isLoggedIn.value) {
+    // 退出登录
+    uni.showModal({
+      title: '确认退出',
+      content: '您确定要退出登录吗?',
+      cancelText: '取消',
+      confirmText: '确认',
+      success: (res) => {
+        if (res.confirm) {
+          // 执行退出登录逻辑
+          console.log('用户确认退出登录')
+
+          // 清除用户信息(实际项目中这里应该清除token等)
+          uni.clearStorageSync()
+
+          // 更新登录状态
+          isLoggedIn.value = false
+
+          uni.showToast({
+            title: '已退出登录',
+            icon: 'none'
+          })
+        } else {
+          console.log('用户取消退出登录')
+        }
+      }
+    })
+  } else {
+    // 登录方法(模拟)
+    // 这里应该调用实际的登录接口
+    // 模拟登录成功
+    uni.setStorageSync('token', 'fake-token')
+    isLoggedIn.value = true
+
+    uni.showToast({
+      title: '登录成功',
+      icon: 'success'
+    })
+  }
+}
+
+const toModifyPhone = () => {
+  uni.navigateTo({
+    url: '/pages/modify-phone/index',
+    animationType:'slide-in-right',
+    animationDuration:300
+  })
+}
+
+const toModifyPassword = () => {
+  uni.navigateTo({
+    url: '/pages/modify-password/index',
+    animationType:'slide-in-right',
+    animationDuration:300
+  })
+}
+
+const toFeedback = () => {
+  uni.navigateTo({
+    url: '/pages/feedback/index',
+    animationType:'slide-in-right',
+    animationDuration:300
+  })
+}
+
+const toLogReport = () => {
+  uni.navigateTo({
+    url: '/pages/log-report/index',
+    animationType:'slide-in-right',
+    animationDuration:300
+  })
+}
+
+// 扫一扫功能
+const scanQRCode = () => {
+  uni.scanCode({
+    success: (res) => {
+      console.log('扫描结果:', res);
+      uni.showModal({
+        title: '扫描结果',
+        content: res.result,
+        showCancel: false,
+        confirmText: '确定'
+      });
+    },
+    fail: (err) => {
+      console.error('扫描失败:', err);
+      uni.showToast({
+        title: '扫描失败,请重试',
+        icon: 'error'
+      });
+    }
+  });
+}
+
+// 跳转到免责申明页面
+const toDisclaimer = () => {
+  uni.navigateTo({
+    url: '/pages/disclaimer/index',
+    animationType:'slide-in-right',
+    animationDuration:300
+  })
+}
+</script>