内容修改

This commit is contained in:
tx 2024-12-31 10:14:54 +08:00
parent a9055522cf
commit 8a6f0fcffe
9 changed files with 543 additions and 76 deletions

14
package-lock.json generated
View File

@ -43,6 +43,7 @@
"react-native-svg": "^15.10.1",
"react-native-toast-message": "^2.2.1",
"react-native-view-shot": "^4.0.0",
"react-native-webview": "^13.12.5",
"react-native-wheel-picker-android": "^2.0.6",
"rn-fetch-blob": "^0.12.0",
"rn-qr-generator": "^1.4.3",
@ -14701,6 +14702,19 @@
"react-native": "*"
}
},
"node_modules/react-native-webview": {
"version": "13.12.5",
"resolved": "https://registry.npmmirror.com/react-native-webview/-/react-native-webview-13.12.5.tgz",
"integrity": "sha512-INOKPom4dFyzkbxbkuQNfeRG9/iYnyRDzrDkJeyvSWgJAW2IDdJkWFJBS2v0RxIL4gqLgHkiIZDOfiLaNnw83Q==",
"dependencies": {
"escape-string-regexp": "^4.0.0",
"invariant": "2.2.4"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-wheel-picker-android": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/react-native-wheel-picker-android/-/react-native-wheel-picker-android-2.0.6.tgz",

View File

@ -45,6 +45,7 @@
"react-native-svg": "^15.10.1",
"react-native-toast-message": "^2.2.1",
"react-native-view-shot": "^4.0.0",
"react-native-webview": "^13.12.5",
"react-native-wheel-picker-android": "^2.0.6",
"rn-fetch-blob": "^0.12.0",
"rn-qr-generator": "^1.4.3",

View File

@ -18,6 +18,7 @@ import TestBule from '../views/device/test_bule';
import ShareDetailScreen from '../views/device/KeyDetail';
import ExpiredKeysScreen from '../views/device/ExpiredKeysScreen';
import deviceDetailSet from '../views/device/deviceDetailSet';
import HelpCenterPage from '../views/user/HelpCenterPage';
const Stack = createStackNavigator<HomeStackParamList>();
const createScreenOptions = (title: string): StackNavigationOptions => {
@ -81,6 +82,13 @@ export default function HomeStackNavigator({ navigation, route }: Props) {
headerShown: false,
}}
/>
<Stack.Screen
name="HelpCenterPage"
component={HelpCenterPage}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="BindIndex"
component={BindIndex}

View File

@ -31,6 +31,7 @@ export type HomeStackParamList = {
ShareDetailScreen: undefined;
ExpiredKeysScreen: undefined;
deviceDetailSet: undefined;
HelpCenterPage: undefined;
};
// 导航属性类型

View File

@ -82,40 +82,63 @@ export const apiService = {
phoneCodeLogin: (phone: string, phoneCode: string, uuid: string) =>
api.post('/appCodeLogin', { phone, phoneCode, uuid }),
// 密码登录
passwordLogin: (username: string, password: string) =>
api.post('/appLogin', { username, password }),
register: (username: string, password: string, code: string, uuid: string) =>
api.post('/register', { username, password, code, uuid }),
// 重置密码
resetPassword: (phone: string, newPassword: string, phoneCode: string, uuid: string) =>
api.post('/forgotPassword', { phone, newPassword, phoneCode, uuid }),
// 获取用户信息
getUserInfo: () => api.get('/getInfo'),
// 获取设备信息
getDeviceInfo: (sn: string) =>
api.get('/appVerify/getDeviceBySn', { params: { sn } }),
// 绑定设备
bindSn: (sn: string) =>
api.post('/appVerify/userBandDevice?sn=' + sn),
// 获取设备列表
getDeviceList: () => api.get('/appVerify/getDeviceListByMerchantToken'),
toggleDefault: (sn: string) => api.put(`/appVerify/toggleDefault?sn=${sn}`),
// 响铃
ring: (sn: string) => api.post(`/app/device/ring?sn=${sn}`),
// 解锁
unlocking: (sn: string) => api.post(`/appVerify/admin/unlocking?sn=${sn}`),
// 锁车
lock: (sn: string) => api.post(`/appVerify/admin/lock?sn=${sn}`),
// 获取钥匙列表
getKeyListByOwnerId: () => api.get('/appVerify/getKeyListByOwnerId'),
// 添加钥匙
addKey: (data: any) => api.post('/appVerify/addKey', data),
// 更新钥匙
updateKey: (data: any) => api.put('/appVerify/editKey', data),
// 删除钥匙
deleteKey: (key: any) => api.delete('/appVerify/del/' + key),
// 获取过期钥匙
getExpiredKeys: () => api.get('/appVerify/getExpiredKeyListByOwnerId'),
// 获取钥匙信息
getKeyInfo: (keyId: string) => api.get('/appVerify/key/'+keyId),
// 绑定钥匙
bindKey: (keyId: string) => api.post('/appVerify/claimKey?keyId='+keyId),
// 更新设备
updateDevice: ( data: any) => api.put('/appVerify/device/edit', data),
// 解绑设备
untieDevice: (deviceId: string) => api.post('/appVerify/untie/'+deviceId),
// 获取七牛云token
getQiniuToken: () => api.get('/common/qiniu/uploadInfo'),
// 获取车型
getModelList: () => api.get('/appVerify/modelList'),
// 获取帮助中心分类
getClassifyList: () => api.get('/app/classify/list'),
// 获取帮助中心文章列表
getArticleList: (classifyId: string) => api.get('/app/article/list?classifyId=' + classifyId),
// 获取客服电话
getServerPhone: () => api.get('/app/getServerPhone'),
// updateKeyExpiration: (keyId: string, expirationTime: string) => api.put('/appVerify/updateKeyExpiration', { keyId, expirationTime }),
};

View File

@ -101,7 +101,7 @@ const ProfileScreen = () => {
<TouchableOpacity
style={styles.item}
onPress={() => navigation.navigate('HelpCenter')}
onPress={() => navigation.navigate('HelpCenterPage')}
>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uO1ju1OpuA5jjMR7bLYh' }}

View File

@ -91,39 +91,49 @@ const deviceDetailSet = () => {
const [brandList, setBrandList] = useState([]);
const [modelList, setModelList] = useState([]);
const [modelModalVisible, setModelModalVisible] = useState(false);
const [previewImage, setPreviewImage] = useState<string | null>(null);
const upload = async () => {
try {
const result = await uploadImageService.uploadImage();
if (result) {
const response = await apiService.updateDevice({
sn: deviceInfo.sn,
pricture: result
if (!result || !Array.isArray(result) || result.length === 0) {
Toast.show({
type: 'error',
text1: '上传失败',
text2: '请重试',
});
return;
}
const imageUrl = result[0]; // 从数组中提取 URL
const response = await apiService.updateDevice({
sn: deviceInfo.sn,
pricture: imageUrl
});
if (response.code == 200) {
setDeviceInfo(prevInfo => ({
...prevInfo,
pricture: imageUrl
}));
setModalVisible(false);
Toast.show({
type: 'success',
text1: '修改成功',
});
fetchDeviceInfo();
} else {
Toast.show({
type: 'error',
text1: response.msg || '修改失败',
});
if (response.code === 200) {
setDeviceInfo(prevInfo => ({
...prevInfo,
pricture: result
}));
Toast.show({
type: 'success',
text1: '图片上传成功',
});
fetchDeviceInfo();
} else {
Toast.show({
type: 'error',
text1: response.msg || '图片上传失败',
});
}
}
} catch (error) {
console.error('Upload failed:', error);
console.error('Update failed:', error);
Toast.show({
type: 'error',
text1: '上传失败',
text1: '更新失败',
text2: '请检查网络连接',
});
}
@ -142,7 +152,7 @@ const deviceDetailSet = () => {
}
const response = await apiService.getDeviceInfo(sn);
if (response.code === 200 && response.data) {
if (response.code == 200 && response.data) {
setDeviceInfo(response.data);
} else {
Toast.show({
@ -177,9 +187,6 @@ const deviceDetailSet = () => {
const models = modelData.filter(item => item.brandName === brand).map(item => item.model);
setModelList(models);
setSelectedModelIndex(new IndexPath(0));
const initialModel = models[0];
const initialImageUrl = getImageUrl(brand, initialModel);
setPreviewImage(initialImageUrl);
};
const getImageUrl = (brand, model) => {
@ -187,6 +194,41 @@ const deviceDetailSet = () => {
return selectedModel ? selectedModel.picture : null;
};
const updateDeviceImage = async (brand, model) => {
const imageUrl = getImageUrl(brand, model);
if (imageUrl && deviceInfo?.sn) {
try {
const response = await apiService.updateDevice({
sn: deviceInfo.sn,
pricture: imageUrl
});
console.log(response,'图片上传');
if (response.code == 200) {
setDeviceInfo(prevInfo => ({
...prevInfo,
pricture: imageUrl
}));
Toast.show({
type: 'success',
text1: '图片更新成功',
});
} else {
Toast.show({
type: 'error',
text1: response.msg || '图片更新失败',
});
}
} catch (error) {
console.error('图片更新失败:', error);
Toast.show({
type: 'error',
text1: '图片更新失败',
text2: '请检查网络连接',
});
}
}
};
const handleBrandChange = (index) => {
setSelectedBrandIndex(index);
const brand = brandList[index.row];
@ -195,50 +237,12 @@ const deviceDetailSet = () => {
const handleModelChange = (index) => {
setSelectedModelIndex(index);
const model = modelList[index.row];
const brand = brandList[selectedBrandIndex.row];
const imageUrl = getImageUrl(brand, model);
setPreviewImage(imageUrl);
};
const handleModelSelection = async () => {
if (!selectedBrandIndex || !selectedModelIndex) return;
const handleModelSelection = () => {
const brand = brandList[selectedBrandIndex.row];
const model = modelList[selectedModelIndex.row];
const imageUrl = getImageUrl(brand, model);
try {
const response = await apiService.updateDevice({
sn: deviceInfo.sn,
pricture: imageUrl
});
if (response.code === 200) {
setDeviceInfo(prevInfo => ({
...prevInfo,
pricture: imageUrl
}));
Toast.show({
type: 'success',
text1: '车辆信息更新成功',
});
fetchDeviceInfo();
} else {
Toast.show({
type: 'error',
text1: response.msg || '车辆信息更新失败',
});
}
} catch (error) {
console.error('Update failed:', error);
Toast.show({
type: 'error',
text1: '更新失败',
text2: '请检查网络连接',
});
}
updateDeviceImage(brand, model);
setModelModalVisible(false);
};
@ -258,6 +262,93 @@ const deviceDetailSet = () => {
/>
);
const handleEdit = (type: 'remark' | 'fullVoltage' | 'vehicleNum' | 'lowVoltage' | 'fullEndurance') => {
let title = '';
let value = '';
switch (type) {
case 'remark':
title = '修改备注';
value = deviceInfo?.remark || '';
break;
case 'fullVoltage':
title = '修改满电电压';
value = deviceInfo?.fullVoltage || '';
break;
case 'vehicleNum':
title = '修改车牌号';
value = deviceInfo?.vehicleNum || '';
break;
case 'lowVoltage':
title = '修改亏电电压';
value = deviceInfo?.lowVoltage || '';
break;
case 'fullEndurance':
title = '修改满电续航';
value = deviceInfo?.fullEndurance || '';
break;
}
setCurrentEdit({ title, value, type });
setModalVisible(true);
};
const handleSubmit = async (value: string) => {
if (!currentEdit || !deviceInfo?.sn) return;
try {
const response = await apiService.updateDevice({
sn: deviceInfo.sn,
[currentEdit.type]: value
});
if (response.code === 200) {
setDeviceInfo(prevInfo => ({
...prevInfo,
[currentEdit.type]: value
}));
setModalVisible(false);
Toast.show({
type: 'success',
text1: '修改成功',
});
fetchDeviceInfo();
} else {
Toast.show({
type: 'error',
text1: response.msg || '修改失败',
});
}
} catch (error) {
console.error('Update failed:', error);
Toast.show({
type: 'error',
text1: '更新失败',
text2: '请检查网络连接',
});
}
};
const handleUnbind = () => {
apiService.untieDevice(deviceInfo.deviceId).then((res) => {
if (res.code == 200) {
Toast.show({
type: 'success',
text1: '解绑成功',
});
navigation.goBack();
}
});
};
if (isLoading) {
return (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#333333" />
</View>
);
}
return (
<View style={styles.container}>
<TopNavigation
@ -271,15 +362,17 @@ const deviceDetailSet = () => {
scrollEventThrottle={16}
nestedScrollEnabled={true}
>
<ImageBackground
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uYRs7Cv2Pbp95w3KjGO3' }}
style={styles.imageBackground}
>
<ImageBackground
source={{ uri: 'https://lxnapi.ccttiot.com/FqAu65KgcylSRv1pD4008a_Ctpz-' }}
style={styles.carInfo}
>
<Image source={{ uri: deviceInfo?.pricture || 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }} style={{ width: rpx(440), height: rpx(340) }} />
<Image source={{ uri: deviceInfo?.pricture ? deviceInfo?.pricture : 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }} style={{ width: rpx(440), height: rpx(340) }} />
<View style={styles.carInfoButtons}>
<TouchableOpacity style={styles.carInfoButton} onPress={upload} >
<Text style={styles.carInfoButtonText}></Text>
@ -290,7 +383,69 @@ const deviceDetailSet = () => {
</View>
</ImageBackground>
<View style={styles.infoContainer}>
{/* ... existing info items ... */}
<View style={styles.infoItem}>
<Text style={styles.label}></Text>
<TouchableOpacity
style={styles.valueContainer}
onPress={() => handleEdit('remark')}
>
<Text style={styles.value}>{deviceInfo?.remark || '未设置'}</Text>
<Icon name='chevron-right' fill='#999999' style={styles.arrow} />
</TouchableOpacity>
</View>
<View style={styles.infoItem}>
<Text style={styles.label}></Text>
<TouchableOpacity
style={styles.valueContainer}
onPress={() => handleEdit('fullVoltage')}
>
<Text style={styles.value}>{deviceInfo?.fullVoltage || '未设置'}</Text>
<Icon name='chevron-right' fill='#999999' style={styles.arrow} />
</TouchableOpacity>
</View>
<View style={styles.infoItem}>
<Text style={styles.label}></Text>
<TouchableOpacity
style={styles.valueContainer}
onPress={() => handleEdit('lowVoltage')}
>
<Text style={styles.value}>{deviceInfo?.lowVoltage || '未设置'}</Text>
<Icon name='chevron-right' fill='#999999' style={styles.arrow} />
</TouchableOpacity>
</View>
<View style={styles.infoItem}>
<Text style={styles.label}></Text>
<TouchableOpacity
style={styles.valueContainer}
onPress={() => handleEdit('fullEndurance')}
>
<Text style={styles.value}>{deviceInfo?.fullEndurance || '未设置'}</Text>
<Icon name='chevron-right' fill='#999999' style={styles.arrow} />
</TouchableOpacity>
</View>
<View style={styles.infoItem}>
<Text style={styles.label}></Text>
<TouchableOpacity
style={styles.valueContainer}
onPress={() => handleEdit('vehicleNum')}
>
<Text style={styles.value}>{deviceInfo?.vehicleNum || '未设置'}</Text>
<Icon name='chevron-right' fill='#999999' style={styles.arrow} />
</TouchableOpacity>
</View>
<View style={styles.infoItem}>
<Text style={styles.label}></Text>
<TouchableOpacity
style={styles.valueContainer}
onPress={() => navigation.navigate('DeviceSet')}
>
<Text style={styles.value}></Text>
<Icon name='chevron-right' fill='#999999' style={styles.arrow} />
</TouchableOpacity>
</View>
</View>
<TouchableOpacity style={styles.unbindButton} onPress={handleUnbind}>
@ -318,7 +473,7 @@ const deviceDetailSet = () => {
<View style={styles.modalContent}>
<Text style={styles.modalTitle}></Text>
<Image
source={{ uri: previewImage || 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
source={{ uri: getImageUrl(brandList[selectedBrandIndex?.row], modelList[selectedModelIndex?.row]) || 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
style={styles.modalImage}
/>
<Select

View File

@ -0,0 +1,257 @@
import React, { useState, useEffect } from 'react';
import { View, StyleSheet, ScrollView, Image, TouchableOpacity, Alert } from 'react-native';
import { TopNavigation, TopNavigationAction, Icon, Text, Button } from '@ui-kitten/components';
import { apiService } from '../../utils/api';
import { rpx } from '../../utils/rpx';
const BackIcon = (props) => (
<Icon {...props} name='arrow-back' />
);
const HelpCenterPage = ({ navigation }) => {
const [showQrcode, setShowQrcode] = useState(false);
const [phone, setPhone] = useState({ serverWx: '', serverPhone: '' });
const [classifyList, setClassifyList] = useState([]);
const [wordlist, setWordlist] = useState([]);
const [tabindex, setTabindex] = useState(0);
useEffect(() => {
fetchClassifyList();
fetchPhone();
}, []);
const navigateBack = () => {
navigation.goBack();
};
const BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={navigateBack} />
);
const fetchPhone = async () => {
// 模拟获取电话信息
const response = await apiService.getServerPhone();
setPhone(response.data);
};
const fetchClassifyList = async () => {
const response = await apiService.getClassifyList();
console.log(response,'分类列表');
setClassifyList(response.data);
fetchArticleList(response.data[0].classifyId);
};
const fetchArticleList = async (id) => {
const response = await apiService.getArticleList(id);
setWordlist(response.data.rows);
};
const showWechat = () => {
setShowQrcode(true);
};
const callPhone = () => {
Alert.alert('拨打电话', `拨打电话: ${phone.serverPhone}`);
};
const changeTab = (index, id) => {
setTabindex(index);
fetchArticleList(id);
};
const topage = (item) => {
navigation.navigate('ArticlePage', { id: item.articleId });
};
return (
<View style={styles.container}>
<TopNavigation
title='帮助中心'
alignment='center'
accessoryLeft={BackAction}
/>
<ScrollView contentContainerStyle={styles.content}>
<Text category='h5' style={styles.title}>Hi~</Text>
<Text category='s1' style={styles.text}>工作时间: 工作日8:30-11:30 13:30-18:00</Text>
<View style={styles.helpBtnBox}>
<TouchableOpacity style={styles.helpBtnItem} onPress={showWechat}>
<View>
<Text style={styles.helpBtnItemLeftTit}></Text>
<Text style={styles.helpBtnItemLeftContent}></Text>
</View>
<Image source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uP0sux01iWvHzofugDjW' }} style={styles.helpBtnItemRightImg} />
</TouchableOpacity>
<View style={styles.line}></View>
<TouchableOpacity style={styles.helpBtnItem} onPress={callPhone}>
<View>
<Text style={styles.helpBtnItemLeftTit}></Text>
<Text style={styles.helpBtnItemLeftContent}></Text>
</View>
<Image source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uKt6yZ7lMykYci7yITT5' }} style={styles.helpBtnItemRightImg} />
</TouchableOpacity>
</View>
<View style={styles.qscard}>
<View style={styles.cardTop}>
{classifyList.map((item, index) => (
<TouchableOpacity key={index} style={styles.li} onPress={() => changeTab(index, item.classifyId)}>
<Text style={styles.txt}>{item.classifyName}</Text>
<View style={tabindex === index ? styles.botBorActive : styles.botBor}></View>
</TouchableOpacity>
))}
</View>
{wordlist.map((item, index) => (
<TouchableOpacity key={index} style={styles.qsLi} onPress={() => topage(item)}>
<Text style={styles.qsLiTxt}>{item.title}</Text>
<Icon name='arrow-forward' style={styles.icon} />
</TouchableOpacity>
))}
</View>
{showQrcode && (
<View style={styles.qrcodeContainer}>
<Text style={styles.qrcodeTitle}></Text>
<Image source={{ uri: phone.serverWx }} style={styles.qrcodeImage} />
<Button onPress={() => setShowQrcode(false)}></Button>
</View>
)}
</ScrollView>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
content: {
padding: rpx(16),
},
title: {
fontSize: rpx(36),
fontWeight: '700',
color: '#3D3D3D',
marginBottom: rpx(10),
},
text: {
fontSize: rpx(24),
fontWeight: '400',
color: '#3D3D3D',
marginVertical: rpx(8),
},
helpBtnBox: {
flexDirection: 'row',
alignItems: 'center',
marginTop: rpx(50),
padding: rpx(20),
backgroundColor: '#FFFFFF',
borderRadius: rpx(20),
shadowColor: '#000',
shadowOffset: { width: 0, height: rpx(6) },
shadowOpacity: 0.08,
shadowRadius: rpx(64),
},
helpBtnItem: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
},
helpBtnItemLeftTit: {
fontWeight: '700',
fontSize: rpx(28),
color: '#3D3D3D',
},
helpBtnItemLeftContent: {
marginTop: rpx(14),
fontWeight: '400',
fontSize: rpx(24),
color: '#3D3D3D',
},
helpBtnItemRightImg: {
width: rpx(84),
height: rpx(84),
},
line: {
width: rpx(2),
height: rpx(128),
backgroundColor: '#D8D8D8',
marginHorizontal: rpx(20),
},
qscard: {
width: '100%',
marginVertical: rpx(40),
backgroundColor: '#FFFFFF',
borderRadius: rpx(40),
padding: rpx(28),
shadowColor: '#2A82E4',
shadowOffset: { width: 0, height: rpx(16) },
shadowOpacity: 0.1,
shadowRadius: rpx(40),
},
cardTop: {
flexDirection: 'row',
alignItems: 'center',
},
li: {
minWidth: rpx(112),
marginRight: rpx(20),
},
txt: {
fontWeight: '500',
fontSize: rpx(28),
color: '#3D3D3D',
},
botBor: {
marginTop: rpx(-20),
width: '90%',
height: rpx(26),
backgroundColor: '#fff',
borderRadius: rpx(20),
},
botBorActive: {
marginTop: rpx(-20),
width: '90%',
height: rpx(26),
backgroundColor: 'rgba(66, 151, 243, 0.55)',
borderRadius: rpx(20),
},
qsLi: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderBottomWidth: rpx(2),
borderBottomColor: '#D8D8D870',
paddingVertical: rpx(26),
},
qsLiTxt: {
fontWeight: '400',
fontSize: rpx(28),
color: '#3D3D3D',
},
icon: {
fontSize: rpx(32),
color: '#3D3D3D',
},
qrcodeContainer: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.6)',
justifyContent: 'center',
alignItems: 'center',
},
qrcodeTitle: {
fontSize: rpx(32),
fontWeight: '500',
color: '#333',
marginBottom: rpx(30),
},
qrcodeImage: {
width: rpx(200),
height: rpx(200),
marginBottom: rpx(20),
},
});
export default HelpCenterPage;

View File

@ -5505,7 +5505,7 @@ internal-slot@^1.1.0:
hasown "^2.0.2"
side-channel "^1.1.0"
invariant@^2.2.4:
invariant@^2.2.4, invariant@2.2.4:
version "2.2.4"
resolved "https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz"
integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@ -7975,6 +7975,14 @@ react-native-view-shot@^4.0.0:
dependencies:
html2canvas "^1.4.1"
react-native-webview@^13.12.5:
version "13.12.5"
resolved "https://registry.npmmirror.com/react-native-webview/-/react-native-webview-13.12.5.tgz"
integrity sha512-INOKPom4dFyzkbxbkuQNfeRG9/iYnyRDzrDkJeyvSWgJAW2IDdJkWFJBS2v0RxIL4gqLgHkiIZDOfiLaNnw83Q==
dependencies:
escape-string-regexp "^4.0.0"
invariant "2.2.4"
react-native-wheel-picker-android@^2.0.6:
version "2.0.6"
resolved "https://registry.npmmirror.com/react-native-wheel-picker-android/-/react-native-wheel-picker-android-2.0.6.tgz"