staff/pagesB/setting/editInfo.vue

511 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 自定义导航栏 -->
<wd-navbar :bordered="false"
custom-style="background: transparent !important; backdrop-filter: blur(10px) !important; -webkit-backdrop-filter: blur(20px) !important;"
safeAreaInsetTop fixed placeholder>
<template #left>
<view class="li-ml-15 li-mt-10 li-flex li-items-center">
<text v-if="hasMultiplePages" class="ri-arrow-left-s-line li-text-70"
@click="toPages({type:'nav'})"></text>
<text v-if="!hasMultiplePages" class="ri-home-5-line li-text-55 li-mb-8 li-mr-10"
@click="toPages({type:'home'})"></text>
<text class="li-text-42">个人信息</text>
</view>
</template>
</wd-navbar>
<!-- 导航栏背景 -->
<view class="nav-bg-layer"></view>
<!-- 页面背景 -->
<view class="page-bg"></view>
<view class="content">
<!-- 个人信息表单 -->
<view class="form-container">
<!-- 头像设置 -->
<view class="avatar-section" @click="chooseAvatar">
<view class="section-left">
<text class="form-label">头像</text>
</view>
<view class="section-right">
<view class="user-avatar">
<image v-if="userInfo.avatar" :src="userInfo.avatar" mode="aspectFill"></image>
<view v-else class="default-avatar">{{ userInfo.nickname.substring(0, 1) }}</view>
</view>
<text class="ri-arrow-right-s-line arrow-icon"></text>
</view>
</view>
<!-- 昵称设置 -->
<view class="form-section">
<view class="section-left">
<text class="form-label">昵称</text>
</view>
<view class="section-right">
<view class="input-wrapper">
<input class="form-input" type="text" v-model="userInfo.nickname" placeholder="请输入昵称"
@blur="validateNickname" />
</view>
<text class="ri-arrow-right-s-line arrow-icon"></text>
</view>
</view>
<!-- 手机号展示 -->
<view class="form-section">
<view class="section-left">
<text class="form-label">手机号</text>
</view>
<view class="section-right">
<text class="phone-text">{{ formatPhone(userInfo.phone) }}</text>
</view>
</view>
</view>
<!-- 保存按钮 -->
<view class="save-btn-container">
<button class="save-btn" @click="saveUserInfo">保存</button>
</view>
</view>
<!-- 头像选择弹窗 -->
<wd-popup v-model="showAvatarPopup" position="bottom">
<view class="avatar-popup">
<view class="popup-title">修改头像</view>
<view class="avatar-options">
<view class="option-item" @click="handleSelectAlbum">
<text class="ri-image-2-line option-icon"></text>
<text class="option-text">从相册选择</text>
</view>
<view class="option-item" @click="handleTakePhoto">
<text class="ri-camera-line option-icon"></text>
<text class="option-text">拍照</text>
</view>
</view>
<view class="cancel-btn" @click="showAvatarPopup = false">取消</view>
</view>
</wd-popup>
</view>
</template>
<script setup>
import {
ref,
reactive,
onMounted
} from 'vue';
import {
useNavigation
} from '@/hooks/useNavigation';
import {
onLoad
} from '@dcloudio/uni-app'
// 使用导航 composable
const {
hasMultiplePages, // 是否有多个页面在路由栈中
isTabBarPage, // 当前页面是否为 tabBar 页面
checkRouteStack // 检查当前路由栈状态的方法
} = useNavigation()
// 用户信息
const userInfo = reactive({
nickname: '里派用户',
phone: '13800138000',
avatar: ''
});
// 头像选择弹窗
const showAvatarPopup = ref(false);
/**
* 格式化手机号码为带星号格式
*/
const formatPhone = (phone) => {
if (!phone) return '';
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
};
/**
* 校验昵称
*/
const validateNickname = () => {
if (!userInfo.nickname.trim()) {
uni.showToast({
title: '昵称不能为空',
icon: 'none'
});
userInfo.nickname = '里派用户';
}
};
/**
* 选择头像
*/
const chooseAvatar = () => {
showAvatarPopup.value = true;
};
/**
* 从相册选择照片
*/
const handleSelectAlbum = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album'],
success: (res) => {
// 选择成功后关闭弹窗
showAvatarPopup.value = false;
// 处理选中的图片
const tempFilePath = res.tempFilePaths[0];
// 在实际应用中这里应该先上传图片到服务器获取到图片URL后再更新用户头像
// 这里简单模拟一下上传过程
uni.showLoading({
title: '上传中...'
});
setTimeout(() => {
uni.hideLoading();
userInfo.avatar = tempFilePath;
uni.showToast({
title: '头像已更新',
icon: 'success'
});
}, 1000);
}
});
};
/**
* 拍照
*/
const handleTakePhoto = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: (res) => {
// 选择成功后关闭弹窗
showAvatarPopup.value = false;
// 处理拍摄的照片
const tempFilePath = res.tempFilePaths[0];
// 在实际应用中这里应该先上传图片到服务器获取到图片URL后再更新用户头像
// 这里简单模拟一下上传过程
uni.showLoading({
title: '上传中...'
});
setTimeout(() => {
uni.hideLoading();
userInfo.avatar = tempFilePath;
uni.showToast({
title: '头像已更新',
icon: 'success'
});
}, 1000);
}
});
};
const toPages = (item) => {
if (item.type === 'nav') {
uni.navigateBack()
} else if (item.type === 'home') {
// 这里是项目内部的跳转逻辑
uni.switchTab({
url: '/pages/index/index'
})
}
}
/**
* 保存用户信息
*/
const saveUserInfo = () => {
// 表单验证
if (!userInfo.nickname.trim()) {
uni.showToast({
title: '昵称不能为空',
icon: 'none'
});
return;
}
// 显示加载中
uni.showLoading({
title: '保存中...'
});
// 模拟保存过程
setTimeout(() => {
// 保存成功后的处理
uni.hideLoading();
// 将用户信息保存到缓存
uni.setStorageSync('userInfo', JSON.stringify(userInfo));
// 显示成功提示
uni.showToast({
title: '保存成功',
icon: 'success'
});
// 返回上一页
setTimeout(() => {
goBack();
}, 1500);
}, 1000);
};
/**
* 返回上一页
*/
const goBack = () => {
uni.navigateBack();
};
onMounted(() => {
checkRouteStack()
// 获取用户信息
const userInfoStorage = uni.getStorageSync('userInfo');
if (userInfoStorage) {
Object.assign(userInfo, JSON.parse(userInfoStorage));
}
});
</script>
<style lang="scss" scoped>
/* 主容器 */
.container {
min-height: 100vh;
background-color: transparent;
position: relative;
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, Helvetica, Segoe UI, Arial, Roboto, PingFang SC, sans-serif;
padding-bottom: env(safe-area-inset-bottom);
}
/* 导航栏背景 */
.nav-bg-layer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: calc(var(--status-bar-height) + 88rpx);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.9) 100%);
z-index: -1;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
/* 页面背景 */
.page-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #f8fafd 0%, #eef2f9 100%);
z-index: -2;
}
/* 内容区域 */
.content {
position: relative;
z-index: 2;
padding: 30rpx;
}
/* 表单容器 */
.form-container {
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
margin-bottom: 40rpx;
}
/* 头像设置区域 */
.avatar-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1px solid #f5f5f5;
.section-left {
.form-label {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
}
.section-right {
display: flex;
align-items: center;
.user-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 16rpx;
border: 2rpx solid rgba(0, 0, 0, 0.05);
image {
width: 100%;
height: 100%;
}
.default-avatar {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #4080FF, #5E96FF);
color: #fff;
font-size: 48rpx;
font-weight: bold;
}
}
.arrow-icon {
font-size: 44rpx;
color: #ccc;
}
}
}
/* 表单项 */
.form-section {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1px solid #f5f5f5;
&:last-child {
border-bottom: none;
}
.section-left {
.form-label {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
}
.section-right {
display: flex;
align-items: center;
.input-wrapper {
text-align: right;
.form-input {
font-size: 30rpx;
color: #333;
text-align: right;
min-width: 200rpx;
}
}
.phone-text {
font-size: 30rpx;
color: #999;
}
.arrow-icon {
font-size: 44rpx;
color: #ccc;
margin-left: 16rpx;
}
}
}
/* 保存按钮 */
.save-btn-container {
padding: 0 20rpx;
margin-top: 60rpx;
.save-btn {
background-color: #4080FF;
color: #fff;
border: none;
height: 96rpx;
line-height: 96rpx;
font-size: 32rpx;
border-radius: 16rpx;
font-weight: 500;
box-shadow: 0 4rpx 16rpx rgba(64, 128, 255, 0.3);
&:active {
background-color: #3a75e6;
}
}
}
/* 头像选择弹窗 */
.avatar-popup {
background-color: #fff;
border-radius: 24rpx 24rpx 0 0;
overflow: hidden;
.popup-title {
text-align: center;
font-size: 32rpx;
font-weight: 600;
color: #333;
padding: 30rpx 0;
border-bottom: 1px solid #f0f0f0;
}
.avatar-options {
padding: 20rpx 0;
.option-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 30rpx 0;
.option-icon {
font-size: 60rpx;
color: #4080FF;
margin-bottom: 16rpx;
}
.option-text {
font-size: 28rpx;
color: #333;
}
}
}
.cancel-btn {
border-top: 12rpx solid #f5f5f5;
text-align: center;
padding: 30rpx 0;
font-size: 32rpx;
color: #999;
&:active {
background-color: #f8f8f8;
}
}
}
</style>