init
This commit is contained in:
793
src/pages/profile/index.vue
Normal file
793
src/pages/profile/index.vue
Normal file
@@ -0,0 +1,793 @@
|
||||
<template>
|
||||
<view class="profile-page">
|
||||
<!-- 用户信息区域 -->
|
||||
<view class="user-info">
|
||||
<view class="avatar-section">
|
||||
<view class="avatar-container" @click="previewAvatar">
|
||||
<image v-if="userInfo.driverInfo?.data?.driverHead"
|
||||
:src="getImageUrl(userInfo.driverInfo.data.driverHead)" :key="avatarKey"
|
||||
class="avatar-image" mode="aspectFill" />
|
||||
<view v-else class="avatar-placeholder">
|
||||
<My size="60" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="user-details">
|
||||
<text class="username">{{ userInfo.driverInfo?.data?.driverName || userInfo.username || '点击登录' }}</text>
|
||||
<text class="phone-number">{{ userInfo.driverInfo?.data?.driverTel || '未设置' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单区域 -->
|
||||
<view class="menu-section">
|
||||
<!-- 我的车辆 -->
|
||||
<!-- <view class="menu-item" @click="goToMyVehicles">
|
||||
<view class="menu-icon">
|
||||
<Cart size="40" color="#666" />
|
||||
</view>
|
||||
<text class="menu-text">我的车辆</text>
|
||||
<view class="menu-arrow">
|
||||
<Right size="32" color="#999" />
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 历史运送车次 -->
|
||||
<view class="menu-item" @click="goToTrips">
|
||||
<view class="menu-icon">
|
||||
<Order size="40" color="#666" />
|
||||
</view>
|
||||
<view class="menu-content">
|
||||
<text class="menu-text">历史运送车次</text>
|
||||
</view>
|
||||
<view class="menu-arrow">
|
||||
<Right size="32" color="#999" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 修改头像 -->
|
||||
<view class="menu-item" @click="changeAvatar" :class="{ 'disabled': isUploadingAvatar }">
|
||||
<view class="menu-icon">
|
||||
<My size="40" color="#666" />
|
||||
</view>
|
||||
<view class="menu-content">
|
||||
<text class="menu-text">{{ isUploadingAvatar ? '头像上传中...' : '修改头像' }}</text>
|
||||
</view>
|
||||
<view class="menu-arrow" v-if="!isUploadingAvatar">
|
||||
<Right size="32" color="#999" />
|
||||
</view>
|
||||
<view class="menu-loading" v-else>
|
||||
<text class="loading-text">...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 实名认证 -->
|
||||
<view class="menu-item" @click="goToIdentity">
|
||||
<view class="menu-icon">
|
||||
<My size="40" color="#666" />
|
||||
</view>
|
||||
<view class="menu-content">
|
||||
<text class="menu-text">实名认证</text>
|
||||
<view v-if="driverStatus" class="status-badge" :class="statusClass">
|
||||
<text class="status-text">{{ statusText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="menu-arrow">
|
||||
<Right size="32" color="#999" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 修改密码 -->
|
||||
<view class="menu-item" @click="changePassword">
|
||||
<view class="menu-icon">
|
||||
<Setting size="40" color="#666" />
|
||||
</view>
|
||||
<view class="menu-content">
|
||||
<text class="menu-text">修改密码</text>
|
||||
</view>
|
||||
<view class="menu-arrow">
|
||||
<Right size="32" color="#999" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<view class="logout-section">
|
||||
<nut-button type="danger" size="large" @click="handleLogout" v-if="userInfo.isLogin">
|
||||
退出登录
|
||||
</nut-button>
|
||||
<nut-button type="primary" size="large" @click="login" v-else>
|
||||
立即登录
|
||||
</nut-button>
|
||||
</view>
|
||||
|
||||
<!-- Toast 提示 -->
|
||||
<nut-toast v-model:visible="showToast" :msg="toastMsg" />
|
||||
|
||||
<!-- 头像预览弹窗 -->
|
||||
<nut-popup v-model:visible="showAvatarPreview" position="center">
|
||||
<view class="avatar-preview-dialog">
|
||||
<view class="preview-title">头像预览</view>
|
||||
<view class="avatar-preview">
|
||||
<image v-if="userInfo.driverInfo?.data?.driverHead || userInfo.avatar"
|
||||
:src="userInfo.driverInfo?.data?.driverHead ? getImageUrl(userInfo.driverInfo.data.driverHead) : userInfo.avatar"
|
||||
class="preview-avatar-image" mode="aspectFill" />
|
||||
<view v-else class="preview-avatar-placeholder">
|
||||
<My size="100" color="#666" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="preview-buttons">
|
||||
<nut-button @click="showAvatarPreview = false">关闭</nut-button>
|
||||
<nut-button type="primary" @click="selectNewAvatar" :disabled="isUploadingAvatar">
|
||||
{{ isUploadingAvatar ? '上传中...' : '选择新头像' }}
|
||||
</nut-button>
|
||||
</view>
|
||||
</view>
|
||||
</nut-popup>
|
||||
|
||||
<!-- 修改密码弹窗 -->
|
||||
<nut-popup v-model:visible="showPasswordDialog" position="center">
|
||||
<view class="password-dialog">
|
||||
<view class="dialog-title">修改密码</view>
|
||||
<nut-form>
|
||||
<nut-form-item label="原密码">
|
||||
<nut-input v-model="passwordForm.oldPassword" type="password" placeholder="请输入原密码" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="新密码">
|
||||
<nut-input v-model="passwordForm.newPassword" type="password" placeholder="请输入新密码" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="确认密码">
|
||||
<nut-input v-model="passwordForm.confirmPassword" type="password" placeholder="请再次输入新密码" />
|
||||
</nut-form-item>
|
||||
</nut-form>
|
||||
<view class="dialog-buttons">
|
||||
<nut-button @click="showPasswordDialog = false">取消</nut-button>
|
||||
<nut-button type="primary" @click="submitPassword">确认</nut-button>
|
||||
</view>
|
||||
</view>
|
||||
</nut-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, nextTick, computed } from 'vue'
|
||||
import { Button, Toast, Avatar, Popup, Form, FormItem, Input } from '@nutui/nutui-taro'
|
||||
import { Cart, Order, Setting, Right, My } from '@nutui/icons-vue'
|
||||
import Taro, { useDidShow } from '@tarojs/taro'
|
||||
import { getUserInfo, logout, isLoggedIn, saveUserInfo, checkLoginAndRedirect } from '../../utils/auth.js'
|
||||
import { driverAPI } from '../../api/index'
|
||||
import { API_CONFIG } from '../../utils/request.js'
|
||||
|
||||
// 用户信息
|
||||
const userInfo = reactive({
|
||||
isLogin: false,
|
||||
username: '',
|
||||
userId: '',
|
||||
phone: '',
|
||||
avatar: ''
|
||||
})
|
||||
|
||||
// 页面加载时检查登录状态
|
||||
onMounted(() => {
|
||||
// 检查登录状态,未登录则跳转到登录页
|
||||
if (!checkLoginAndRedirect()) {
|
||||
return
|
||||
}
|
||||
|
||||
// 已登录,获取用户信息
|
||||
const storedUserInfo = getUserInfo()
|
||||
if (storedUserInfo) {
|
||||
Object.assign(userInfo, storedUserInfo)
|
||||
}
|
||||
})
|
||||
|
||||
// 页面显示时重新获取用户信息
|
||||
useDidShow(() => {
|
||||
// 检查登录状态,未登录则跳转到登录页
|
||||
if (!checkLoginAndRedirect()) {
|
||||
return
|
||||
}
|
||||
|
||||
// 已登录,重新获取用户信息
|
||||
const storedUserInfo = getUserInfo()
|
||||
if (storedUserInfo) {
|
||||
Object.assign(userInfo, storedUserInfo)
|
||||
|
||||
// 如果头像有变化,强制重新渲染
|
||||
if (storedUserInfo.driverInfo?.data?.driverHead || storedUserInfo.avatar) {
|
||||
avatarKey.value++
|
||||
}
|
||||
} else {
|
||||
Object.assign(userInfo, {
|
||||
isLogin: false,
|
||||
username: '',
|
||||
userId: '',
|
||||
phone: '',
|
||||
avatar: ''
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新司机数据以获取最新的认证状态
|
||||
refreshDriverData()
|
||||
})
|
||||
|
||||
// Toast 相关
|
||||
const showToast = ref(false)
|
||||
const toastMsg = ref('')
|
||||
|
||||
// 头像预览弹窗
|
||||
const showAvatarPreview = ref(false)
|
||||
|
||||
// 修改密码弹窗
|
||||
const showPasswordDialog = ref(false)
|
||||
const passwordForm = reactive({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
})
|
||||
|
||||
// 头像上传状态
|
||||
const isUploadingAvatar = ref(false)
|
||||
|
||||
// 头像key,用于强制重新渲染
|
||||
const avatarKey = ref(0)
|
||||
|
||||
// 司机状态相关
|
||||
const driverStatus = computed(() => {
|
||||
return userInfo.driverInfo?.data?.driverStatus
|
||||
})
|
||||
|
||||
const statusText = computed(() => {
|
||||
const status = driverStatus.value
|
||||
if (status === '0') return '待认证'
|
||||
if (status === '1') return '正常'
|
||||
if (status === '2') return '冻结'
|
||||
return '未知状态'
|
||||
})
|
||||
|
||||
// 获取图片完整URL
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return ''
|
||||
// 如果已经是完整URL,直接返回
|
||||
if (path.startsWith('http')) {
|
||||
return path
|
||||
}
|
||||
// 拼接API地址
|
||||
return `${API_CONFIG.BASE_URL}api${path.startsWith('/') ? path : '/' + path}`
|
||||
}
|
||||
|
||||
const statusClass = computed(() => {
|
||||
const status = driverStatus.value
|
||||
if (status === '0') return 'status-pending'
|
||||
if (status === '1') return 'status-normal'
|
||||
if (status === '2') return 'status-frozen'
|
||||
return 'status-unknown'
|
||||
})
|
||||
|
||||
// 显示提示
|
||||
const showMessage = (msg) => {
|
||||
toastMsg.value = msg
|
||||
showToast.value = true
|
||||
}
|
||||
|
||||
// 刷新司机数据
|
||||
const refreshDriverData = async () => {
|
||||
try {
|
||||
const storedUserInfo = getUserInfo()
|
||||
if (!storedUserInfo) {
|
||||
console.error('无法获取用户信息')
|
||||
return
|
||||
}
|
||||
|
||||
// 获取用户ID
|
||||
const userId = storedUserInfo.userId || storedUserInfo.id || storedUserInfo.user?.id
|
||||
if (!userId) {
|
||||
console.error('无法获取用户ID')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 调用API获取最新的司机信息
|
||||
const response = await driverAPI.getDriverInfo(userId)
|
||||
|
||||
if (response.statusCode === 200 && response.data) {
|
||||
if (response.data.code === 0 && response.data.data) {
|
||||
// 更新本地用户信息中的司机数据
|
||||
const updatedUserInfo = {
|
||||
...storedUserInfo,
|
||||
driverInfo: {
|
||||
...storedUserInfo.driverInfo,
|
||||
data: response.data.data
|
||||
}
|
||||
}
|
||||
|
||||
// 保存更新后的用户信息
|
||||
saveUserInfo(updatedUserInfo)
|
||||
|
||||
// 更新当前页面的用户信息
|
||||
Object.assign(userInfo, updatedUserInfo)
|
||||
} else {
|
||||
console.error('获取司机信息失败:', response.data)
|
||||
}
|
||||
} else {
|
||||
console.error('获取司机信息API调用失败:', response)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('刷新司机数据失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 预览头像
|
||||
const previewAvatar = () => {
|
||||
if (!userInfo.isLogin) {
|
||||
showMessage('请先登录')
|
||||
return
|
||||
}
|
||||
showAvatarPreview.value = true
|
||||
}
|
||||
|
||||
// 更换头像
|
||||
const changeAvatar = () => {
|
||||
if (!userInfo.isLogin) {
|
||||
showMessage('请先登录')
|
||||
return
|
||||
}
|
||||
selectNewAvatar()
|
||||
}
|
||||
|
||||
// 选择新头像
|
||||
const selectNewAvatar = () => {
|
||||
showAvatarPreview.value = false
|
||||
|
||||
if (isUploadingAvatar.value) {
|
||||
showMessage('头像上传中,请稍候...')
|
||||
return
|
||||
}
|
||||
|
||||
Taro.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const tempFilePath = res.tempFilePaths[0]
|
||||
|
||||
// 将图片转换为base64
|
||||
Taro.getFileSystemManager().readFile({
|
||||
filePath: tempFilePath,
|
||||
encoding: 'base64',
|
||||
success: (fileRes) => {
|
||||
const base64Data = `data:image/jpeg;base64,${fileRes.data}`
|
||||
|
||||
// 上传头像
|
||||
uploadAvatar(base64Data)
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('读取图片文件失败:', error)
|
||||
showMessage('头像处理失败,请重试')
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: (error) => {
|
||||
console.error('选择图片失败:', error)
|
||||
showMessage('选择头像失败,请重试')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 上传头像
|
||||
const uploadAvatar = async (base64Data) => {
|
||||
if (isUploadingAvatar.value) return
|
||||
|
||||
isUploadingAvatar.value = true
|
||||
showMessage('正在上传头像...')
|
||||
|
||||
try {
|
||||
|
||||
// 获取当前用户的司机ID
|
||||
const storedUserInfo = getUserInfo()
|
||||
const driverId = storedUserInfo?.driverId || storedUserInfo?.id || userInfo.userId
|
||||
|
||||
if (!driverId) {
|
||||
console.error('未找到司机ID,无法上传头像')
|
||||
showMessage('用户信息不完整,请重新登录')
|
||||
return
|
||||
}
|
||||
|
||||
const updateData = {
|
||||
id: driverId,
|
||||
driverHead: base64Data
|
||||
}
|
||||
|
||||
const updateResponse = await driverAPI.updateDriverHead(updateData)
|
||||
|
||||
if (updateResponse.statusCode === 200 && updateResponse.data) {
|
||||
if (updateResponse.data.code === 0) {
|
||||
// 获取服务器返回的图片路径
|
||||
const imagePath = updateResponse.data.data || updateResponse.data.path || updateResponse.data.url
|
||||
|
||||
if (imagePath) {
|
||||
// 更新driverInfo.data.driverHead字段为服务器返回的路径
|
||||
if (userInfo.driverInfo && userInfo.driverInfo.data) {
|
||||
userInfo.driverInfo.data.driverHead = imagePath
|
||||
}
|
||||
|
||||
// 强制触发响应式更新
|
||||
await nextTick()
|
||||
|
||||
// 强制重新渲染头像
|
||||
avatarKey.value++
|
||||
|
||||
// 更新本地存储的用户信息
|
||||
if (storedUserInfo) {
|
||||
// 同时更新driverInfo中的头像字段
|
||||
if (storedUserInfo.driverInfo && storedUserInfo.driverInfo.data) {
|
||||
storedUserInfo.driverInfo.data.driverHead = imagePath
|
||||
}
|
||||
Taro.setStorageSync('userInfo', storedUserInfo)
|
||||
}
|
||||
|
||||
showMessage('头像更新成功')
|
||||
} else {
|
||||
console.error('服务器未返回图片路径')
|
||||
showMessage('头像上传失败:未获取到图片路径')
|
||||
}
|
||||
} else {
|
||||
const errorMsg = updateResponse.data?.msg || updateResponse.data?.message || '头像上传失败'
|
||||
console.error('头像上传业务失败:', updateResponse.data)
|
||||
showMessage(errorMsg)
|
||||
}
|
||||
} else {
|
||||
const errorMsg = updateResponse.data?.msg || updateResponse.data?.message || '头像上传失败'
|
||||
showMessage(errorMsg)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('头像上传失败:', error)
|
||||
showMessage('头像上传失败,请重试')
|
||||
} finally {
|
||||
isUploadingAvatar.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 我的车辆
|
||||
const goToMyVehicles = () => {
|
||||
showMessage('跳转到我的车辆页面')
|
||||
// 这里可以跳转到车辆页面
|
||||
// Taro.navigateTo({ url: '/pages/vehicle/index' })
|
||||
}
|
||||
|
||||
// 历史运送车次
|
||||
const goToTrips = () => {
|
||||
Taro.navigateTo({ url: '/pages/history/index' })
|
||||
}
|
||||
|
||||
// 实名认证
|
||||
const goToIdentity = () => {
|
||||
Taro.navigateTo({ url: '/pages/realname/index' })
|
||||
}
|
||||
|
||||
// 修改密码
|
||||
const changePassword = () => {
|
||||
Taro.navigateTo({ url: '/pages/password/index' })
|
||||
}
|
||||
|
||||
// 提交密码修改
|
||||
const submitPassword = () => {
|
||||
if (!passwordForm.oldPassword || !passwordForm.newPassword || !passwordForm.confirmPassword) {
|
||||
showMessage('请填写完整信息')
|
||||
return
|
||||
}
|
||||
|
||||
if (passwordForm.newPassword !== passwordForm.confirmPassword) {
|
||||
showMessage('两次输入的密码不一致')
|
||||
return
|
||||
}
|
||||
|
||||
if (passwordForm.newPassword.length < 6) {
|
||||
showMessage('密码长度不能少于6位')
|
||||
return
|
||||
}
|
||||
|
||||
// 这里调用修改密码的API
|
||||
showMessage('密码修改成功')
|
||||
showPasswordDialog.value = false
|
||||
|
||||
// 清空表单
|
||||
passwordForm.oldPassword = ''
|
||||
passwordForm.newPassword = ''
|
||||
passwordForm.confirmPassword = ''
|
||||
}
|
||||
|
||||
|
||||
// 登录
|
||||
const login = () => {
|
||||
Taro.navigateTo({ url: '/pages/login/index' })
|
||||
}
|
||||
|
||||
// 退出登录
|
||||
const handleLogout = () => {
|
||||
logout() // 使用认证工具中的退出登录函数
|
||||
showMessage('已退出登录')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.profile-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 用户信息区域 */
|
||||
.user-info {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 60rpx 40rpx;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.avatar-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
margin-left: 40rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.username {
|
||||
display: block;
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.user-id {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.phone-number {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 状态徽章 */
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
width: fit-content;
|
||||
max-width: 200rpx;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: rgba(255, 193, 7, 0.2);
|
||||
color: #ffc107;
|
||||
border: 1rpx solid rgba(255, 193, 7, 0.3);
|
||||
}
|
||||
|
||||
.status-normal {
|
||||
background: rgba(40, 167, 69, 0.2);
|
||||
color: #28a745;
|
||||
border: 1rpx solid rgba(40, 167, 69, 0.3);
|
||||
}
|
||||
|
||||
.status-frozen {
|
||||
background: rgba(220, 53, 69, 0.2);
|
||||
color: #dc3545;
|
||||
border: 1rpx solid rgba(220, 53, 69, 0.3);
|
||||
}
|
||||
|
||||
.status-unknown {
|
||||
background: rgba(108, 117, 125, 0.2);
|
||||
color: #6c757d;
|
||||
border: 1rpx solid rgba(108, 117, 125, 0.3);
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 功能菜单区域 */
|
||||
.menu-section {
|
||||
background: white;
|
||||
margin: 40rpx;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 40rpx;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.menu-item.disabled {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f0f0f0;
|
||||
border-radius: 16rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.menu-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 32rpx;
|
||||
color: #667eea;
|
||||
animation: loading 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
|
||||
0%,
|
||||
20% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
80%,
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 退出登录区域 */
|
||||
.logout-section {
|
||||
padding: 40rpx;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
/* 头像预览弹窗 */
|
||||
.avatar-preview-dialog {
|
||||
background: white;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
width: 500rpx;
|
||||
max-width: 90vw;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
margin-bottom: 40rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preview-avatar-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.preview-avatar-placeholder {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 50%;
|
||||
background: #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preview-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.preview-buttons .nut-button {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 修改密码弹窗 */
|
||||
.password-dialog {
|
||||
background: white;
|
||||
border-radius: 24rpx;
|
||||
padding: 40rpx;
|
||||
width: 600rpx;
|
||||
max-width: 90vw;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.dialog-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 40rpx;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.dialog-buttons .nut-button {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user