Merge remote-tracking branch 'origin/master'
This commit is contained in:
@ -147,6 +147,14 @@
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/profile",
|
||||
"type": "page",
|
||||
"layout": "default",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/notice/bill",
|
||||
"type": "page",
|
||||
|
||||
@ -123,8 +123,8 @@ onUnload(() => {
|
||||
const My = {
|
||||
// 跳转到个人信息
|
||||
handleToProfile: () => {
|
||||
if (isLogin.value) {
|
||||
router.navigateTo('/bundle/profile/profile')
|
||||
if (!isLogin.value) {
|
||||
router.navigateTo('/pages/my/profile')
|
||||
}
|
||||
else {
|
||||
router.navigateTo('/pages/login/login')
|
||||
|
||||
352
src/pages/my/profile.vue
Normal file
352
src/pages/my/profile.vue
Normal file
@ -0,0 +1,352 @@
|
||||
<route lang="jsonc" type="page">
|
||||
{
|
||||
"layout": "default",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
</route>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { IUserResult } from '@/api/types/user'
|
||||
import { updateUserInfo } from '@/api/user'
|
||||
import { toast } from '@/utils/toast'
|
||||
import { router } from '@/utils/tools'
|
||||
import { uploadFileUrl, useUpload } from '@/utils/uploadFile'
|
||||
import defaultAvatarImg from './img/头像.png'
|
||||
|
||||
const OSS = inject('OSS')
|
||||
const navbarHeight = inject('navbarHeight')
|
||||
|
||||
// 本地图片资源
|
||||
const defaultAvatar = defaultAvatarImg as string
|
||||
|
||||
// 用户信息相关
|
||||
const user = ref<IUserResult>({
|
||||
id: 0,
|
||||
sn: 0,
|
||||
sex: '未知',
|
||||
account: '',
|
||||
nickname: '',
|
||||
real_name: '',
|
||||
avatar: '',
|
||||
collect_count: 0,
|
||||
coupon_count: 0,
|
||||
create_time: '',
|
||||
has_auth: false,
|
||||
has_password: false,
|
||||
member: 0,
|
||||
mobile: '',
|
||||
user_money: '0.00',
|
||||
version: '',
|
||||
})
|
||||
|
||||
// Action Sheet 相关
|
||||
const showAvatarActionSheet = ref(false)
|
||||
const avatarActions = ref([
|
||||
{
|
||||
name: '拍照',
|
||||
value: 'camera',
|
||||
},
|
||||
{
|
||||
name: '从手机相册选择',
|
||||
value: 'album',
|
||||
},
|
||||
])
|
||||
|
||||
// 编辑昵称相关
|
||||
const showEditNicknamePopup = ref(false)
|
||||
const nicknameInput = ref('')
|
||||
|
||||
/**
|
||||
* 上传头像文件
|
||||
*/
|
||||
function handleUploadAvatar(filePath: string) {
|
||||
const { run: uploadFile } = useUpload<string>(
|
||||
uploadFileUrl.USER_AVATAR,
|
||||
{},
|
||||
{
|
||||
maxSize: 5,
|
||||
onSuccess: async (res) => {
|
||||
try {
|
||||
const avatarUrl = typeof res === 'string' ? res : (res as any).uri || (res as any).url
|
||||
await updateUserInfo({ field: 'avatar', value: avatarUrl })
|
||||
user.value.avatar = avatarUrl
|
||||
toast.info('头像上传成功')
|
||||
}
|
||||
catch (error) {
|
||||
console.error('更新头像失败:', error)
|
||||
toast.info('头像上传失败')
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error('上传失败:', err)
|
||||
toast.info('头像上传失败')
|
||||
},
|
||||
},
|
||||
filePath,
|
||||
)
|
||||
uploadFile()
|
||||
}
|
||||
|
||||
/**
|
||||
* 掩码处理手机号
|
||||
*/
|
||||
const maskedMobile = computed(() => {
|
||||
if (!user.value.mobile || user.value.mobile.length !== 11)
|
||||
return '+86 155****5456'
|
||||
// 只处理11位手机号
|
||||
return `+86 ${user.value.mobile.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')}`
|
||||
})
|
||||
|
||||
/**
|
||||
* 验证昵称是否有效(1-10字符,一个汉字为一个字符)
|
||||
*/
|
||||
const isNicknameValid = computed(() => {
|
||||
const trimmed = nicknameInput.value.trim()
|
||||
return trimmed.length >= 1 && trimmed.length <= 10
|
||||
})
|
||||
|
||||
const Profile = {
|
||||
/**
|
||||
* 初始化用户信息
|
||||
*/
|
||||
handleInit: () => {
|
||||
// getUserInfo().then((res) => {
|
||||
// user.value = res
|
||||
// })
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑头像 - 显示选择面板
|
||||
*/
|
||||
handleEditAvatar: () => {
|
||||
showAvatarActionSheet.value = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 处理头像选择
|
||||
*/
|
||||
handleSelectAvatarAction: (item: any) => {
|
||||
showAvatarActionSheet.value = false
|
||||
|
||||
if (item.value === 'camera') {
|
||||
// 拍照
|
||||
Profile.handleChooseImage(['camera'])
|
||||
}
|
||||
else if (item.value === 'album') {
|
||||
// 从相册选择
|
||||
Profile.handleChooseImage(['album'])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 选择图片
|
||||
*/
|
||||
handleChooseImage: (sourceType: ('camera' | 'album')[]) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.chooseMedia({
|
||||
count: 1,
|
||||
mediaType: ['image'],
|
||||
sourceType,
|
||||
success: (res) => {
|
||||
const file = res.tempFiles[0]
|
||||
if (file) {
|
||||
handleUploadAvatar(file.tempFilePath)
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('选择图片失败:', err)
|
||||
if (err.errMsg && !err.errMsg.includes('cancel')) {
|
||||
toast.info('选择图片失败')
|
||||
}
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType,
|
||||
success: (res) => {
|
||||
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
|
||||
handleUploadAvatar(res.tempFilePaths[0])
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('选择图片失败:', err)
|
||||
if (err.errMsg && !err.errMsg.includes('cancel')) {
|
||||
toast.info('选择图片失败')
|
||||
}
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
},
|
||||
|
||||
/**
|
||||
* 编辑昵称 - 显示弹窗
|
||||
*/
|
||||
handleEditNickname: () => {
|
||||
nicknameInput.value = user.value.nickname || ''
|
||||
showEditNicknamePopup.value = true
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭编辑昵称弹窗
|
||||
*/
|
||||
handleCloseEditNickname: () => {
|
||||
showEditNicknamePopup.value = false
|
||||
nicknameInput.value = ''
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存昵称
|
||||
*/
|
||||
handleSaveNickname: async () => {
|
||||
const trimmed = nicknameInput.value.trim()
|
||||
if (!trimmed || trimmed.length < 1 || trimmed.length > 10) {
|
||||
toast.info('昵称限制1-10字符')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await updateUserInfo({ field: 'nickname', value: trimmed })
|
||||
user.value.nickname = trimmed
|
||||
showEditNicknamePopup.value = false
|
||||
toast.info('昵称修改成功')
|
||||
}
|
||||
catch (error) {
|
||||
console.error('更新昵称失败:', error)
|
||||
toast.info('昵称修改失败')
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改手机号
|
||||
*/
|
||||
handleEditMobile: () => {
|
||||
router.navigateTo('/pages/login/mobile?type=edit')
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
handleEditPassword: () => {
|
||||
// TODO: 实现修改密码功能
|
||||
console.log('修改密码')
|
||||
},
|
||||
|
||||
/**
|
||||
* 修改绑定用户
|
||||
*/
|
||||
handleEditBoundUser: () => {
|
||||
// TODO: 实现修改绑定用户功能
|
||||
console.log('修改绑定用户')
|
||||
},
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
Profile.handleInit()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<!-- 导航栏 -->
|
||||
<view>
|
||||
<navbar title="个人信息" custom-class="!bg-white">
|
||||
<template #right />
|
||||
</navbar>
|
||||
</view>
|
||||
|
||||
<view class="mx-30rpx mt-20rpx">
|
||||
<wd-cell-group>
|
||||
<!-- 头像 -->
|
||||
<wd-cell is-link title="头像" @click="Profile.handleEditAvatar">
|
||||
<template #value>
|
||||
<wd-img width="64rpx" height="64rpx" :src="(user.avatar && typeof user.avatar === 'string' && user.avatar.trim()) ? user.avatar : defaultAvatar" mode="aspectFill" round />
|
||||
</template>
|
||||
</wd-cell>
|
||||
|
||||
<!-- 昵称 -->
|
||||
<wd-cell is-link title="昵称" :value="(user.nickname || '昵称名字')" @click="Profile.handleEditNickname" />
|
||||
|
||||
<!-- 修改手机号 -->
|
||||
<wd-cell is-link title="修改手机号" :value="maskedMobile" @click="Profile.handleEditMobile" />
|
||||
|
||||
<!-- 修改密码 -->
|
||||
<wd-cell is-link title="修改密码" @click="Profile.handleEditPassword" />
|
||||
|
||||
<!-- 修改绑定用户 -->
|
||||
<wd-cell is-link title="修改绑定用户" @click="Profile.handleEditBoundUser" />
|
||||
</wd-cell-group>
|
||||
</view>
|
||||
|
||||
<!-- 头像选择 Action Sheet -->
|
||||
<wd-action-sheet
|
||||
v-model="showAvatarActionSheet"
|
||||
:actions="avatarActions"
|
||||
cancel-text="取消"
|
||||
@close="showAvatarActionSheet = false"
|
||||
@select="Profile.handleSelectAvatarAction"
|
||||
/>
|
||||
|
||||
<!-- 编辑昵称弹窗 -->
|
||||
<wd-popup
|
||||
v-model="showEditNicknamePopup"
|
||||
lock-scroll
|
||||
custom-style="border-radius: 32rpx 32rpx 0rpx 0rpx;"
|
||||
position="bottom"
|
||||
@close="Profile.handleCloseEditNickname"
|
||||
>
|
||||
<view class="relative bg-white px-30rpx pb-78rpx pt-50rpx">
|
||||
<!-- 关闭按钮 -->
|
||||
<view class="absolute right-30rpx top-18rpx" @click="Profile.handleCloseEditNickname">
|
||||
<wd-icon name="close" size="20px" color="#C0C4CC" />
|
||||
</view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<view class="mb-40rpx text-center text-36rpx text-[#121212] leading-50rpx">
|
||||
修改昵称
|
||||
</view>
|
||||
|
||||
<!-- 输入框 -->
|
||||
<view class="mb-20rpx">
|
||||
<view class="mb-20rpx text-30rpx text-[#303133] leading-44rpx">
|
||||
昵称:
|
||||
</view>
|
||||
<wd-input
|
||||
v-model="nicknameInput"
|
||||
type="text"
|
||||
placeholder="请输入昵称"
|
||||
no-border
|
||||
custom-class="!bg-[#F6F7F8] !border !border-solid !border-[#EAECF0] !rounded-16rpx"
|
||||
custom-input-class="!px-32rpx !h-104rpx"
|
||||
:maxlength="10"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 提示文字 -->
|
||||
<view class="mb-40rpx text-24rpx text-[#606266] leading-34rpx">
|
||||
昵称限制1-10字符,一个汉字为一个字符
|
||||
</view>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<view
|
||||
class="h-90rpx rounded-8rpx bg-[#4C9F44] text-center text-[#fff] leading-90rpx"
|
||||
:class="{ 'opacity-40': !isNicknameValid }"
|
||||
@click="isNicknameValid && Profile.handleSaveNickname()"
|
||||
>
|
||||
保存
|
||||
</view>
|
||||
</view>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background: #f6f7f8;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user