bk-shop/src/subpages/member/user-info.js

718 lines
21 KiB
JavaScript
Executable File

import React, { useEffect, useRef } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { useImmer } from 'use-immer'
import Taro from '@tarojs/taro'
import { AtButton } from 'taro-ui'
import { SpPage, SpCell, SpImage, SpFloatLayout, SpCheckbox } from '@/components'
import { useLogin } from '@/hooks'
import api from '@/api'
import { SG_POLICY } from '@/consts'
import { classNames, showToast, formatTime, isWeixin, isWeb, pickBy } from '@/utils'
import imgUploader from '@/utils/upload'
import { View, Input, Picker, Button, Text, Checkbox } from '@tarojs/components'
import { updateUserInfo } from '@/store/slices/user'
import './user-info.scss'
const initialState = {
formItems: [],
formUserInfo: {},
checkboxPickerTitle: '',
showCheckboxPicker: false,
checkboxKey: '',
checkboxList: [],
checked: false,
info: {},
areaList: [],
multiIndex: [],
listLength: 0,
nList: [],
listLength: 0,
loading: true
}
function MemberUserInfo () {
const [state, setState] = useImmer(initialState)
const dispatch = useDispatch()
const {
formItems,
formUserInfo,
checkboxPickerTitle,
showCheckboxPicker,
checkboxKey,
checkboxList,
checked,
info,
areaList,
multiIndex,
nList,
loading
} = state
const { userInfo = {} } = useSelector((_state) => _state.user)
const { appName } = useSelector((_state) => _state.sys)
const pageRef = useRef()
const { getUserInfo, logout } = useLogin()
useEffect(() => {
getFormItem()
}, [])
useEffect(() => {
if (showCheckboxPicker) {
pageRef.current?.pageLock()
} else {
pageRef.current.pageUnLock()
}
}, [showCheckboxPicker])
// console.log('userInfo ******', userInfo)
const fetchData = async () => {
let res = await api.member.areaList()
const _nList = pickBy(res, {
label: 'label',
children: 'children'
})
// let arrProvice = []
// let arrCity = []
// let arrCounty = []
// _nList.map((item, index) => {
// arrProvice.push(item.label)
// if (index === 0) {
// item.children.map((c_item, c_index) => {
// arrCity.push(c_item.label)
// if (c_index === 0) {
// c_item.children.map((cny_item) => {
// arrCounty.push(cny_item.label)
// })
// }
// })
// }
// })
// setState((draft) => {
// draft.nList = _nList
// draft.areaList = [arrProvice, arrCity, arrCounty]
// // draft.multiIndex = [0, 0, 0]
// })
return _nList
}
const getFormItem = async () => {
const _areaList = await fetchData()
const data = await api.user.regParam({
is_edite_page: true
})
const { other_params: { custom_data = {} } } = userInfo
const _formItems = []
const _formUserInfo = {
avatar: userInfo.avatar,
username: userInfo.username,
...custom_data
}
const formSort = {
mobile: -1,
username: 1,
sex: 2,
birthday: 3,
// city: 5
}
Object.keys(data).forEach((key, i) => {
const value = custom_data[key] || userInfo[key]
if (data[key].is_open) {
// if (key !== 'mobile' && key !== 'username') {
// }
_formItems.push({ ...data[key], sort: formSort[key] || 3 + i })
}
if (data[key].element_type == 'checkbox') {
_formUserInfo[key] = value ? value.split(',').map(item => ({ name: item, ischecked: true })) : []
} else {
_formUserInfo[key] = value || ''
}
if (key === 'sex') {
const sexType = {
0: '未知',
1: '男',
2: '女'
}
_formUserInfo[key] = sexType[value]
}
})
_formItems.push({ name: "居住城市", required_message: "请输入居住城市", key: "city", element_type: "area", field_type: 7, placeholder: "请选择居住城市", range: [], sort: 999 })
const { life_province, life_city, life_county } = userInfo
_formUserInfo.life_province = life_province
_formUserInfo.life_city = life_city
_formUserInfo.life_county = life_county
// _formUserInfo.multiIndex = userInfo.multiIndex || [0, 0, 0]
let _multiIndex = [0, 0, 0]
let arrProvice = []
let arrCity = []
let arrCounty = []
_areaList.forEach((item, index) => {
arrProvice.push(item.label)
if (life_province && life_city && life_county) {
if (item.label === life_province) {
_multiIndex[0] = index
item.children.map((s_item, sIndex) => {
arrCity.push(s_item.label)
if (s_item.label === life_city) {
_multiIndex[1] = sIndex
s_item.children.map((th_item, thIndex) => {
arrCounty.push(th_item.label)
if (th_item.label === life_county) {
_multiIndex[2] = thIndex
}
})
}
})
}
} else {
if (index === 0) {
item.children.map((c_item, c_index) => {
arrCity.push(c_item.label)
if (c_index === 0) {
c_item.children.map((cny_item) => {
arrCounty.push(cny_item.label)
})
}
})
}
}
})
setState((draft) => {
draft.nList = _areaList
draft.formItems = _formItems.sort((a, b) => a.sort - b.sort)
draft.formUserInfo = _formUserInfo
draft.areaList = [arrProvice, arrCity, arrCounty]
draft.multiIndex = _multiIndex
draft.loading = false
})
}
const renderText = ({ key, required_message }) => {
return (
<Input
name={key}
class='input-field-1'
value={formUserInfo[key]}
placeholder={required_message}
onInput={onChangePicker.bind(this, key)}
/>
)
}
const renderNumber = ({ key, range: { start, end }, required_message }) => {
return (
<Input
name={key}
type='number'
value={formUserInfo[key]}
max={end}
min={start}
placeholder={required_message}
onInput={onChangePicker.bind(this, key)}
/>
)
}
const onChangePicker = (key, e) => {
setState((draft) => {
draft.formUserInfo[key] = e.detail.value
})
}
const onChangeSelectPicker = (key, e) => {
const item = formItems.find((_item) => _item.key == key)
const { select } = item
setState((draft) => {
draft.formUserInfo[key] = select[e.detail.value]
})
}
const getIndexBySelecValue = (key) => {
const item = formItems.find((_item) => _item.key == key)
const { select } = item
return select.findIndex((s) => s == formUserInfo[key])
}
const renderDatePicker = ({ key, required_message }) => {
const disabled = key === 'birthday' && !userInfo.birthday_can_edit
return (
<Picker mode='date' disabled={disabled} value={formUserInfo[key]} onChange={onChangePicker.bind(this, key)} start='1900-01-01' end={formatTime(new Date())}>
<View
className={classNames('picker-value', {
'placeholder': !formUserInfo[key]
})}
style={{ 'color': disabled ? '#a5a5a5' : '#000' }}
>
{formUserInfo[key] || required_message}
</View>
</Picker>
)
}
const renderRadioPicker = ({ key, required_message, select }) => {
return (
<Picker
mode='selector'
value={getIndexBySelecValue(key)}
onChange={onChangeSelectPicker.bind(this, key)}
range={select}
>
<View
className={classNames('picker-value', {
'placeholder': !formUserInfo[key]
})}
>
{formUserInfo[key] || required_message}
</View>
</Picker>
)
}
const renderCheckboxPicker = ({ name, key, required_message, checkbox }) => {
return (
<View
className={classNames('picker-value', {
'placeholder': formUserInfo[key].length == 0
})}
onClick={() => {
const _checkboxList = checkbox.map((item) => {
const fd = formUserInfo[key].find((k) => k.name == item.name)
const isChecked = fd ? fd.ischecked : false
return {
name: item.name,
ischecked: isChecked
}
})
setState((draft) => {
draft.showCheckboxPicker = true
draft.checkboxKey = key
draft.checkboxPickerTitle = `选择${name}`
draft.checkboxList = _checkboxList
})
}}
>
{formUserInfo[key].length > 0
? formUserInfo[key]
.filter((item) => !!item.ischecked)
.map((item) => item.name)
.join(',')
: required_message}
</View>
)
}
const renderPhone = () => {
return (
<View className='user-form-item-phone' onClick={() => {
Taro.navigateTo({
url: '/subpages/auth/edit-phone'
})
}}>{userInfo?.mobile}</View>
)
}
const bindMultiPickerChange = async (e) => {
let _info = { ...info }
nList.map((item, index) => {
if (index === e.detail.value[0]) {
_info.province = item.label
item.children.map((s_item, sIndex) => {
if (sIndex === e.detail.value[1]) {
_info.city = s_item.label
s_item.children.map((th_item, thIndex) => {
if (thIndex === e.detail.value[2]) {
_info.county = th_item.label
}
})
}
})
}
})
const { province: life_province, city: life_city, county: life_county } = _info
setState((draft) => {
draft.multiIndex = e.detail.value
draft.info = _info
draft.formUserInfo = { ...draft.formUserInfo, life_province, life_city, life_county, multiIndex }
})
}
const bindMultiPickerColumnChange = (e) => {
let _areaList = [...areaList],
_multiIndex = [...multiIndex]
if (e.detail.column === 0) {
setState((draft) => {
draft.multiIndex = [e.detail.value, 0, 0]
})
nList.map((item, index) => {
if (index === e.detail.value) {
let arrCity = []
let arrCounty = []
item.children.map((c_item, c_index) => {
arrCity.push(c_item.label)
if (c_index === 0) {
c_item.children.map((cny_item) => {
arrCounty.push(cny_item.label)
})
}
})
_areaList[1] = arrCity
_areaList[2] = arrCounty
setState((draft) => { draft.areaList = _areaList })
}
})
} else if (e.detail.column === 1) {
_multiIndex[1] = e.detail.value
_multiIndex[2] = 0
setState(
(draft) => {
draft.multiIndex = _multiIndex
}
)
nList[_multiIndex[0]].children.map((c_item, c_index) => {
if (c_index === e.detail.value) {
let arrCounty = []
c_item.children.map((cny_item) => {
arrCounty.push(cny_item.label)
})
_areaList[2] = arrCounty
setState((draft) => { draft.areaList = _areaList })
}
})
} else {
_multiIndex[2] = e.detail.value
setState((draft) => {
draft.multiIndex = _multiIndex
})
}
}
const renderArea = ({ required_message }) => {
return <Picker
mode='multiSelector'
onChange={bindMultiPickerChange}
onColumnChange={bindMultiPickerColumnChange}
value={multiIndex}
range={areaList}
>
<View className='picker' style={{ 'color': multiIndex.length > 0 ? '#000' : '#a5a5a5' }}>
{info.address_id ? (
`${info.province}-${info.city}-${info.county}`
) : (
<View>
{multiIndex.length > 0 ? (
<Text>
{areaList[0][multiIndex[0]]}-
{areaList[1][multiIndex[1]]}-
{areaList[2][multiIndex[2]]}
</Text>
) : required_message}
</View>
)}
</View>
</Picker>
}
const compType = {
1: renderText,
2: renderNumber,
3: renderDatePicker,
4: renderRadioPicker,
5: renderCheckboxPicker,
6: renderPhone,
7: renderArea
}
const renderFormItem = (item) => {
const { field_type } = item
return compType[field_type] && compType[field_type](item)
}
const saveUserInfo = async () => {
const { avatar, username } = formUserInfo
await api.member.updateMemberInfo({
username,
avatar,
...formUserInfo
})
await api.member.setMemberInfo({
...formUserInfo,
})
showToast('修改成功')
await getUserInfo(true)
let memberRes = await api.member.memberInfo()
dispatch(updateUserInfo(memberRes))
setTimeout(() => {
Taro.navigateBack()
}, 300)
}
const handleLogOff = async () => {
const { status, msg } = await api.member.deleteMember({ is_delete: '0' })
if (!status) {
await Taro.showModal({
content: msg,
confirmText: '我知道了'
})
} else {
Taro.navigateTo({
url: `/marketing/pages/member/destroy-member?phone=${formUserInfo.mobile}`
})
}
}
// H5退出账号
const handleLogOut = async () => {
logout()
showToast('退出登录成功')
// Taro.redirectTo({ url: '/pages/index' })
window.location.href = `${window.location.origin}/pages/index`
}
const onChooseAvatar = async (e) => {
const res = await imgUploader.uploadImageFn([
{
file: {
path: e.detail.avatarUrl
},
url: e.detail.avatarUrl
}
])
setState((draft) => {
draft.formUserInfo.avatar = res[0]?.url
})
}
const onUploadAvatarFile = async () => {
const { tempFiles = [] } = await Taro.chooseImage({
count: 1
})
console.log('onUploadAvatarFile:tempFiles', tempFiles)
if (tempFiles.length > 0) {
const imgFiles = tempFiles.slice(0, 1).map((item) => {
return {
file: item,
url: item.path
}
})
const res = await imgUploader.uploadImageFn(imgFiles)
console.log('onUploadAvatarFile:res', res)
// debugger
// https://resource/apml16866fa5e90bd3dd72409b11e4f68679.jpg
setState((draft) => {
draft.formUserInfo.avatar = res[0].url
// draft.formUserInfo.avatar = imgFiles[0].url
})
}
}
const onChangeUsername = (e) => {
setState((draft) => {
draft.formUserInfo.username = e.detail.value
})
}
const { agreeTime } = Taro.getStorageSync(SG_POLICY)
let policyAgreeText = ''
if (agreeTime) {
policyAgreeText = `${formatTime(agreeTime, 'YYYY年MM月DD日')}同意`
}
// console.log('formUserInfo:', formUserInfo)
const renderAvatar = () => {
if (isWeixin) {
return (
<Button class='avatar-wrapper' open-type='chooseAvatar' onChooseAvatar={onChooseAvatar}>
{formUserInfo.avatar ? <SpImage src={formUserInfo.avatar} width={110} height={110} circle /> : <SpImage src={'cart/logo-hui.png'} width={110} height={110} circle isNew />}
</Button>
)
} else {
return (
<View class='avatar-wrapper' onClick={onUploadAvatarFile}>
<SpImage src={formUserInfo.avatar || 'user_icon.png'} width={110} height={110} circle />
</View>
)
}
}
return (
<SpPage
ref={pageRef}
className='pages-member-user-info has-navbar'
renderFooter={
<AtButton type='primary' disabled={!checked} onClick={saveUserInfo}>
保存
</AtButton>
}
loading={loading}
>
<View className='block-container'>
{/* <SpCell title='头像' isLink border value={renderAvatar()}></SpCell> */}
<View className="avatar-block">
{renderAvatar()}
{/* <View className="avatar-text">编辑</View> */}
<Button class='avatar-text' open-type='chooseAvatar' onChooseAvatar={onChooseAvatar}>编辑</Button>
</View>
<View className="user-form">
{formItems.map((item, index) => <View className="user-form-item" key={`userinfo-item__${index}`}>
<View className="user-form-item-title">{item.name}</View>
<View className="user-form-item-input">
{/* {item.element_type == 'input' ? <Input className="" placeholder={'请输入' + item.name}></Input>
: renderFormItem(item)} */}
{item.key === 'username' ? <Input
name='nickname'
value={formUserInfo.username}
type='nickname'
class='input-field-1'
placeholder='请输入昵称'
onInput={onChangeUsername}
onConfirm={onChangeUsername}
/> : renderFormItem(item)}
{(item.element_type === 'select' || item.element_type === 'date') && <View className="iconfont icon-arrowRight" style={{ color: item.key === 'birthday' && !userInfo.birthday_can_edit ? '#a5a5a5' : '#000' }}></View>}
</View>
</View>)}
</View>
{false && <><SpCell
title='昵称'
isLink
border
value={
<Input
name='nickname'
value={formUserInfo.username}
type='nickname'
class='input-field'
placeholder='请输入昵称'
onInput={onChangeUsername}
onConfirm={onChangeUsername}
/>
}
></SpCell>
<SpCell
isLink
title='手机'
value={userInfo?.mobile}
onClick={() => {
Taro.navigateTo({
url: '/subpages/auth/edit-phone'
})
}}
></SpCell></>}
</View>
{/* <View className='block-container'>
{formItems.map((item, index) => (
<SpCell
title={item.name}
isLink={item.element_type != 'input'}
key={`userinfo-item__${index}`}
border={index < formItems.length - 1}
value={renderFormItem(item)}
></SpCell>
))}
</View> */}
<View className='block-container'>
<View className='check-box'>
{/* <Checkbox value='选中' checked={state.checked} >选中</Checkbox> */}
<SpCheckbox checked={checked} colors="#000" onChange={() => setState((draft) => { draft.checked = !checked })} />
<View>
<Text onChange={() => setState((draft) => { draft.checked = !draft.checked })} >我已经阅读并同意</Text>
<Text
onClick={() => Taro.navigateTo({ url: '/subpages/auth/reg-rule?type=member_logout' })}
style={`color: #000000`}
>
{`${appName}使用条款》`}
</Text>
<Text
onClick={() => Taro.navigateTo({ url: '/subpages/auth/reg-rule?type=privacyAndregister' })}
style={`color: #000000`}
>
隐私政策
</Text>
</View>
</View>
{/* 注销账号 */}
<View className="cancel-account">
<View className="cancel-account-left" onClick={() => Taro.navigateTo({ url: '/subpages/auth/reg-rule?type=privacyAndregister' })}>会员规则</View>
<View className="cancel-account-right" onClick={handleLogOff}>账户注销</View>
</View>
{/* <SpCell
isLink
title='隐私政策和用户协议'
value={policyAgreeText}
onClick={() => {
Taro.navigateTo({
url: '/subpages/auth/reg-rule?type=privacyAndregister'
})
}}
></SpCell> */}
</View>
{/* <View className='block-container'>
<SpCell
isLink
title='注销账号'
value='注销后无法恢复,请谨慎操作'
onClick={handleLogOff}
></SpCell>
</View> */}
{isWeb && (
<View className='block-container'>
<SpCell isLink title='退出登录' value='退出当前账号' onClick={handleLogOut}></SpCell>
</View>
)}
<SpFloatLayout
title={checkboxPickerTitle}
open={showCheckboxPicker}
onClose={() => {
setState((draft) => {
draft.showCheckboxPicker = false
})
}}
renderFooter={
<AtButton
// circle
type='primary'
onClick={() => {
// const fd = checkboxList.filter((item) => !!item.checked)
setState((draft) => {
draft.formUserInfo[checkboxKey] = checkboxList
draft.showCheckboxPicker = false
})
}}
>
确定
</AtButton>
}
>
{checkboxList.map((item, index) => (
<View className='checkout-item' key={`checkout-item__${index}`}>
<SpCheckbox
checked={item.ischecked}
onChange={(e) => {
setState((draft) => {
draft.checkboxList[index].ischecked = e
})
}}
>
{item.name}
</SpCheckbox>
</View>
))}
</SpFloatLayout>
</SpPage>
)
}
MemberUserInfo.options = {
addGlobalClass: true
}
export default MemberUserInfo