Files
ss-tiku-manage-h5/src/pages/mine/personal-info.vue
2026-01-30 14:08:23 +08:00

670 lines
13 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="personal-info-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">个人资料修改</view>
<view class="header-right" @click="saveInfo">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 个人信息表单 -->
<view class="form-section">
<view class="avatar-section">
<view class="avatar-preview" @click="chooseAvatar">
<view v-if="userInfo.avatar" class="avatar-img">
<image :src="userInfo.avatar" mode="aspectFill"></image>
</view>
<view v-else class="avatar-placeholder">
<view class="avatar-icon">{{ userInitial }}</view>
<view class="avatar-tip">点击更换头像</view>
</view>
</view>
</view>
<view class="form-group">
<view class="form-label">姓名</view>
<view class="form-control">
<input
v-model="userInfo.name"
class="form-input"
placeholder="请输入姓名"
maxlength="20"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">手机号</view>
<view class="form-control">
<input
v-model="userInfo.phone"
class="form-input"
placeholder="请输入手机号"
maxlength="15"
type="number"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">邮箱</view>
<view class="form-control">
<input
v-model="userInfo.email"
class="form-input"
placeholder="请输入邮箱"
maxlength="50"
type="email"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">性别</view>
<view class="form-control">
<picker
:value="getGenderIndex()"
:range="genders"
@change="onGenderChange"
class="form-picker"
>
<view class="picker-display">{{ userInfo.gender || '请选择性别' }}</view>
</picker>
</view>
</view>
<view class="form-group">
<view class="form-label">所属驾校</view>
<view class="form-control">
<view class="form-text">{{ userInfo.school || '顺达驾校' }}</view>
</view>
</view>
<view class="form-group">
<view class="form-label">职位</view>
<view class="form-control">
<input
v-model="userInfo.position"
class="form-input"
placeholder="请输入职位"
maxlength="20"
/>
</view>
</view>
<view class="form-group">
<view class="form-label">简介</view>
<view class="form-control">
<textarea
v-model="userInfo.bio"
class="form-textarea"
placeholder="请输入个人简介"
maxlength="200"
rows="3"
></textarea>
</view>
</view>
</view>
<!-- 账号信息 -->
<view class="account-section">
<view class="section-title">账号信息</view>
<view class="account-info">
<view class="info-item">
<view class="info-label">账号ID</view>
<view class="info-value">{{ userInfo.id || '10001' }}</view>
</view>
<view class="info-item">
<view class="info-label">注册时间</view>
<view class="info-value">{{ userInfo.registerTime || '2026-01-01' }}</view>
</view>
<view class="info-item">
<view class="info-label">最后登录</view>
<view class="info-value">{{ userInfo.lastLogin || '2026-01-29' }}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
// 性别选项
const genders = ['男', '女', '保密']
// 用户信息
const userInfo = ref({
name: '李教练',
phone: '13900139000',
email: 'li@shunda.com',
gender: '男',
school: '顺达驾校',
position: '科目二教练',
bio: '拥有10年驾驶教学经验擅长科目二倒车入库教学',
id: '10002',
registerTime: '2026-01-15',
lastLogin: '2026-01-29 10:30:00'
})
// 计算用户名首字母
const userInitial = computed(() => {
return userInfo.value.name ? userInfo.value.name.charAt(0).toUpperCase() : 'U'
})
onMounted(() => {
// 实际项目中应从接口获取用户信息
// loadUserInfo()
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 获取性别索引
function getGenderIndex() {
return genders.indexOf(userInfo.value.gender)
}
// 处理性别变更
function onGenderChange(e) {
const index = e.detail.value
userInfo.value.gender = genders[index]
}
// 选择头像
function chooseAvatar() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function(res) {
// 实际项目中应上传图片到服务器
userInfo.value.avatar = res.tempFilePaths[0]
}
})
}
// 保存个人信息
function saveInfo() {
// 表单验证
if (!userInfo.value.name) {
uni.showToast({ title: '请输入姓名', icon: 'none' })
return
}
if (!userInfo.value.phone) {
uni.showToast({ title: '请输入手机号', icon: 'none' })
return
}
// 实际项目中应调用接口保存信息
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '保存成功', icon: 'success' })
goBack()
}, 1000)
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.personal-info-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 28rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 表单区域 */
.form-section {
flex: 1;
padding: 32rpx;
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
/* 头像部分 */
.avatar-section {
display: flex;
justify-content: center;
margin-bottom: 40rpx;
}
.avatar-preview {
width: 200rpx;
height: 200rpx;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
background-color: #f0f0f0;
}
.avatar-img {
width: 100%;
height: 100%;
}
.avatar-img image {
width: 100%;
height: 100%;
}
.avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #409eff 0%, #667eea 100%);
color: #fff;
}
.avatar-icon {
font-size: 80rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.avatar-tip {
font-size: 20rpx;
opacity: 0.9;
}
.form-group {
margin-bottom: 32rpx;
}
.form-label {
font-size: 28rpx;
font-weight: 600;
color: #303133;
margin-bottom: 12rpx;
line-height: 1.2;
}
.form-control {
position: relative;
}
.form-input {
width: 100%;
height: 80rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-textarea {
width: 100%;
min-height: 160rpx;
padding: 24rpx;
font-size: 28rpx;
color: #303133;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
resize: none;
}
.form-textarea:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.form-picker {
width: 100%;
height: 80rpx;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
background-color: #f9f9f9;
box-sizing: border-box;
}
.picker-display {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 0 24rpx;
font-size: 28rpx;
color: #303133;
}
.form-text {
width: 100%;
height: 80rpx;
display: flex;
align-items: center;
padding: 0 24rpx;
font-size: 28rpx;
color: #606266;
background-color: #f9f9f9;
border-radius: 8rpx;
box-sizing: border-box;
}
/* 账号信息 */
.account-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 32rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.account-info {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #e4e7ed;
}
.info-item:last-child {
border-bottom: none;
}
.info-label {
font-size: 28rpx;
color: #606266;
}
.info-value {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.personal-info-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.page-header {
height: 140rpx;
padding: 0 48rpx;
}
.header-title {
font-size: 36rpx;
}
.back-icon {
font-size: 48rpx;
}
.save-btn {
font-size: 32rpx;
}
.form-section {
margin: 24rpx;
padding: 40rpx;
}
.avatar-section {
margin-bottom: 48rpx;
}
.avatar-preview {
width: 240rpx;
height: 240rpx;
}
.avatar-icon {
font-size: 96rpx;
}
.avatar-tip {
font-size: 24rpx;
}
.form-group {
margin-bottom: 40rpx;
}
.form-label {
font-size: 32rpx;
margin-bottom: 16rpx;
}
.form-input {
height: 96rpx;
font-size: 32rpx;
padding: 0 32rpx;
}
.form-textarea {
min-height: 200rpx;
font-size: 32rpx;
padding: 32rpx;
}
.form-text {
height: 96rpx;
font-size: 32rpx;
padding: 0 32rpx;
}
.picker-display {
font-size: 32rpx;
padding: 0 32rpx;
}
.account-section {
margin: 0 24rpx 32rpx;
padding: 40rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 32rpx;
}
.account-info {
gap: 24rpx;
}
.info-item {
padding: 24rpx 0;
}
.info-label,
.info-value {
font-size: 32rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.personal-info-container {
max-width: 1000px;
}
.page-header {
height: 160rpx;
padding: 0 64rpx;
}
.header-title {
font-size: 40rpx;
}
.back-icon {
font-size: 56rpx;
}
.save-btn {
font-size: 36rpx;
}
.form-section {
padding: 48rpx;
}
.avatar-section {
margin-bottom: 56rpx;
}
.avatar-preview {
width: 280rpx;
height: 280rpx;
}
.avatar-icon {
font-size: 112rpx;
}
.avatar-tip {
font-size: 28rpx;
}
.form-group {
margin-bottom: 48rpx;
}
.form-label {
font-size: 36rpx;
margin-bottom: 20rpx;
}
.form-input {
height: 112rpx;
font-size: 36rpx;
padding: 0 40rpx;
}
.form-textarea {
min-height: 240rpx;
font-size: 36rpx;
padding: 40rpx;
}
.form-text {
height: 112rpx;
font-size: 36rpx;
padding: 0 40rpx;
}
.picker-display {
font-size: 36rpx;
padding: 0 40rpx;
}
.account-section {
padding: 48rpx;
}
.section-title {
font-size: 40rpx;
margin-bottom: 40rpx;
}
.account-info {
gap: 28rpx;
}
.info-item {
padding: 28rpx 0;
}
.info-label,
.info-value {
font-size: 36rpx;
}
}
</style>