|
|
|
|
@ -4,43 +4,40 @@
@@ -4,43 +4,40 @@
|
|
|
|
|
import { View, Text, Image, Input, Button as WxButton } from '@tarojs/components' |
|
|
|
|
import Taro, { useLoad } from '@tarojs/taro' |
|
|
|
|
import { useState } from 'react' |
|
|
|
|
import { Image as TaroifyImage, DatetimePicker, Popup, Button, ActionSheet } from '@taroify/core' |
|
|
|
|
import { ArrowLeft } from '@taroify/icons' |
|
|
|
|
import { observer } from 'mobx-react' |
|
|
|
|
import { Image as TaroifyImage, Button, ActionSheet } from '@taroify/core' |
|
|
|
|
import { updateCustomer, readImageAsBase64 } from '../../api/customer' |
|
|
|
|
import { userStore } from '../../store' |
|
|
|
|
import myAvatar from '../../assets/icon/my_avatar.png' |
|
|
|
|
import './index.scss' |
|
|
|
|
|
|
|
|
|
const EditProfile = () => { |
|
|
|
|
const [nickname, setNickname] = useState('旋转跳跃的球圣') |
|
|
|
|
const [birthday, setBirthday] = useState(new Date('2025-01-01')) |
|
|
|
|
const [datePickerOpen, setDatePickerOpen] = useState(false) |
|
|
|
|
const EditProfile = observer(() => { |
|
|
|
|
const info = userStore.userInfo |
|
|
|
|
|
|
|
|
|
const [nickname, setNickname] = useState(info?.name || info?.nickname || '') |
|
|
|
|
const [phone, setPhone] = useState(info?.phone || '') |
|
|
|
|
const [wchart, setWchart] = useState(info?.wchart || '') |
|
|
|
|
const [avatarUrl, setAvatarUrl] = useState(info?.avatar || myAvatar) |
|
|
|
|
// 是否选了新的本地头像(需要上传)
|
|
|
|
|
const [newAvatarPath, setNewAvatarPath] = useState<string>('') |
|
|
|
|
const [loading, setLoading] = useState(false) |
|
|
|
|
const [avatarActionOpen, setAvatarActionOpen] = useState(false) |
|
|
|
|
const [avatarUrl, setAvatarUrl] = useState(myAvatar) |
|
|
|
|
|
|
|
|
|
useLoad(() => { |
|
|
|
|
console.log('编辑个人信息页面加载') |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 返回上一页
|
|
|
|
|
const handleBack = () => { |
|
|
|
|
Taro.navigateBack() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 点击头像,打开选择菜单
|
|
|
|
|
// 点击头像区域
|
|
|
|
|
const handleAvatarClick = () => { |
|
|
|
|
setAvatarActionOpen(true) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 使用微信头像
|
|
|
|
|
const handleUseWechatAvatar = () => { |
|
|
|
|
// 注意:button open-type="chooseAvatar" 需要在 button 组件上使用
|
|
|
|
|
// 这里先关闭 ActionSheet,让用户点击特殊的 button
|
|
|
|
|
// 微信头像回调
|
|
|
|
|
const handleChooseAvatar = (e: any) => { |
|
|
|
|
const url = e.detail.avatarUrl |
|
|
|
|
setAvatarUrl(url) |
|
|
|
|
setNewAvatarPath(url) |
|
|
|
|
setAvatarActionOpen(false) |
|
|
|
|
// 实际使用时需要通过 button open-type="chooseAvatar" 触发
|
|
|
|
|
Taro.showToast({ |
|
|
|
|
title: '请使用下方按钮选择微信头像', |
|
|
|
|
icon: 'none', |
|
|
|
|
duration: 2000 |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 从相册选择
|
|
|
|
|
@ -51,10 +48,10 @@ const EditProfile = () => {
@@ -51,10 +48,10 @@ const EditProfile = () => {
|
|
|
|
|
sizeType: ['compressed'], |
|
|
|
|
sourceType: ['album'], |
|
|
|
|
success: (res) => { |
|
|
|
|
console.log('选择头像', res.tempFilePaths[0]) |
|
|
|
|
setAvatarUrl(res.tempFilePaths[0]) |
|
|
|
|
// TODO: 上传头像到服务器
|
|
|
|
|
} |
|
|
|
|
const path = res.tempFilePaths[0] |
|
|
|
|
setAvatarUrl(path) |
|
|
|
|
setNewAvatarPath(path) |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -66,74 +63,83 @@ const EditProfile = () => {
@@ -66,74 +63,83 @@ const EditProfile = () => {
|
|
|
|
|
sizeType: ['compressed'], |
|
|
|
|
sourceType: ['camera'], |
|
|
|
|
success: (res) => { |
|
|
|
|
console.log('拍照', res.tempFilePaths[0]) |
|
|
|
|
setAvatarUrl(res.tempFilePaths[0]) |
|
|
|
|
// TODO: 上传头像到服务器
|
|
|
|
|
} |
|
|
|
|
const path = res.tempFilePaths[0] |
|
|
|
|
setAvatarUrl(path) |
|
|
|
|
setNewAvatarPath(path) |
|
|
|
|
}, |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 获取微信头像回调
|
|
|
|
|
const handleChooseAvatar = (e: any) => { |
|
|
|
|
console.log('微信头像', e.detail.avatarUrl) |
|
|
|
|
setAvatarUrl(e.detail.avatarUrl) |
|
|
|
|
// TODO: 上传头像到服务器
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 格式化日期显示
|
|
|
|
|
const formatDate = (date: Date) => { |
|
|
|
|
const year = date.getFullYear() |
|
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0') |
|
|
|
|
const day = String(date.getDate()).padStart(2, '0') |
|
|
|
|
return `${year}-${month}-${day}` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 确认选择日期
|
|
|
|
|
const handleDateConfirm = (newValue: any) => { |
|
|
|
|
setBirthday(newValue) |
|
|
|
|
setDatePickerOpen(false) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 保存
|
|
|
|
|
const handleSave = () => { |
|
|
|
|
Taro.showToast({ |
|
|
|
|
title: '保存成功', |
|
|
|
|
icon: 'success', |
|
|
|
|
duration: 2000 |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
Taro.navigateBack() |
|
|
|
|
}, 2000) |
|
|
|
|
const handleSave = async () => { |
|
|
|
|
if (loading) return |
|
|
|
|
|
|
|
|
|
const userId = info?.id |
|
|
|
|
if (!userId) { |
|
|
|
|
Taro.showToast({ title: '用户信息异常,请重新登录', icon: 'none', duration: 2000 }) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!nickname.trim()) { |
|
|
|
|
Taro.showToast({ title: '昵称不能为空', icon: 'none', duration: 2000 }) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setLoading(true) |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
// 如果选了新头像,先转成 Base64
|
|
|
|
|
let avatarImage: string | undefined |
|
|
|
|
if (newAvatarPath) { |
|
|
|
|
try { |
|
|
|
|
avatarImage = await readImageAsBase64(newAvatarPath) |
|
|
|
|
} catch (e) { |
|
|
|
|
console.warn('头像转 Base64 失败,跳过头像更新:', e) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
await updateCustomer(userId, { |
|
|
|
|
id: userId, |
|
|
|
|
name: nickname.trim(), |
|
|
|
|
phone: phone.trim() || undefined, |
|
|
|
|
wchart: wchart.trim() || undefined, |
|
|
|
|
avatarImage, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
// 同步更新本地 store
|
|
|
|
|
userStore.setUserInfo({ |
|
|
|
|
...userStore.userInfo!, |
|
|
|
|
name: nickname.trim(), |
|
|
|
|
nickname: nickname.trim(), |
|
|
|
|
phone: phone.trim() || userStore.userInfo?.phone, |
|
|
|
|
wchart: wchart.trim() || userStore.userInfo?.wchart, |
|
|
|
|
avatar: newAvatarPath || userStore.userInfo?.avatar, |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
Taro.showToast({ title: '保存成功', icon: 'success', duration: 2000 }) |
|
|
|
|
setTimeout(() => Taro.navigateBack(), 1500) |
|
|
|
|
} catch (error: any) { |
|
|
|
|
console.error('保存失败:', error) |
|
|
|
|
// 错误提示由 request 拦截器统一处理
|
|
|
|
|
} finally { |
|
|
|
|
setLoading(false) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<View className="edit-profile-page"> |
|
|
|
|
{/* 自定义导航栏 */} |
|
|
|
|
{/* <View className="custom-navbar"> |
|
|
|
|
<View className="navbar-left" onClick={handleBack}> |
|
|
|
|
<ArrowLeft size={20} color="#FFFFFF" /> |
|
|
|
|
</View> |
|
|
|
|
<View className="navbar-title"> |
|
|
|
|
<Text>个人信息</Text> |
|
|
|
|
</View> |
|
|
|
|
<View className="navbar-right" /> |
|
|
|
|
</View> */} |
|
|
|
|
|
|
|
|
|
{/* 内容区域 */} |
|
|
|
|
<View className="content-area"> |
|
|
|
|
{/* 头像区域 */} |
|
|
|
|
<View className="avatar-section" onClick={handleAvatarClick}> |
|
|
|
|
<View className="avatar-wrapper"> |
|
|
|
|
<TaroifyImage |
|
|
|
|
<TaroifyImage |
|
|
|
|
className="avatar" |
|
|
|
|
src={avatarUrl} |
|
|
|
|
src={avatarUrl || myAvatar} |
|
|
|
|
round |
|
|
|
|
mode="aspectFill" |
|
|
|
|
/> |
|
|
|
|
{/* 相机图标 */} |
|
|
|
|
<View className="camera-icon"> |
|
|
|
|
<Image |
|
|
|
|
<Image |
|
|
|
|
className="camera-img" |
|
|
|
|
src={require('../../assets/icon/phototake.png')} |
|
|
|
|
mode="widthFix" |
|
|
|
|
@ -153,51 +159,55 @@ const EditProfile = () => {
@@ -153,51 +159,55 @@ const EditProfile = () => {
|
|
|
|
|
onInput={(e) => setNickname(e.detail.value)} |
|
|
|
|
placeholder="请输入昵称" |
|
|
|
|
placeholderClass="form-placeholder" |
|
|
|
|
maxlength={20} |
|
|
|
|
/> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 生日 */} |
|
|
|
|
<View className="form-item" onClick={() => setDatePickerOpen(true)}> |
|
|
|
|
<Text className="form-label">生日</Text> |
|
|
|
|
<View className="form-value"> |
|
|
|
|
<Text>{formatDate(birthday)}</Text> |
|
|
|
|
<ArrowLeft className="arrow-icon" size={16} color="#999" /> |
|
|
|
|
</View> |
|
|
|
|
{/* 手机号 */} |
|
|
|
|
<View className="form-item"> |
|
|
|
|
<Text className="form-label">手机号</Text> |
|
|
|
|
<Input |
|
|
|
|
className="form-input" |
|
|
|
|
value={phone} |
|
|
|
|
onInput={(e) => setPhone(e.detail.value)} |
|
|
|
|
placeholder="请输入手机号" |
|
|
|
|
placeholderClass="form-placeholder" |
|
|
|
|
type="number" |
|
|
|
|
maxlength={11} |
|
|
|
|
/> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 微信号 */} |
|
|
|
|
<View className="form-item"> |
|
|
|
|
<Text className="form-label">微信号</Text> |
|
|
|
|
<Input |
|
|
|
|
className="form-input" |
|
|
|
|
value={wchart} |
|
|
|
|
onInput={(e) => setWchart(e.detail.value)} |
|
|
|
|
placeholder="请输入微信号" |
|
|
|
|
placeholderClass="form-placeholder" |
|
|
|
|
maxlength={30} |
|
|
|
|
/> |
|
|
|
|
</View> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 保存按钮 */} |
|
|
|
|
<Button className="save-button" onClick={handleSave}> |
|
|
|
|
保存 |
|
|
|
|
<Button |
|
|
|
|
className={`save-button ${loading ? 'disabled' : ''}`} |
|
|
|
|
loading={loading} |
|
|
|
|
onClick={handleSave} |
|
|
|
|
> |
|
|
|
|
{loading ? '保存中...' : '保存'} |
|
|
|
|
</Button> |
|
|
|
|
</View> |
|
|
|
|
|
|
|
|
|
{/* 日期选择器 */} |
|
|
|
|
<Popup |
|
|
|
|
open={datePickerOpen} |
|
|
|
|
placement="bottom" |
|
|
|
|
onClose={() => setDatePickerOpen(false)} |
|
|
|
|
> |
|
|
|
|
<DatetimePicker |
|
|
|
|
type="date" |
|
|
|
|
value={birthday} |
|
|
|
|
onChange={handleDateConfirm} |
|
|
|
|
onCancel={() => setDatePickerOpen(false)} |
|
|
|
|
onConfirm={handleDateConfirm} |
|
|
|
|
> |
|
|
|
|
{/* <Button>取消</Button> |
|
|
|
|
<Button>确认</Button> */} |
|
|
|
|
</DatetimePicker> |
|
|
|
|
</Popup> |
|
|
|
|
|
|
|
|
|
{/* 头像选择菜单 */} |
|
|
|
|
<ActionSheet |
|
|
|
|
open={avatarActionOpen} |
|
|
|
|
onSelect={() => {}} |
|
|
|
|
onClose={() => setAvatarActionOpen(false)} |
|
|
|
|
> |
|
|
|
|
{/* 使用微信头像 - 需要特殊处理 */} |
|
|
|
|
<WxButton |
|
|
|
|
<WxButton |
|
|
|
|
className="avatar-action-item wechat-avatar-btn" |
|
|
|
|
openType="chooseAvatar" |
|
|
|
|
onChooseAvatar={handleChooseAvatar} |
|
|
|
|
@ -205,29 +215,30 @@ const EditProfile = () => {
@@ -205,29 +215,30 @@ const EditProfile = () => {
|
|
|
|
|
<Text className="avatar-emoji">🤵</Text> |
|
|
|
|
<Text>用微信头像</Text> |
|
|
|
|
</WxButton> |
|
|
|
|
|
|
|
|
|
<ActionSheet.Action |
|
|
|
|
|
|
|
|
|
<ActionSheet.Action |
|
|
|
|
className="avatar-action-item" |
|
|
|
|
onClick={handleChooseFromAlbum} |
|
|
|
|
> |
|
|
|
|
从相册选择 |
|
|
|
|
</ActionSheet.Action> |
|
|
|
|
|
|
|
|
|
<ActionSheet.Action |
|
|
|
|
|
|
|
|
|
<ActionSheet.Action |
|
|
|
|
className="avatar-action-item" |
|
|
|
|
onClick={handleTakePhoto} |
|
|
|
|
> |
|
|
|
|
拍照 |
|
|
|
|
</ActionSheet.Action> |
|
|
|
|
|
|
|
|
|
<ActionSheet.Action |
|
|
|
|
|
|
|
|
|
<ActionSheet.Action |
|
|
|
|
className="avatar-action-item cancel-action" |
|
|
|
|
onClick={() => setAvatarActionOpen(false)} |
|
|
|
|
> |
|
|
|
|
取消 |
|
|
|
|
</ActionSheet.Action> |
|
|
|
|
</ActionSheet> |
|
|
|
|
</View> |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
export default EditProfile |
|
|
|
|
|