版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28978893/article/details/80318781
import React, { Component } from 'react'
import { View, Text, TextInput, Image, ScrollView, InteractionManager, TouchableOpacity, TouchableWithoutFeedback, Modal, Animated, Platform, StyleSheet } from 'react-native'
import connectWithNavigationIsFocused from '../../Utils/NavigationIsFocused'
import * as ActionTypes from '../../Redux/ActionTypes'
import { ApplicationStyles, px2dp, Colors, metrics, FontSize } from '../../Themes'
import { toastAction } from '../../Redux/Actions'
import { ErrorPage } from '../../Components'
import Icon from '../../Fonts/iconfont'
let addressAllList = [
{ title: 'A', number: 0, scrollHeight: 0 },
{ title: 'B', number: 0, scrollHeight: 0 },
{ title: 'C', number: 0, scrollHeight: 0 },
{ title: 'D', number: 0, scrollHeight: 0 },
{ title: 'E', number: 0, scrollHeight: 0 },
{ title: 'F', number: 0, scrollHeight: 0 },
{ title: 'G', number: 0, scrollHeight: 0 },
{ title: 'H', number: 0, scrollHeight: 0 },
{ title: 'I', number: 0, scrollHeight: 0 },
{ title: 'J', number: 0, scrollHeight: 0 },
{ title: 'K', number: 0, scrollHeight: 0 },
{ title: 'L', number: 0, scrollHeight: 0 },
{ title: 'M', number: 0, scrollHeight: 0 },
{ title: 'N', number: 0, scrollHeight: 0 },
{ title: 'O', number: 0, scrollHeight: 0 },
{ title: 'P', number: 0, scrollHeight: 0 },
{ title: 'Q', number: 0, scrollHeight: 0 },
{ title: 'R', number: 0, scrollHeight: 0 },
{ title: 'S', number: 0, scrollHeight: 0 },
{ title: 'T', number: 0, scrollHeight: 0 },
{ title: 'U', number: 0, scrollHeight: 0 },
{ title: 'V', number: 0, scrollHeight: 0 },
{ title: 'W', number: 0, scrollHeight: 0 },
{ title: 'X', number: 0, scrollHeight: 0 },
{ title: 'Y', number: 0, scrollHeight: 0 },
{ title: 'Z', number: 0, scrollHeight: 0 }
]
class MyPatientScreen extends Component {
static navigationOptions = ({ navigation }) => {
return {
...ApplicationStyles.defaultHeaderStyleWithOutBorderBottom,
title: navigation.state.hasOwnProperty('params') && navigation.state.params.hasOwnProperty('title') ? navigation.state.params.title : ''
}
};
constructor (props) {
super(props)
this.state = {
firstLoad: true,
searchText: '',
rowHeight: 0,
newHeight: 0,
searchHeight: 0,
onNumber: 0,
modalVisible: false,
top: new Animated.Value(0)
}
/** functions */
/** object */
this.addressListSource = []
this.area = { min: null, max: null }
}
componentDidMount () {
InteractionManager.runAfterInteractions(() => {
if (this.props.role === 'ROLE_DOCTOR') {
// 好友列表
this.props.getUserPatient()
// 新的好友申请计数
this.props.countNewApplication()
} else {
// 获取医疗小组信息
this.props.getTeamDoctor()
}
this.props.navigation.setParams({
isDoctor: this.props.role === 'ROLE_DOCTOR'
})
})
}
componentWillReceiveProps (nextProps) {
if (!this.props.isFocused && nextProps.isFocused) {
this.onFocus()
}
if (this.props.isFocused && !nextProps.isFocused) {
this.onBlur()
}
if (nextProps.friendList.length !== this.props.friendList.length) {
console.log('获取到了新的好友列表*****************************')
/** 右侧通讯录筛选与配置 */
const that = this
this.setIntervalAddress = setInterval(function () {
if (that.state.searchHeight && that.state.newHeight && that.state.rowHeight) {
that.sortAddress(nextProps.friendList)
clearInterval(that.setIntervalAddress)
}
}, 300)
}
}
componentWillUnmount () {
/** 清除定时器 */
clearTimeout(this.setTimeout)
}
onFocus () {
const { getUserPatient, countNewApplication, role, getTeamDoctor, toggleTabBarAction } = this.props
toggleTabBarAction(true, 1)
if (role === 'ROLE_DOCTOR') {
// 医生角色
/** 好友列表 */
getUserPatient()
/** 新的好友申请计数 */
countNewApplication()
if (this.state.firstLoad) {
this.setState({ firstLoad: false })
}
let i = 0
const that = this
if (undefined !== this.setInterval) clearInterval(this.setInterval)
this.setInterval = setInterval(function () {
i++
if (i >= 30) clearInterval(that.setInterval)
getUserPatient()
countNewApplication()
}, 20000)
} else {
// 护士角色
getTeamDoctor()
}
}
onBlur () {
clearInterval(this.setInterval)
this.props.toggleTabBarAction(false, 1)
}
// 右侧通讯录
sortAddress (friendList) {
/** ************************* 右侧通讯录 **********************************/
/**
* 计算每层个数
*/
this.addressListSource = []
let tempList = [
{ title: 'A', number: 0, scrollHeight: 0 },
{ title: 'B', number: 0, scrollHeight: 0 },
{ title: 'C', number: 0, scrollHeight: 0 },
{ title: 'D', number: 0, scrollHeight: 0 },
{ title: 'E', number: 0, scrollHeight: 0 },
{ title: 'F', number: 0, scrollHeight: 0 },
{ title: 'G', number: 0, scrollHeight: 0 },
{ title: 'H', number: 0, scrollHeight: 0 },
{ title: 'I', number: 0, scrollHeight: 0 },
{ title: 'J', number: 0, scrollHeight: 0 },
{ title: 'K', number: 0, scrollHeight: 0 },
{ title: 'L', number: 0, scrollHeight: 0 },
{ title: 'M', number: 0, scrollHeight: 0 },
{ title: 'N', number: 0, scrollHeight: 0 },
{ title: 'O', number: 0, scrollHeight: 0 },
{ title: 'P', number: 0, scrollHeight: 0 },
{ title: 'Q', number: 0, scrollHeight: 0 },
{ title: 'R', number: 0, scrollHeight: 0 },
{ title: 'S', number: 0, scrollHeight: 0 },
{ title: 'T', number: 0, scrollHeight: 0 },
{ title: 'U', number: 0, scrollHeight: 0 },
{ title: 'V', number: 0, scrollHeight: 0 },
{ title: 'W', number: 0, scrollHeight: 0 },
{ title: 'X', number: 0, scrollHeight: 0 },
{ title: 'Y', number: 0, scrollHeight: 0 },
{ title: 'Z', number: 0, scrollHeight: 0 }
]
friendList.map((item) => {
addressAllList.map((element, index) => {
if (element.title === item.phonetic) {
let { number } = tempList[index]
// console.log('出现一个相同项' + item.letter)
tempList.splice(index, 1, { ...tempList[index], number: number + 1 })
}
})
})
/**
* 计算每层y
*/
tempList.map((item, index) => {
let change = {}
if (index === 0) {
change = { ...item, scrollHeight: this.state.searchHeight + this.state.newHeight }
} else {
const { scrollHeight, number } = this.addressListSource[index - 1]
change = { ...item, scrollHeight: scrollHeight + number * this.state.rowHeight }
}
this.addressListSource.push(change)
if (index === 25) {
this.props.setContactSearchList({ contactSearchList: this.addressListSource })
}
})
}
// 滚动轴滑动
onScroll (e) {
let contentOffsetY = e.nativeEvent.contentOffset.y
let navigation = this.props.navigation
this.title.measure((x, y, width, height, left, top) => {
// 遮盖标题
if (contentOffsetY >= height) {
navigation.setParams({ title: '我的患者' })
} else {
if (navigation.state.hasOwnProperty('params') && navigation.state.params.hasOwnProperty('title') && navigation.state.params.title) navigation.setParams({ title: '' })
}
})
}
// 是否滑动到当前的层
isScrollOn (e) {
this.onScroll(e)
const y = e.nativeEvent.contentOffset.y
console.log('实时高度' + y)
/** 重复区间与异常值判断 */
const { min, max } = this.area
/** 场景一 实时数据位于结果区间 */
let reason1 = !!((min && max && (y >= min && y < max)))
/** 场景二 实时数据位于结果区间 */
let reason2 = !!((min && !max && y >= min))
/** 场景三 实时数据从上侧滑出列表区域 */
let reason3 = !!((y < min && y < (this.state.searchHeight + this.state.newHeight)))
/** 初始化 */
let reason4 = !!((!min && !max))
console.log('监听到滑动操作,判断是否需要重新定位*******************')
console.log('reason1' + reason1 + 'reason2' + reason2 + 'reason3' + reason3 + 'reason4' + reason4)
if ((!reason1 && !reason2 && !reason3) || reason4) {
console.log('分层处理频率**********************************')
console.log(y)
console.log(this.area)
this.props.contactSearchList && this.props.contactSearchList.length > 0 && this.props.contactSearchList.map((item, index) => {
if (index <= this.props.contactSearchList.length - 2) {
if (y >= item.scrollHeight && y < this.props.contactSearchList[index + 1].scrollHeight) {
this.area = { min: item.scrollHeight, max: this.props.contactSearchList[index + 1].scrollHeight }
this.setState({ onNumber: index })
}
} else {
if (y >= item.scrollHeight) {
this.area = { min: item.scrollHeight, max: null }
this.setState({ onNumber: index })
}
}
})
}
}
// 获取area
getLoayout (key, event) {
// 获取根View的宽高,以及左上角的坐标值
let { x, y, width, height } = event.nativeEvent.layout
this.setState({ [key]: key === 'newHeight' ? y : height })
}
doctor () {
const { navigation, friendList, newApplicationNumber, contactSearchList } = this.props
const { searchText, onNumber, modalVisible, top, searchHeight, newHeight, headerHeight } = this.state
return (
<View style={{ flex: 1 }}>
<ScrollView
ref={e => { if (e) this.scroll = e }}
overScrollMode='always'
/** onScroll 回调频率 */
scrollEventThrottle={2}
onScroll={(e) => this.isScrollOn(e)}
>
<View ref={e => { if (e) this.title = e }} style={[Styles.titleView]} onLayout={e => this.getLoayout('headerHeight', e)}>
<Text style={Styles.title}>我的患者</Text>
<TouchableWithoutFeedback onPress={() => navigation.navigate('addPatient')}>
<Icon name='record' color={Colors.CB} size={px2dp(48)} />
</TouchableWithoutFeedback>
</View>
<View style={{ backgroundColor: Colors.C7 }} onLayout={e => this.getLoayout('searchHeight', e)}>
<View style={{ borderWidth: 1, borderColor: Colors.C7, borderRadius: px2dp(10), justifyContent: 'center', backgroundColor: Colors.C8, margin: px2dp(20), marginLeft: px2dp(30), marginRight: px2dp(30) }}>
<TextInput style={{ height: px2dp(60), fontSize: px2dp(28) }} underlineColorAndroid='transparent' />
<TouchableWithoutFeedback onPress={() => {
this.setState({ modalVisible: true })
Animated.timing(this.state.top, {
toValue: 1,
duration: 300
}).start(() => this.refs.searchText.focus())
}}>
<View style={{ flexDirection: 'row', justifyContent: 'center', alignItems: 'center', height: px2dp(60), marginTop: -px2dp(60) }}>
<Icon name='search' size={px2dp(30)} color={Colors.C6} />
<Text style={{ fontSize: px2dp(28), color: Colors.C5, marginLeft: px2dp(10) }}>搜索</Text>
</View>
</TouchableWithoutFeedback>
</View>
</View>
<View style={{ padding: px2dp(30), paddingLeft: px2dp(50), paddingRight: 0, backgroundColor: Colors.C8 }}>
<TouchableOpacity onPress={() => navigation.navigate('newPatientList')}>
<View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', paddingBottom: px2dp(20), borderBottomWidth: 1, borderBottomColor: Colors.C7 }}>
<View style={{ height: px2dp(70), width: px2dp(70), borderRadius: px2dp(35), backgroundColor: Colors.CB, justifyContent: 'center', alignItems: 'center' }} >
<Icon name='add-friend' size={px2dp(34)} color={Colors.C8} />
</View>
<Text style={{ fontSize: px2dp(28), lineHeight: px2dp(40), color: Colors.C3, marginLeft: px2dp(20) }}>新的患者</Text>
{ newApplicationNumber > 0 &&
<View style={{ width: px2dp(40), height: px2dp(40), backgroundColor: '#ff3a30', borderRadius: px2dp(20), justifyContent: 'center', alignItems: 'center', marginLeft: px2dp(10) }}>
<Text style={{ fontSize: px2dp(26), color: Colors.C8 }}>{newApplicationNumber}</Text>
</View>
}
</View>
</TouchableOpacity>
<View style={{ }} onLayout={e => this.getLoayout('newHeight', e)}>
{
undefined !== friendList && friendList && friendList.length > 0 && friendList.map((item, index) => {
const { id, oppositeUserId, oppositePhoneNumber, oppositeAvatar, oppositeNickname, oppositeNote, oppositeGender, oppositeHeight, oppositeWeight, diseaseHistories, oppositeAge, assignedNurse, bodyMassIndex } = item
return (
<TouchableOpacity onPress={() => navigation.navigate('patientInfo', { friendId: id, receiver: oppositeUserId, oppositeAvatar, oppositeNickname, oppositePhoneNumber, oppositeNote, oppositeGender, oppositeHeight, oppositeWeight, diseaseHistories, oppositeAge, assignedNurse, bodyMassIndex, index })} key={index} onLayout={e => this.getLoayout('rowHeight', e)}>
<View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', paddingTop: px2dp(20), paddingBottom: px2dp(20), borderBottomWidth: 1, borderBottomColor: Colors.C7 }}>
<Image source={oppositeAvatar ? { uri: oppositeAvatar } : require('../../Images/PersonalCenter/avatar.png')} style={{ width: px2dp(80), height: px2dp(80), borderRadius: px2dp(40) }} />
<Text style={{ fontSize: px2dp(24), lineHeight: px2dp(34), color: Colors.C3, marginLeft: px2dp(20) }}>{oppositeNickname || oppositePhoneNumber}</Text>
</View>
</TouchableOpacity>
)
})
}
</View>
</View>
</ScrollView>
<View style={{ position: 'absolute', top: searchHeight + newHeight + headerHeight, right: px2dp(6) }}>
{ contactSearchList && contactSearchList.length > 0 && contactSearchList.map((item, index) => {
const { title, number, scrollHeight } = item
return (number !== 0 &&
<TouchableWithoutFeedback onPress={() => { this.scroll.scrollTo({ y: scrollHeight, animated: true }) }} key={index}>
<View style={{ width: px2dp(40), height: px2dp(40), borderRadius: px2dp(20), margin: px2dp(4), backgroundColor: onNumber !== index ? Colors.C8 : Colors.CB, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ textAlign: 'center', fontSize: px2dp(24), color: onNumber !== index ? Colors.C3 : Colors.C8 }}>{title}</Text>
</View>
</TouchableWithoutFeedback>
)
})}
</View>
<Modal visible={modalVisible} onRequestClose={() => {}}>
<Animated.View style={{ flex: 1,
marginTop: px2dp(140) + metrics.NavBarElementMovingDelta,
transform: [{
translateY: top.interpolate({
inputRange: [0, 1],
outputRange: [0, -px2dp(90)]
})
}]
}}>
<View style={{ backgroundColor: Colors.C7, justifyContent: 'center' }}>
<View style={{ borderWidth: 1, borderColor: Colors.C7, borderRadius: px2dp(10), flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', backgroundColor: Colors.C8, margin: px2dp(20), marginLeft: px2dp(30), marginRight: px2dp(100) }}>
<View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', marginLeft: px2dp(20) }}>
<Icon name='search' size={px2dp(30)} color={Colors.C6} />
</View>
<TextInput ref='searchText' value={searchText} onChangeText={(text) => this.setState({ searchText: text })} style={[{ flex: 1, fontSize: px2dp(28), color: Colors.C5, marginLeft: px2dp(10), textAlignVertical: 'center' }, Platform.OS === 'android' ? { paddingBottom: px2dp(2), paddingTop: px2dp(2) } : { height: px2dp(60) }]} placeholder={'搜索'} returnKeyType='search' underlineColorAndroid='transparent' />
</View>
<TouchableOpacity onPress={() => {
Animated.timing(this.state.top, {
toValue: 0,
duration: 200
}).start(() => this.setState({ modalVisible: false, searchText: '' }))
}}
style={{ position: 'absolute', right: px2dp(20) }}>
<View style={{}}>
<Text style={{ fontSize: px2dp(28), color: Colors.CB }}>取消</Text>
</View>
</TouchableOpacity>
</View>
<ScrollView>
<View style={{ padding: px2dp(30), paddingTop: 0 }}>
{
undefined !== friendList && friendList && friendList.length > 0 && friendList.map((item, index) => {
const { id, oppositeUserId, oppositePhoneNumber, oppositeAvatar, oppositeNickname, oppositeNote, oppositeGender, oppositeHeight, oppositeWeight, diseaseHistories, oppositeAge, assignedNurse, bodyMassIndex } = item
let checked = true
if (!searchText || oppositeNickname.indexOf(searchText) === -1) return false
return (checked &&
<TouchableOpacity onPress={() => { this.setState({ modalVisible: false, top: new Animated.Value(0) }); navigation.navigate('patientInfo', { friendId: id, receiver: oppositeUserId, oppositeAvatar, oppositeNickname, oppositePhoneNumber, oppositeNote, oppositeGender, oppositeHeight, oppositeWeight, diseaseHistories, oppositeAge, assignedNurse, bodyMassIndex, index }) }} key={index}>
<View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', paddingTop: px2dp(20), paddingBottom: px2dp(20), borderBottomWidth: 1, borderBottomColor: Colors.C7 }}>
<Image source={oppositeAvatar ? { uri: oppositeAvatar } : require('../../Images/PersonalCenter/avatar.png')} style={{ width: px2dp(80), height: px2dp(80), borderRadius: px2dp(40) }} />
<Text style={{ fontSize: px2dp(24), lineHeight: px2dp(34), color: Colors.C3, marginLeft: px2dp(20) }}>{oppositeNickname || oppositePhoneNumber}</Text>
</View>
</TouchableOpacity>
)
})
}
</View>
</ScrollView>
</Animated.View>
</Modal>
</View>
)
}
nurse () {
const { navigation, doctorList } = this.props
return (
<View style={{ flex: 1 }}>
{!(doctorList && doctorList.length > 0) &&
<View style={{ position: 'absolute', left: 0, right: 0, bottom: px2dp(240) }}>
<ErrorPage message='暂无医疗小组信息,请联系医生进行关联' />
</View>
}
<ScrollView
contentContainerStyle={{ paddingLeft: px2dp(30) }}
ref={e => { if (e) this.scrollN = e }}
scrollEventThrottle={20}
onScroll={(e) => this.onScroll(e)}>
<View ref={e => { if (e) this.title = e }} style={[Styles.paddingView, Styles.titleView, { borderBottomWidth: StyleSheet.hairlineWidth, borderColor: Colors.C7 }]}>
<Text style={Styles.title}>我的患者</Text>
</View>
{ doctorList && doctorList.length > 0 &&
doctorList.map((item, index) => {
const { userId, nickname, picture, phoneNumber, employer, department, title, subordinateNumber, subordinateStaffs } = item
let serveDoctorId = userId
return (
<View key={index}>
<View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', paddingTop: px2dp(18), paddingBottom: px2dp(18), borderBottomWidth: 1, borderBottomColor: Colors.C7 }}>
<Image source={{ uri: picture }} style={{ width: px2dp(100), height: px2dp(100), borderRadius: px2dp(10) }} />
<View style={{ alignItems: 'flex-start', marginLeft: px2dp(20) }}>
<Text style={{ fontSize: px2dp(28), lineHeight: px2dp(34), color: Colors.C3 }}>{nickname || phoneNumber} 的医疗小组</Text>
<Text style={{ fontSize: px2dp(24), lineHeight: px2dp(34), color: Colors.C3, marginTop: px2dp(10) }}>{`分配患者人数:${subordinateNumber}` }</Text>
</View>
</View>
{subordinateStaffs && subordinateStaffs.length > 0
? subordinateStaffs.map((item, index) => {
let { userId, nickname, picture, phoneNumber } = item
return (
<TouchableWithoutFeedback onPress={() => navigation.navigate('patientInfo', { friendId: '', receiver: userId, oppositeAvatar: picture, oppositeNickname: nickname, oppositePhoneNumber: phoneNumber, oppositeNote: '', index, serveDoctorId })} key={index}>
<View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', padding: px2dp(60), paddingTop: px2dp(15), paddingBottom: px2dp(15), borderBottomWidth: 1, borderBottomColor: Colors.C7 }}>
<Image source={{ uri: picture }} style={{ width: px2dp(80), height: px2dp(80), borderRadius: px2dp(40) }} />
<Text style={{ fontSize: px2dp(28), lineHeight: px2dp(34), color: Colors.C3, marginLeft: px2dp(20) }}>{nickname || phoneNumber}</Text>
</View>
</TouchableWithoutFeedback>
)
})
: <View style={{ flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', padding: px2dp(60), paddingTop: px2dp(30), paddingBottom: px2dp(30), borderBottomWidth: 1, borderBottomColor: Colors.C7 }}>
<Text style={{ fontSize: px2dp(28), lineHeight: px2dp(34), color: Colors.C3 }}>该医疗小组暂未向您分配管理患者</Text>
</View>
}
</View>)
})
}
</ScrollView>
</View>
)
}
render () {
return (
<View style={{ flex: 1, backgroundColor: Colors.C8 }}>
{this.props.role === 'ROLE_DOCTOR' ? this.doctor() : this.nurse()}
</View>
)
}
}
const mapStateToProps = state => ({
strangerInfo: state.patient.strangerInfo,
friendList: state.patient.friendList,
newApplicationNumber: state.patient.newApplicationNumber,
contactSearchList: state.patient.contactSearchList,
username: state.user.username,
role: state.user.role,
doctorList: state.medicalTeam.doctorList,
showIndicator: state.medicalTeam.showIndicator
})
const mapDispatchToProps = dispatch => ({
toastAction: message => dispatch(toastAction(message)),
toggleTabBarAction: (showTabBar, index) => dispatch({ type: ActionTypes.TOGGLE_TAR_BAR, payload: { showTabBar, index } }),
countNewApplication: () => dispatch({ type: ActionTypes.COUNT_NEW_APPLICATION }),
getUserPatient: () => dispatch({ type: ActionTypes.GET_USER_PATIENT }),
setContactSearchList: ({ contactSearchList }) => dispatch({ type: ActionTypes.SET_CONTACT_SEARCH_LIST, payload: { contactSearchList } }),
getTeamDoctor: () => dispatch({ type: ActionTypes.GET_TEAM_DOCTOR_LIST })
})
export default connectWithNavigationIsFocused(
mapStateToProps,
mapDispatchToProps,
'tabMyPatient',
'mainTab',
1
)(MyPatientScreen)
const Styles = StyleSheet.create({
container: { flex: 1, backgroundColor: Colors.C8 },
titleView: { padding: px2dp(50), paddingTop: 0, paddingBottom: px2dp(18), flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
title: { fontSize: FontSize(62), color: Colors.C11, fontFamily: 'PingFang-SC-Medium', lineHeight: FontSize(88) },
paddingView: { paddingLeft: px2dp(50), paddingRight: px2dp(30) },
header: { height: px2dp(200), backgroundColor: 'rgba(0,0,0,0)', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center' },
avatar: { height: px2dp(140), width: px2dp(140), borderRadius: px2dp(70) },
headerMiddle: { marginLeft: px2dp(40) },
nickname: { fontSize: FontSize(36), color: Colors.C8 },
score: { fontSize: FontSize(22), color: Colors.C8, marginTop: px2dp(16) },
inconRight: { position: 'absolute', right: px2dp(30) },
options: { marginTop: px2dp(60), flexDirection: 'row', flexWrap: 'wrap', justifyContent: 'flex-start', alignItems: 'center' },
optionItem: { alignItems: 'center', marginBottom: px2dp(64), width: metrics.screenWidth / 3 },
optionName: { fontSize: FontSize(26), color: Colors.C11, fontFamily: 'PingFang-SC-Regular', marginTop: px2dp(18) }
})