794 lines
19 KiB
Vue
794 lines
19 KiB
Vue
<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>
|