|
|
@ -1,69 +1,208 @@ |
|
|
|
import {useEffect, useState, useRef} from "react"; |
|
|
|
import {Loading, CellGroup, Input, Form, Radio, InputNumber, TextArea, ConfigProvider} from '@nutui/nutui-react-taro' |
|
|
|
import {Loading, CellGroup, Input, Form, Avatar, Button, Space} from '@nutui/nutui-react-taro' |
|
|
|
import {Edit} from '@nutui/icons-react-taro' |
|
|
|
import Taro from '@tarojs/taro' |
|
|
|
import {Image} from '@tarojs/components'; |
|
|
|
import {View} from '@tarojs/components' |
|
|
|
import FixedButton from "@/components/FixedButton"; |
|
|
|
import {DictData} from "@/api/system/dict-data/model"; |
|
|
|
import {listDictData} from "@/api/system/dict-data"; |
|
|
|
import {addShopUser, getShopUser} from "@/api/shop/shopUser"; |
|
|
|
import {ShopUser} from "@/api/shop/shopUser/model"; |
|
|
|
import {uploadFile} from "@/api/system/file"; |
|
|
|
import {useUser} from "@/hooks/useUser"; |
|
|
|
import {TenantId} from "@/config/app"; |
|
|
|
import {updateUser} from "@/api/system/user"; |
|
|
|
import {User} from "@/api/system/user/model"; |
|
|
|
import {getStoredInviteParams, handleInviteRelation} from "@/utils/invite"; |
|
|
|
import {addShopDealerUser} from "@/api/shop/shopDealerUser"; |
|
|
|
import {listUserRole, updateUserRole} from "@/api/system/userRole"; |
|
|
|
|
|
|
|
const customTheme = { |
|
|
|
nutuiInputnumberButtonWidth: '30px', |
|
|
|
nutuiInputnumberButtonHeight: '30px', |
|
|
|
nutuiInputnumberButtonBorderRadius: '2px', |
|
|
|
nutuiInputnumberButtonBackgroundColor: `#f4f4f4`, |
|
|
|
nutuiInputnumberInputHeight: '30px', |
|
|
|
nutuiInputnumberInputMargin: '0 2px', |
|
|
|
// 类型定义
|
|
|
|
interface ChooseAvatarEvent { |
|
|
|
detail: { |
|
|
|
avatarUrl: string; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const AddApply = () => { |
|
|
|
const {user} = useUser() |
|
|
|
interface InputEvent { |
|
|
|
detail: { |
|
|
|
value: string; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const AddDoctor = () => { |
|
|
|
const {user, loginUser} = useUser() |
|
|
|
const [loading, setLoading] = useState<boolean>(true) |
|
|
|
const [FormData, setFormData] = useState<ShopUser>() |
|
|
|
const [userType, setUserType] = useState<DictData[]>() |
|
|
|
const [FormData, setFormData] = useState<User>() |
|
|
|
const formRef = useRef<any>(null) |
|
|
|
|
|
|
|
const reload = async () => { |
|
|
|
const userId = Taro.getStorageSync('UserId') |
|
|
|
if(!userId || userId == '') return |
|
|
|
const shopUser = await getShopUser(Number(Taro.getStorageSync('UserId'))) |
|
|
|
if(shopUser){ |
|
|
|
console.log(shopUser.type,'shopUsershopUsershopUsershopUsershopUsershopUsershopUser') |
|
|
|
const inviteParams = getStoredInviteParams() |
|
|
|
if (inviteParams?.inviter) { |
|
|
|
setFormData({ |
|
|
|
...shopUser, |
|
|
|
type : Number(shopUser.type) |
|
|
|
...user, |
|
|
|
refereeId: Number(inviteParams.inviter), |
|
|
|
// 清空昵称,强制用户手动输入
|
|
|
|
nickname: '', |
|
|
|
}) |
|
|
|
} else { |
|
|
|
// 如果没有邀请参数,也要确保昵称为空
|
|
|
|
setFormData({ |
|
|
|
...user, |
|
|
|
nickname: '', |
|
|
|
}) |
|
|
|
} |
|
|
|
const userType = await listDictData({dictCode: 'UserType'}) |
|
|
|
if(userType){ |
|
|
|
setUserType(userType) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const uploadAvatar = ({detail}: ChooseAvatarEvent) => { |
|
|
|
// 先更新本地显示的头像(临时显示)
|
|
|
|
const tempFormData = { |
|
|
|
...FormData, |
|
|
|
avatar: `${detail.avatarUrl}`, |
|
|
|
} |
|
|
|
setFormData(tempFormData) |
|
|
|
|
|
|
|
Taro.uploadFile({ |
|
|
|
url: 'https://server.websoft.top/api/oss/upload', |
|
|
|
filePath: detail.avatarUrl, |
|
|
|
name: 'file', |
|
|
|
header: { |
|
|
|
'content-type': 'application/json', |
|
|
|
TenantId |
|
|
|
}, |
|
|
|
success: async (res) => { |
|
|
|
const data = JSON.parse(res.data); |
|
|
|
if (data.code === 0) { |
|
|
|
const finalAvatarUrl = `${data.data.thumbnail}` |
|
|
|
|
|
|
|
try { |
|
|
|
// 使用 useUser hook 的 updateUser 方法更新头像
|
|
|
|
await updateUser({ |
|
|
|
avatar: finalAvatarUrl |
|
|
|
}) |
|
|
|
|
|
|
|
Taro.showToast({ |
|
|
|
title: '头像上传成功', |
|
|
|
icon: 'success', |
|
|
|
duration: 1500 |
|
|
|
}) |
|
|
|
} catch (error) { |
|
|
|
console.error('更新用户头像失败:', error) |
|
|
|
} |
|
|
|
|
|
|
|
// 无论用户信息更新是否成功,都要更新本地FormData
|
|
|
|
const finalFormData = { |
|
|
|
...tempFormData, |
|
|
|
avatar: finalAvatarUrl |
|
|
|
} |
|
|
|
setFormData(finalFormData) |
|
|
|
|
|
|
|
// 同步更新表单字段
|
|
|
|
if (formRef.current) { |
|
|
|
formRef.current.setFieldsValue({ |
|
|
|
avatar: finalAvatarUrl |
|
|
|
}) |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 上传失败,恢复原来的头像
|
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
avatar: user?.avatar || '' |
|
|
|
}) |
|
|
|
Taro.showToast({ |
|
|
|
title: '上传失败', |
|
|
|
icon: 'error' |
|
|
|
}) |
|
|
|
} |
|
|
|
}, |
|
|
|
fail: (error) => { |
|
|
|
console.error('上传头像失败:', error) |
|
|
|
Taro.showToast({ |
|
|
|
title: '上传失败', |
|
|
|
icon: 'error' |
|
|
|
}) |
|
|
|
// 恢复原来的头像
|
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
avatar: user?.avatar || '' |
|
|
|
}) |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 提交表单
|
|
|
|
const submitSucceed = async (values: any) => { |
|
|
|
if (!FormData?.age || FormData?.age == 0) { |
|
|
|
Taro.showToast({ |
|
|
|
title: `请填写年龄`, |
|
|
|
icon: 'error' |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
try { |
|
|
|
// 验证必填字段
|
|
|
|
if (!values.phone && !FormData?.phone) { |
|
|
|
Taro.showToast({ |
|
|
|
title: '请先获取手机号', |
|
|
|
icon: 'error' |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 验证昵称:必须填写且不能是默认的微信昵称
|
|
|
|
const nickname = values.realName || FormData?.nickname || ''; |
|
|
|
if (!nickname || nickname.trim() === '') { |
|
|
|
Taro.showToast({ |
|
|
|
title: '请填写昵称', |
|
|
|
icon: 'error' |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否为默认的微信昵称(常见的默认昵称)
|
|
|
|
const defaultNicknames = ['微信用户', 'WeChat User', '微信昵称']; |
|
|
|
if (defaultNicknames.includes(nickname.trim())) { |
|
|
|
Taro.showToast({ |
|
|
|
title: '请填写真实昵称,不能使用默认昵称', |
|
|
|
icon: 'error' |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 验证昵称长度
|
|
|
|
if (nickname.trim().length < 2) { |
|
|
|
Taro.showToast({ |
|
|
|
title: '昵称至少需要2个字符', |
|
|
|
icon: 'error' |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (!values.avatar && !FormData?.avatar) { |
|
|
|
Taro.showToast({ |
|
|
|
title: '请上传头像', |
|
|
|
icon: 'error' |
|
|
|
}); |
|
|
|
return; |
|
|
|
} |
|
|
|
console.log(values,FormData) |
|
|
|
|
|
|
|
const roles = await listUserRole({userId: user?.userId}) |
|
|
|
console.log(roles, 'roles...') |
|
|
|
|
|
|
|
// 准备提交的数据
|
|
|
|
await addShopUser({ |
|
|
|
userId: Taro.getStorageSync('UserId'), |
|
|
|
type: values.type, |
|
|
|
username: user?.username, |
|
|
|
nickname: user?.nickname, |
|
|
|
await updateUser({ |
|
|
|
userId: user?.userId, |
|
|
|
nickname: values.realName || FormData?.nickname, |
|
|
|
phone: values.phone || FormData?.phone, |
|
|
|
avatar: values.avatar || FormData?.avatar, |
|
|
|
refereeId: values.refereeId || FormData?.refereeId |
|
|
|
}); |
|
|
|
|
|
|
|
await addShopDealerUser({ |
|
|
|
userId: user?.userId, |
|
|
|
realName: values.realName || FormData?.nickname, |
|
|
|
phone: values.phone || FormData?.phone |
|
|
|
mobile: values.phone || FormData?.phone, |
|
|
|
refereeId: values.refereeId || FormData?.refereeId |
|
|
|
}) |
|
|
|
|
|
|
|
if (roles.length > 0) { |
|
|
|
await updateUserRole({ |
|
|
|
...roles[0], |
|
|
|
roleId: 1848 |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Taro.showToast({ |
|
|
|
title: `注册成功`, |
|
|
|
icon: 'success' |
|
|
@ -78,6 +217,127 @@ const AddApply = () => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 获取微信昵称
|
|
|
|
const getWxNickname = (nickname: string) => { |
|
|
|
// 更新表单数据
|
|
|
|
const updatedFormData = { |
|
|
|
...FormData, |
|
|
|
nickname: nickname |
|
|
|
} |
|
|
|
setFormData(updatedFormData); |
|
|
|
|
|
|
|
// 同步更新表单字段
|
|
|
|
if (formRef.current) { |
|
|
|
formRef.current.setFieldsValue({ |
|
|
|
realName: nickname |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* 获取用户手机号 */ |
|
|
|
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => { |
|
|
|
const {code, encryptedData, iv} = detail |
|
|
|
Taro.login({ |
|
|
|
success: (loginRes) => { |
|
|
|
if (code) { |
|
|
|
Taro.request({ |
|
|
|
url: 'https://server.websoft.top/api/wx-login/loginByMpWxPhone', |
|
|
|
method: 'POST', |
|
|
|
data: { |
|
|
|
authCode: loginRes.code, |
|
|
|
code, |
|
|
|
encryptedData, |
|
|
|
iv, |
|
|
|
notVerifyPhone: true, |
|
|
|
refereeId: 0, |
|
|
|
sceneType: 'save_referee', |
|
|
|
tenantId: TenantId |
|
|
|
}, |
|
|
|
header: { |
|
|
|
'content-type': 'application/json', |
|
|
|
TenantId |
|
|
|
}, |
|
|
|
success: async function (res) { |
|
|
|
if (res.data.code == 1) { |
|
|
|
Taro.showToast({ |
|
|
|
title: res.data.message, |
|
|
|
icon: 'error', |
|
|
|
duration: 2000 |
|
|
|
}) |
|
|
|
return false; |
|
|
|
} |
|
|
|
// 登录成功
|
|
|
|
const token = res.data.data.access_token; |
|
|
|
const userData = res.data.data.user; |
|
|
|
console.log(userData, 'userData...') |
|
|
|
// 使用useUser Hook的loginUser方法更新状态
|
|
|
|
loginUser(token, userData); |
|
|
|
|
|
|
|
if (userData.phone) { |
|
|
|
console.log('手机号已获取', userData.phone) |
|
|
|
const updatedFormData = { |
|
|
|
...FormData, |
|
|
|
phone: userData.phone, |
|
|
|
// 不自动填充微信昵称,保持用户已输入的昵称
|
|
|
|
nickname: FormData?.nickname || '', |
|
|
|
// 只在没有头像时才使用微信头像
|
|
|
|
avatar: FormData?.avatar || userData.avatar |
|
|
|
} |
|
|
|
setFormData(updatedFormData) |
|
|
|
|
|
|
|
// 更新表单字段值
|
|
|
|
if (formRef.current) { |
|
|
|
formRef.current.setFieldsValue({ |
|
|
|
phone: userData.phone, |
|
|
|
// 不覆盖用户已输入的昵称
|
|
|
|
realName: FormData?.nickname || '', |
|
|
|
avatar: FormData?.avatar || userData.avatar |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
Taro.showToast({ |
|
|
|
title: '手机号获取成功', |
|
|
|
icon: 'success', |
|
|
|
duration: 1500 |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理邀请关系
|
|
|
|
if (userData?.userId) { |
|
|
|
try { |
|
|
|
const inviteSuccess = await handleInviteRelation(userData.userId) |
|
|
|
if (inviteSuccess) { |
|
|
|
Taro.showToast({ |
|
|
|
title: '邀请关系建立成功', |
|
|
|
icon: 'success', |
|
|
|
duration: 2000 |
|
|
|
}) |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('处理邀请关系失败:', error) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 显示登录成功提示
|
|
|
|
// Taro.showToast({
|
|
|
|
// title: '注册成功',
|
|
|
|
// icon: 'success',
|
|
|
|
// duration: 1500
|
|
|
|
// })
|
|
|
|
|
|
|
|
// 不需要重新启动小程序,状态已经通过useUser更新
|
|
|
|
// 可以选择性地刷新当前页面数据
|
|
|
|
// await reload();
|
|
|
|
} |
|
|
|
}) |
|
|
|
} else { |
|
|
|
console.log('登录失败!') |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 处理固定按钮点击事件
|
|
|
|
const handleFixedButtonClick = () => { |
|
|
|
// 触发表单提交
|
|
|
@ -88,25 +348,17 @@ const AddApply = () => { |
|
|
|
console.log(error, 'err...') |
|
|
|
} |
|
|
|
|
|
|
|
const uploadImg1 = () => { |
|
|
|
uploadFile().then(data => { |
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
uploadImg1: data.url |
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
reload().then(() => { |
|
|
|
setLoading(false) |
|
|
|
}) |
|
|
|
}, []); // 依赖用户ID,当用户变化时重新加载
|
|
|
|
}, [user?.userId]); // 依赖用户ID,当用户变化时重新加载
|
|
|
|
|
|
|
|
// 当FormData变化时,同步更新表单字段值
|
|
|
|
useEffect(() => { |
|
|
|
if (formRef.current && FormData) { |
|
|
|
formRef.current.setFieldsValue({ |
|
|
|
refereeId: FormData.refereeId, |
|
|
|
phone: FormData.phone, |
|
|
|
avatar: FormData.avatar, |
|
|
|
realName: FormData.nickname |
|
|
@ -128,106 +380,42 @@ const AddApply = () => { |
|
|
|
onFinish={(values) => submitSucceed(values)} |
|
|
|
onFinishFailed={(errors) => submitFailed(errors)} |
|
|
|
> |
|
|
|
<View className={'bg-gray-100 h-3'}></View> |
|
|
|
<CellGroup style={{padding: '4px 0'}}> |
|
|
|
{JSON.stringify(FormData)} |
|
|
|
<Form.Item label="用户类型" name="type" initialValue={FormData?.type} required> |
|
|
|
<Radio.Group |
|
|
|
defaultValue="0" |
|
|
|
direction="horizontal" |
|
|
|
value={FormData?.type} |
|
|
|
onChange={(value: any) => { |
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
type: value |
|
|
|
}) |
|
|
|
}} |
|
|
|
> |
|
|
|
{userType?.map((item) => ( |
|
|
|
<Radio key={item.value} value={item.value}> |
|
|
|
{item.label} |
|
|
|
</Radio> |
|
|
|
))} |
|
|
|
</Radio.Group> |
|
|
|
</Form.Item> |
|
|
|
<Form.Item label="姓名" name="realName" required> |
|
|
|
<Input |
|
|
|
placeholder={'请填写真实姓名'} |
|
|
|
value={FormData?.realName || ''} |
|
|
|
onChange={(value) => { |
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
realName: value |
|
|
|
}) |
|
|
|
}} |
|
|
|
/> |
|
|
|
</Form.Item> |
|
|
|
<Form.Item label="性别" name="sex" required> |
|
|
|
<Radio.Group |
|
|
|
direction="horizontal" |
|
|
|
value={FormData?.sex || "0"} |
|
|
|
> |
|
|
|
<Radio value="1"> |
|
|
|
男 |
|
|
|
</Radio> |
|
|
|
<Radio value="2"> |
|
|
|
女 |
|
|
|
</Radio> |
|
|
|
</Radio.Group> |
|
|
|
<Form.Item name="refereeId" label="邀请人ID" initialValue={FormData?.refereeId} required> |
|
|
|
<Input placeholder="邀请人ID" disabled={true}/> |
|
|
|
</Form.Item> |
|
|
|
<Form.Item label="年龄" name="age" initialValue={FormData?.age} required> |
|
|
|
<ConfigProvider theme={customTheme}> |
|
|
|
<InputNumber |
|
|
|
value={FormData?.age} |
|
|
|
onChange={(value) => { |
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
age: Number(value) |
|
|
|
}) |
|
|
|
}} |
|
|
|
min={0} |
|
|
|
max={120} |
|
|
|
step={1} |
|
|
|
<Form.Item name="phone" label="手机号" initialValue={FormData?.phone} required> |
|
|
|
<View className="flex items-center justify-between"> |
|
|
|
<Input |
|
|
|
placeholder="请填写手机号" |
|
|
|
disabled={true} |
|
|
|
maxLength={11} |
|
|
|
value={FormData?.phone || ''} |
|
|
|
/> |
|
|
|
</ConfigProvider> |
|
|
|
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}> |
|
|
|
<Space> |
|
|
|
<Button size="small">点击获取</Button> |
|
|
|
</Space> |
|
|
|
</Button> |
|
|
|
</View> |
|
|
|
</Form.Item> |
|
|
|
<Form.Item label={FormData?.type == 1 ? '医生简介' : '个人简介'} name="introduction"> |
|
|
|
<TextArea |
|
|
|
style={{ |
|
|
|
height: '50px', |
|
|
|
backgroundColor: '#fafafa', |
|
|
|
padding: '10px', |
|
|
|
}} |
|
|
|
value={FormData?.introduction || ''} |
|
|
|
{ |
|
|
|
FormData?.phone && <Form.Item name="avatar" label="头像" initialValue={FormData?.avatar} required> |
|
|
|
<Button open-type="chooseAvatar" style={{height: '58px'}} onChooseAvatar={uploadAvatar}> |
|
|
|
<Avatar src={FormData?.avatar || user?.avatar} size="54"/> |
|
|
|
</Button> |
|
|
|
</Form.Item> |
|
|
|
} |
|
|
|
<Form.Item name="realName" label="昵称" initialValue="" required> |
|
|
|
<Input |
|
|
|
type="nickname" |
|
|
|
className="info-content__input" |
|
|
|
placeholder="请获取微信昵称" |
|
|
|
value={FormData?.nickname || ''} |
|
|
|
onInput={(e: InputEvent) => getWxNickname(e.detail.value)} |
|
|
|
/> |
|
|
|
</Form.Item> |
|
|
|
{FormData?.type == 1 && ( |
|
|
|
<> |
|
|
|
<Form.Item label="证书编号" name="userCode" required> |
|
|
|
<Input |
|
|
|
placeholder={'请填证书编号'} |
|
|
|
value={FormData?.userCode || ''} |
|
|
|
onChange={(value) => { |
|
|
|
setFormData({ |
|
|
|
...FormData, |
|
|
|
idCard: value |
|
|
|
}) |
|
|
|
}} |
|
|
|
/> |
|
|
|
</Form.Item> |
|
|
|
<Form.Item |
|
|
|
label={'上传证件'} |
|
|
|
name="uploadImg1" |
|
|
|
required |
|
|
|
rules={[{message: '请上传医师资格证书'} |
|
|
|
]} |
|
|
|
> |
|
|
|
<div onClick={uploadImg1}> |
|
|
|
<Image src={FormData.uploadImg1 || ''} mode={'scaleToFill'} lazyLoad={false} /> |
|
|
|
</div> |
|
|
|
</Form.Item> |
|
|
|
</> |
|
|
|
)} |
|
|
|
|
|
|
|
</CellGroup> |
|
|
|
</Form> |
|
|
|
|
|
|
@ -242,4 +430,4 @@ const AddApply = () => { |
|
|
|
); |
|
|
|
}; |
|
|
|
|
|
|
|
export default AddApply; |
|
|
|
export default AddDoctor; |
|
|
|