钥匙共享
This commit is contained in:
parent
60b4b83704
commit
05872f47d7
|
@ -19,6 +19,8 @@
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||||
<application
|
<application
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
|
22
package-lock.json
generated
22
package-lock.json
generated
|
@ -32,6 +32,7 @@
|
||||||
"react-native-linear-gradient": "^2.8.3",
|
"react-native-linear-gradient": "^2.8.3",
|
||||||
"react-native-permissions": "^5.2.1",
|
"react-native-permissions": "^5.2.1",
|
||||||
"react-native-qrcode-scanner": "^1.5.5",
|
"react-native-qrcode-scanner": "^1.5.5",
|
||||||
|
"react-native-qrcode-svg": "^6.3.12",
|
||||||
"react-native-reanimated": "^3.16.1",
|
"react-native-reanimated": "^3.16.1",
|
||||||
"react-native-safe-area-context": "^4.14.0",
|
"react-native-safe-area-context": "^4.14.0",
|
||||||
"react-native-screens": "^3.35.0",
|
"react-native-screens": "^3.35.0",
|
||||||
|
@ -14696,6 +14697,21 @@
|
||||||
"react-native": ">=0.60.0"
|
"react-native": ">=0.60.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-qrcode-svg": {
|
||||||
|
"version": "6.3.12",
|
||||||
|
"resolved": "https://registry.npmmirror.com/react-native-qrcode-svg/-/react-native-qrcode-svg-6.3.12.tgz",
|
||||||
|
"integrity": "sha512-7Bx23ZdFNJJdVXyW9BJmFWdI5kccjnpotzmL3exkV0irUKTmj51jesxpn5sqtgVdYFE4IUVoGzdS+8qg6Ua9BA==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.8.0",
|
||||||
|
"qrcode": "^1.5.1",
|
||||||
|
"text-encoding": "^0.7.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": ">=0.63.4",
|
||||||
|
"react-native-svg": ">=13.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-reanimated": {
|
"node_modules/react-native-reanimated": {
|
||||||
"version": "3.16.3",
|
"version": "3.16.3",
|
||||||
"resolved": "https://registry.npmmirror.com/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz",
|
"resolved": "https://registry.npmmirror.com/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz",
|
||||||
|
@ -16440,6 +16456,12 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/text-encoding": {
|
||||||
|
"version": "0.7.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/text-encoding/-/text-encoding-0.7.0.tgz",
|
||||||
|
"integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==",
|
||||||
|
"deprecated": "no longer maintained"
|
||||||
|
},
|
||||||
"node_modules/text-segmentation": {
|
"node_modules/text-segmentation": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"react-native-linear-gradient": "^2.8.3",
|
"react-native-linear-gradient": "^2.8.3",
|
||||||
"react-native-permissions": "^5.2.1",
|
"react-native-permissions": "^5.2.1",
|
||||||
"react-native-qrcode-scanner": "^1.5.5",
|
"react-native-qrcode-scanner": "^1.5.5",
|
||||||
|
"react-native-qrcode-svg": "^6.3.12",
|
||||||
"react-native-reanimated": "^3.16.1",
|
"react-native-reanimated": "^3.16.1",
|
||||||
"react-native-safe-area-context": "^4.14.0",
|
"react-native-safe-area-context": "^4.14.0",
|
||||||
"react-native-screens": "^3.35.0",
|
"react-native-screens": "^3.35.0",
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
|
||||||
import { HomeStackParamList } from './types';
|
import { HomeStackParamList } from './types';
|
||||||
import TestBule from '../views/device/test_bule';
|
import TestBule from '../views/device/test_bule';
|
||||||
import ShareDetailScreen from '../views/device/KeyDetail';
|
import ShareDetailScreen from '../views/device/KeyDetail';
|
||||||
|
import ExpiredKeysScreen from '../views/device/ExpiredKeysScreen';
|
||||||
const Stack = createStackNavigator<HomeStackParamList>();
|
const Stack = createStackNavigator<HomeStackParamList>();
|
||||||
|
|
||||||
const createScreenOptions = (title: string): StackNavigationOptions => {
|
const createScreenOptions = (title: string): StackNavigationOptions => {
|
||||||
|
@ -84,6 +85,13 @@ export default function HomeStackNavigator({ navigation, route }: Props) {
|
||||||
component={SnBind}
|
component={SnBind}
|
||||||
options={createScreenOptions('手动绑车')}
|
options={createScreenOptions('手动绑车')}
|
||||||
/> */}
|
/> */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="ExpiredKeysScreen"
|
||||||
|
component={ExpiredKeysScreen}
|
||||||
|
options={{
|
||||||
|
headerShown: false,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="ConfirmBind"
|
name="ConfirmBind"
|
||||||
component={ConfirmBind}
|
component={ConfirmBind}
|
||||||
|
|
|
@ -29,6 +29,7 @@ export type HomeStackParamList = {
|
||||||
ShareQrcode: undefined;
|
ShareQrcode: undefined;
|
||||||
TestBule: undefined;
|
TestBule: undefined;
|
||||||
ShareDetailScreen: undefined;
|
ShareDetailScreen: undefined;
|
||||||
|
ExpiredKeysScreen: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 导航属性类型
|
// 导航属性类型
|
||||||
|
|
|
@ -108,4 +108,7 @@ export const apiService = {
|
||||||
lock: (sn: string) => api.post(`/appVerify/admin/lock?sn=${sn}`),
|
lock: (sn: string) => api.post(`/appVerify/admin/lock?sn=${sn}`),
|
||||||
getKeyListByOwnerId: () => api.get('/appVerify/getKeyListByOwnerId'),
|
getKeyListByOwnerId: () => api.get('/appVerify/getKeyListByOwnerId'),
|
||||||
addKey: (data: any) => api.post('/appVerify/addKey', data),
|
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'),
|
||||||
};
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState, useCallback } from 'react';
|
||||||
import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native';
|
import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
import { useNavigation ,useFocusEffect} from '@react-navigation/native';
|
||||||
import { apiService } from '../../utils/api';
|
import { apiService } from '../../utils/api';
|
||||||
import { rpx } from '../../utils/rpx';
|
import { rpx } from '../../utils/rpx';
|
||||||
interface KeyItem {
|
interface KeyItem {
|
||||||
|
@ -18,7 +18,7 @@ const DeviceShare = () => {
|
||||||
|
|
||||||
const getKeyList = async () => {
|
const getKeyList = async () => {
|
||||||
const response = await apiService.getKeyListByOwnerId();
|
const response = await apiService.getKeyListByOwnerId();
|
||||||
|
// console.log(response);
|
||||||
if (response.code == 200) {
|
if (response.code == 200) {
|
||||||
setKeyList(response.data);
|
setKeyList(response.data);
|
||||||
|
|
||||||
|
@ -59,9 +59,11 @@ const DeviceShare = () => {
|
||||||
return '未知状态';
|
return '未知状态';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useFocusEffect(
|
||||||
|
useCallback(() => {
|
||||||
getKeyList();
|
getKeyList();
|
||||||
}, []);
|
}, [])
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
|
@ -121,7 +123,9 @@ const DeviceShare = () => {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
<TouchableOpacity onPress={() => {
|
||||||
|
navigation.navigate('ExpiredKeysScreen' as never );
|
||||||
|
}}>
|
||||||
<View style={styles.shareTip}>
|
<View style={styles.shareTip}>
|
||||||
<Text style={styles.shareBtnTxt}>查看已失效共享</Text>
|
<Text style={styles.shareBtnTxt}>查看已失效共享</Text>
|
||||||
<Image
|
<Image
|
||||||
|
@ -129,6 +133,7 @@ const DeviceShare = () => {
|
||||||
style={styles.lasttimeImg}
|
style={styles.lasttimeImg}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
106
src/views/device/ExpiredKeysScreen.tsx
Normal file
106
src/views/device/ExpiredKeysScreen.tsx
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { ImageBackground, FlatList, StyleSheet, Image } from 'react-native';
|
||||||
|
import { TopNavigation, TopNavigationAction, Icon, Card, Layout, Text } from '@ui-kitten/components';
|
||||||
|
import { rpx } from '../../utils/rpx';
|
||||||
|
import { apiService } from '../../utils/api';
|
||||||
|
|
||||||
|
const BackIcon = (props) => (
|
||||||
|
<Icon {...props} name='arrow-back' />
|
||||||
|
);
|
||||||
|
|
||||||
|
const ExpiredKeysScreen = ({ navigation }) => {
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
|
||||||
|
const navigateBack = () => {
|
||||||
|
navigation.goBack();
|
||||||
|
};
|
||||||
|
|
||||||
|
const BackAction = () => (
|
||||||
|
<TopNavigationAction icon={BackIcon} onPress={navigateBack}/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const getExpiredKeys = async () => {
|
||||||
|
const res = await apiService.getExpiredKeys();
|
||||||
|
setData(res || []);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderItem = ({ item }) => (
|
||||||
|
<Card style={styles.card}>
|
||||||
|
<Text style={styles.name}>{item.name} {item.number}</Text>
|
||||||
|
<Text style={styles.date}>失效时间:{item.date}</Text>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getExpiredKeys();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImageBackground
|
||||||
|
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uYRs7Cv2Pbp95w3KjGO3' }}
|
||||||
|
style={styles.background}
|
||||||
|
>
|
||||||
|
<TopNavigation
|
||||||
|
title='已失效分享'
|
||||||
|
alignment='center'
|
||||||
|
accessoryLeft={BackAction}
|
||||||
|
/>
|
||||||
|
{data.length > 0 ? (
|
||||||
|
<FlatList
|
||||||
|
data={data}
|
||||||
|
renderItem={renderItem}
|
||||||
|
keyExtractor={item => item.id}
|
||||||
|
contentContainerStyle={styles.list}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Layout style={styles.emptyContainer}>
|
||||||
|
{/* <Image
|
||||||
|
source={{ uri: 'https://example.com/empty-image.png' }} // 替换为你的缺省图URL
|
||||||
|
style={styles.emptyImage}
|
||||||
|
/> */}
|
||||||
|
<Text category='h5' style={styles.emptyText}>暂无失效分享</Text>
|
||||||
|
</Layout>
|
||||||
|
)}
|
||||||
|
</ImageBackground>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
background: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
padding: rpx(30),
|
||||||
|
},
|
||||||
|
card: {
|
||||||
|
marginVertical: rpx(20),
|
||||||
|
padding: rpx(30),
|
||||||
|
borderRadius: rpx(20),
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
fontSize: rpx(36),
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#3D3D3D',
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
fontSize: rpx(28),
|
||||||
|
color: '#808080',
|
||||||
|
marginTop: rpx(10),
|
||||||
|
},
|
||||||
|
emptyContainer: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: rpx(20),
|
||||||
|
},
|
||||||
|
emptyImage: {
|
||||||
|
width: rpx(200),
|
||||||
|
height: rpx(200),
|
||||||
|
marginBottom: rpx(20),
|
||||||
|
},
|
||||||
|
emptyText: {
|
||||||
|
color: '#808080',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ExpiredKeysScreen;
|
|
@ -1,16 +1,19 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, View, Image,TouchableOpacity } from 'react-native';
|
import { StyleSheet, View, Image, TouchableOpacity, Modal } from 'react-native';
|
||||||
import { Layout, Text, Avatar, Button, Divider, TopNavigation, TopNavigationAction, Icon } from '@ui-kitten/components';
|
import { Layout, Text, Avatar, Button, TopNavigation, TopNavigationAction, Icon, Card } from '@ui-kitten/components';
|
||||||
import { rpx } from '../../utils/rpx';
|
import { rpx } from '../../utils/rpx';
|
||||||
import { useNavigation,useRoute } from '@react-navigation/native';
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||||
|
import { apiService } from '../../utils/api';
|
||||||
|
|
||||||
interface KeyItem {
|
interface KeyItem {
|
||||||
id: string;
|
keyId: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
shareUserName: string;
|
shareUserName: string;
|
||||||
sharePhone: string;
|
sharePhone: string;
|
||||||
status: string;
|
status: string;
|
||||||
expirationTime: string;
|
expirationTime: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BackIcon = (props) => (
|
const BackIcon = (props) => (
|
||||||
<Icon
|
<Icon
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -20,29 +23,81 @@ const BackIcon = (props) => (
|
||||||
|
|
||||||
const KeyDetail = () => {
|
const KeyDetail = () => {
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const keyItem = route.params?.keyItem as KeyItem;
|
const keyItem = route.params?.keyItem as KeyItem;
|
||||||
|
const [visible, setVisible] = React.useState(false);
|
||||||
|
const [showTimeModal, setShowTimeModal] = React.useState(false);
|
||||||
|
const [selectedTime, setSelectedTime] = React.useState('');
|
||||||
|
const timeOptions = ['1天', '7天', '30天', '永久'];
|
||||||
|
|
||||||
|
const showDeleteModal = () => {
|
||||||
|
setVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const hideDeleteModal = () => {
|
||||||
|
setVisible(false);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
// 这里添加删除逻辑
|
||||||
|
hideDeleteModal();
|
||||||
|
apiService.deleteKey(keyItem.keyId).then(res => {
|
||||||
|
console.log(res,'resresres');
|
||||||
|
if (res.code == 200) {
|
||||||
|
navigation.goBack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const navigateBack = () => {
|
const navigateBack = () => {
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTimeSelect = (time: string) => {
|
||||||
|
setSelectedTime(time);
|
||||||
|
setShowTimeModal(false);
|
||||||
|
// 这里添加更新有效期的逻辑
|
||||||
|
};
|
||||||
|
|
||||||
const BackAction = () => (
|
const BackAction = () => (
|
||||||
<TopNavigationAction
|
<TopNavigationAction
|
||||||
icon={BackIcon}
|
icon={BackIcon}
|
||||||
onPress={navigateBack}
|
onPress={navigateBack}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
const calculateRemainingTime = (expirationTime: string): string => {
|
||||||
|
const now = new Date();
|
||||||
|
const expiration = new Date(expirationTime);
|
||||||
|
const diffTime = expiration.getTime() - now.getTime();
|
||||||
|
|
||||||
const RightIcon = (props) => (
|
// 如果已过期
|
||||||
|
if (diffTime <= 0) {
|
||||||
|
return '已过期';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算剩余天数、小时、分钟
|
||||||
|
const days = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
||||||
|
const hours = Math.floor((diffTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
|
const minutes = Math.floor((diffTime % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
|
||||||
|
if (days > 0) {
|
||||||
|
return `${days}天${hours}小时`;
|
||||||
|
} else if (hours > 0) {
|
||||||
|
return `${hours}小时${minutes}分钟`;
|
||||||
|
} else {
|
||||||
|
return `${minutes}分钟`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const RightIcon = (props: any) => (
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uGq4yJlU1ZZRkwiJ8Y74' }}
|
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uGq4yJlU1ZZRkwiJ8Y74' }}
|
||||||
style={styles.arrowIcon}
|
style={styles.arrowIcon}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
const toQrCode = () => {
|
||||||
|
navigation.navigate('ShareQrcode', { QrId: keyItem.keyId });
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Layout style={styles.container}>
|
<Layout style={styles.container}>
|
||||||
<TopNavigation
|
<TopNavigation
|
||||||
|
@ -56,50 +111,131 @@ const KeyDetail = () => {
|
||||||
<Avatar
|
<Avatar
|
||||||
style={styles.avatar}
|
style={styles.avatar}
|
||||||
size="giant"
|
size="giant"
|
||||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
|
source={{ uri: keyItem.avatarUrl || 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.name}>小黄鸭</Text>
|
<Text style={styles.name}>{keyItem.shareUserName}</Text>
|
||||||
<Text style={styles.phone}>13569254567</Text>
|
<Text style={styles.phone}>{keyItem.sharePhone}</Text>
|
||||||
<Text style={styles.expireTime}>剩余有效期:23小时54分钟</Text>
|
<Text style={styles.expireTime}>剩余有效期:{calculateRemainingTime(keyItem.expirationTime)}</Text>
|
||||||
<TouchableOpacity style={styles.eidtBtn}>
|
<TouchableOpacity style={styles.eidtBtn} onPress={() => setShowTimeModal(true)}>
|
||||||
<Text style={styles.expireTime}>修改钥匙有效期</Text>
|
<View style={styles.editBtnContent}>
|
||||||
|
<Text style={styles.editBtnText}>修改钥匙有效期</Text>
|
||||||
<Icon name='arrow-ios-forward-outline' style={styles.arrowIcon} />
|
<Icon name='arrow-ios-forward-outline' style={styles.arrowIcon} />
|
||||||
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<TouchableOpacity style={styles.deleteBtn}>
|
<TouchableOpacity style={styles.deleteBtn} onPress={showDeleteModal}>
|
||||||
<Text style={styles.deleteText}>删除共享人</Text>
|
<Text style={styles.deleteText}>删除共享人</Text>
|
||||||
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<Layout style={styles.actionContainer}>
|
<Layout style={styles.actionContainer}>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
appearance='ghost'
|
appearance='ghost'
|
||||||
style={styles.actionButton}
|
style={styles.actionButton}
|
||||||
accessoryRight={RightIcon}
|
accessoryRight={RightIcon}
|
||||||
|
onPress={toQrCode}
|
||||||
>
|
>
|
||||||
<Text style={styles.buttonText}>查看二维码</Text>
|
{evaProps => <Text {...evaProps} style={styles.buttonText}>查看二维码</Text>}
|
||||||
</Button>
|
</Button>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
{/* 删除确认弹窗 */}
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
transparent={true}
|
||||||
|
animationType="fade"
|
||||||
|
onRequestClose={hideDeleteModal}>
|
||||||
|
<View style={styles.modalOverlay}>
|
||||||
|
<View style={styles.modalCard}>
|
||||||
|
<Text style={styles.modalText}>删除后,被共享人将无法再操控 您的车辆,确定删除吗?</Text>
|
||||||
|
<View style={styles.modalButtons}>
|
||||||
|
<Button
|
||||||
|
style={styles.modalButton}
|
||||||
|
status='basic'
|
||||||
|
size='large'
|
||||||
|
onPress={hideDeleteModal}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={styles.modalButton}
|
||||||
|
status='danger'
|
||||||
|
size='large'
|
||||||
|
onPress={handleDelete}>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{/* 时间选择弹窗 */}
|
||||||
|
<Modal
|
||||||
|
visible={showTimeModal}
|
||||||
|
transparent={true}
|
||||||
|
animationType="slide"
|
||||||
|
onRequestClose={() => setShowTimeModal(false)}>
|
||||||
|
<View style={styles.modalContainer}>
|
||||||
|
<View style={styles.modalContent}>
|
||||||
|
<View style={styles.modalHeader}>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.headerButton}
|
||||||
|
onPress={() => setShowTimeModal(false)}
|
||||||
|
>
|
||||||
|
<Text style={styles.cancelText}>取消</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<Text style={styles.modalTitle}>选择有效期</Text>
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.headerButton}
|
||||||
|
onPress={() => setShowTimeModal(false)}
|
||||||
|
>
|
||||||
|
<Text style={styles.confirmText}>确定</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
<View style={styles.optionsContainer}>
|
||||||
|
{timeOptions.map((option, index) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={index}
|
||||||
|
style={[
|
||||||
|
styles.optionItem,
|
||||||
|
selectedTime === option && styles.selectedItemBg
|
||||||
|
]}
|
||||||
|
onPress={() => handleTimeSelect(option)}
|
||||||
|
>
|
||||||
|
<Text style={[
|
||||||
|
styles.optionText,
|
||||||
|
selectedTime === option && styles.selectedOption
|
||||||
|
]}>
|
||||||
|
{option}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Modal>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
width: rpx(750),
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#F5F5F5',
|
backgroundColor: '#F3FCFF',
|
||||||
},
|
},
|
||||||
topNav: {
|
topNav: {
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#F3FCFF',
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: '#E8E8E8',
|
borderBottomColor: '#fff',
|
||||||
},
|
},
|
||||||
header: {
|
header: {
|
||||||
|
marginHorizontal: 'auto',
|
||||||
|
width: rpx(700),
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
paddingVertical: rpx(40),
|
paddingVertical: rpx(40),
|
||||||
marginTop: rpx(20),
|
marginTop: rpx(20),
|
||||||
|
alignSelf: 'center',
|
||||||
|
borderRadius: rpx(16),
|
||||||
},
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
width: rpx(188),
|
width: rpx(188),
|
||||||
|
@ -112,11 +248,10 @@ const styles = StyleSheet.create({
|
||||||
color: '#333',
|
color: '#333',
|
||||||
marginBottom: rpx(8),
|
marginBottom: rpx(8),
|
||||||
},
|
},
|
||||||
deleteBtn:{
|
deleteBtn: {
|
||||||
marginTop: rpx(56),
|
marginTop: rpx(56),
|
||||||
|
|
||||||
},
|
},
|
||||||
deleteText:{
|
deleteText: {
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
fontSize: rpx(40),
|
fontSize: rpx(40),
|
||||||
color: '#FF8282',
|
color: '#FF8282',
|
||||||
|
@ -125,16 +260,21 @@ const styles = StyleSheet.create({
|
||||||
width: rpx(592),
|
width: rpx(592),
|
||||||
marginTop: rpx(20),
|
marginTop: rpx(20),
|
||||||
height: rpx(108),
|
height: rpx(108),
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: rpx(16),
|
|
||||||
backgroundColor: '#EEEFF9',
|
backgroundColor: '#EEEFF9',
|
||||||
borderRadius: rpx(16),
|
borderRadius: rpx(16),
|
||||||
},
|
},
|
||||||
|
editBtnContent: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingHorizontal: rpx(16),
|
||||||
|
},
|
||||||
|
editBtnText: {
|
||||||
|
fontSize: rpx(36),
|
||||||
|
color: '#808080',
|
||||||
|
},
|
||||||
phone: {
|
phone: {
|
||||||
|
|
||||||
fontSize: rpx(36),
|
fontSize: rpx(36),
|
||||||
color: '#808080',
|
color: '#808080',
|
||||||
marginBottom: rpx(8),
|
marginBottom: rpx(8),
|
||||||
|
@ -146,6 +286,8 @@ const styles = StyleSheet.create({
|
||||||
color: '#808080',
|
color: '#808080',
|
||||||
},
|
},
|
||||||
actionContainer: {
|
actionContainer: {
|
||||||
|
marginHorizontal: 'auto',
|
||||||
|
width: rpx(700),
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
marginTop: rpx(20),
|
marginTop: rpx(20),
|
||||||
},
|
},
|
||||||
|
@ -157,8 +299,8 @@ const styles = StyleSheet.create({
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
fontSize: rpx(28),
|
fontSize: rpx(36),
|
||||||
color: '#333',
|
color: '#3D3D3D',
|
||||||
},
|
},
|
||||||
arrowIcon: {
|
arrowIcon: {
|
||||||
width: rpx(38),
|
width: rpx(38),
|
||||||
|
@ -170,10 +312,98 @@ const styles = StyleSheet.create({
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
divider: {
|
divider: {
|
||||||
backgroundColor: '#E8E8E8',
|
backgroundColor: '#E8E8E8',
|
||||||
},
|
},
|
||||||
|
modalOverlay: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
},
|
||||||
|
modalCard: {
|
||||||
|
width: rpx(600),
|
||||||
|
borderRadius: rpx(20),
|
||||||
|
padding: rpx(32),
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
modalText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
marginBottom: rpx(40),
|
||||||
|
fontSize: rpx(36),
|
||||||
|
fontWeight: '500',
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
modalButtons: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginTop: rpx(20),
|
||||||
|
},
|
||||||
|
modalButton: {
|
||||||
|
flex: 1,
|
||||||
|
marginHorizontal: rpx(15),
|
||||||
|
borderRadius: rpx(16),
|
||||||
|
height: rpx(88),
|
||||||
|
},
|
||||||
|
modalContainer: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
},
|
||||||
|
modalContent: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
borderTopLeftRadius: rpx(20),
|
||||||
|
borderTopRightRadius: rpx(20),
|
||||||
|
paddingBottom: rpx(30),
|
||||||
|
},
|
||||||
|
modalHeader: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
height: rpx(100),
|
||||||
|
borderBottomWidth: 1,
|
||||||
|
borderBottomColor: '#eee',
|
||||||
|
paddingHorizontal: rpx(30),
|
||||||
|
},
|
||||||
|
headerButton: {
|
||||||
|
padding: rpx(20),
|
||||||
|
},
|
||||||
|
modalTitle: {
|
||||||
|
fontSize: rpx(32),
|
||||||
|
fontWeight: '500',
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
cancelText: {
|
||||||
|
fontSize: rpx(32),
|
||||||
|
color: '#666',
|
||||||
|
},
|
||||||
|
confirmText: {
|
||||||
|
fontSize: rpx(32),
|
||||||
|
color: '#4297F3',
|
||||||
|
},
|
||||||
|
optionsContainer: {
|
||||||
|
paddingHorizontal: rpx(30),
|
||||||
|
paddingTop: rpx(20),
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
optionItem: {
|
||||||
|
height: rpx(100),
|
||||||
|
width: rpx(600),
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
borderRadius: rpx(16),
|
||||||
|
marginBottom: rpx(20),
|
||||||
|
},
|
||||||
|
optionText: {
|
||||||
|
fontSize: rpx(32),
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
selectedItemBg: {
|
||||||
|
backgroundColor: '#F0F7FF',
|
||||||
|
},
|
||||||
|
selectedOption: {
|
||||||
|
color: '#4297F3',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default KeyDetail;
|
export default KeyDetail;
|
|
@ -1,101 +1,118 @@
|
||||||
import React from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { View, StyleSheet, Image, ImageBackground, TouchableOpacity, Text, Alert, Platform, NativeModules } from 'react-native';
|
import { View, StyleSheet, Image, ImageBackground, TouchableOpacity, Text, Alert, Platform, NativeModules } from 'react-native';
|
||||||
import { rpx } from '../../utils/rpx';
|
import { rpx } from '../../utils/rpx';
|
||||||
import { RouteProp, useRoute } from '@react-navigation/native';
|
import { RouteProp, useRoute } from '@react-navigation/native';
|
||||||
import RNFS from 'react-native-fs';
|
import RNFS from 'react-native-fs';
|
||||||
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
|
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
|
||||||
|
import { Spinner, Layout } from '@ui-kitten/components';
|
||||||
|
import QRCode from 'react-native-qrcode-svg'; // 新增的库
|
||||||
|
|
||||||
const ShareQrcode = () => {
|
const ShareQrcode = () => {
|
||||||
const route = useRoute<RouteProp<RootStackParamList, 'ShareQrcode'>>();
|
const route = useRoute<RouteProp<RootStackParamList, 'ShareQrcode'>>();
|
||||||
const { QrId } = route.params;
|
const { QrId } = route.params;
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [qrCodeRef, setQrCodeRef] = useState(null); // 用于保存二维码的引用
|
||||||
|
|
||||||
const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${rpx(400)}x${rpx(400)}&data=https://your-domain.com/share?id=${QrId}`;
|
useEffect(() => {
|
||||||
console.log(qrCodeUrl);
|
const timer = setTimeout(() => {
|
||||||
|
setLoading(false);
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// const qrCodeUrl = `https://lxnapi.ccttiot.com/bike/img/static/upCrcuiBaoZrd9ZRZayj`
|
|
||||||
// https://lxnapi.ccttiot.com/bike/img/static/upCrcuiBaoZrd9ZRZayj
|
|
||||||
const saveToGallery = async () => {
|
const saveToGallery = async () => {
|
||||||
try {
|
try {
|
||||||
// 检查写入权限
|
// 检查并请求权限
|
||||||
const writePermission = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
|
let permissionResult;
|
||||||
const readPermission = await request(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE);
|
if (Platform.OS === 'android') {
|
||||||
|
if (Platform.Version >= 33) {
|
||||||
if (writePermission === RESULTS.GRANTED && readPermission === RESULTS.GRANTED) {
|
permissionResult = await request(PERMISSIONS.ANDROID.READ_MEDIA_IMAGES);
|
||||||
try {
|
} else {
|
||||||
const directoryPath = `${RNFS.DownloadDirectoryPath}`;
|
permissionResult = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
|
||||||
const fileName = `qrcode_${Date.now()}.jpg`;
|
|
||||||
let downloadDest = `${directoryPath}/${fileName}`;
|
|
||||||
|
|
||||||
// 检查目录是否存在
|
|
||||||
const exists = await RNFS.exists(directoryPath);
|
|
||||||
console.log('目录是否存在:', exists);
|
|
||||||
|
|
||||||
if (!exists) {
|
|
||||||
console.log('尝试创建目录:', directoryPath);
|
|
||||||
try {
|
|
||||||
await RNFS.mkdir(directoryPath);
|
|
||||||
} catch (mkdirError) {
|
|
||||||
console.error('创建目录失败:', mkdirError);
|
|
||||||
// 如果创建目录失败,尝试直接使用根目录
|
|
||||||
downloadDest = `${RNFS.ExternalStorageDirectoryPath}/${fileName}`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('开始下载文件到:', downloadDest);
|
if (permissionResult === RESULTS.GRANTED || Platform.OS === 'ios') {
|
||||||
const options = {
|
qrCodeRef.toDataURL(async (data) => {
|
||||||
fromUrl: qrCodeUrl,
|
try {
|
||||||
toFile: downloadDest,
|
// 使用 ExternalDirectoryPath,这个目录在大多数 Android 设备上都可以访问
|
||||||
};
|
const basePath = Platform.OS === 'android'
|
||||||
|
? `${RNFS.ExternalDirectoryPath}`
|
||||||
|
: RNFS.DocumentDirectoryPath;
|
||||||
|
|
||||||
const response = await RNFS.downloadFile(options).promise;
|
const fileName = `qrcode_${Date.now()}.png`;
|
||||||
console.log('下载响应:', response);
|
const filePath = `${basePath}/${fileName}`;
|
||||||
|
|
||||||
if (response.statusCode === 200) {
|
// 直接写入文件
|
||||||
const fileExists = await RNFS.exists(downloadDest);
|
await RNFS.writeFile(filePath, data, 'base64');
|
||||||
if (fileExists) {
|
|
||||||
// 使用原生模块刷新媒体库
|
if (Platform.OS === 'android') {
|
||||||
NativeModules.MediaScanner.scanFile(downloadDest, 'image/jpeg', (err) => {
|
// 使用 CameraRoll 保存到相册
|
||||||
|
const { CameraRoll } = NativeModules;
|
||||||
|
if (CameraRoll && CameraRoll.saveToCameraRoll) {
|
||||||
|
await CameraRoll.saveToCameraRoll(`file://${filePath}`, 'photo');
|
||||||
|
// 删除临时文件
|
||||||
|
await RNFS.unlink(filePath);
|
||||||
|
Alert.alert('成功', '二维码已保存到相册');
|
||||||
|
} else {
|
||||||
|
// 如果 CameraRoll 模块不可用,尝试使用 MediaScanner
|
||||||
|
NativeModules.MediaScanner.scanFile(filePath, 'image/png', (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error('媒体扫描错误:', err);
|
console.error('媒体扫描错误:', err);
|
||||||
Alert.alert('错误', '无法刷新媒体库');
|
Alert.alert('提示', '二维码已保存,但可能需要手动刷新相册');
|
||||||
} else {
|
} else {
|
||||||
Alert.alert('成功', '二维码已保存到相册');
|
Alert.alert('成功', '二维码已保存到相册');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
throw new Error('文件未能成功创建');
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Alert.alert('错误', '下载失败,请检查网络连接');
|
// iOS 处理
|
||||||
|
Alert.alert('成功', '二维码已保存');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('文件操作详细错误:', JSON.stringify(err));
|
console.error('文件操作错误:', err);
|
||||||
Alert.alert('错误', '保存失败,无法访问存储空间');
|
Alert.alert('错误', '保存失败,请检查存储权限');
|
||||||
}
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
Alert.alert('权限不足', '请在设置中授予存储权限');
|
Alert.alert('提示', '需要存储权限才能保存二维码,请在设置中授予权限');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('整体错误:', error);
|
console.error('保存过程错误:', error);
|
||||||
Alert.alert('错误', '保存失败,请重试');
|
Alert.alert('错误', '保存失败,请重试');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Layout style={styles.loadingContainer}>
|
||||||
|
<Spinner size='giant' />
|
||||||
|
<Text style={styles.loadingText}>加载中...</Text>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: `https://lxnapi.ccttiot.com/bike/img/static/uvDKCdnlkcshHOrXvPUq` }}
|
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uvDKCdnlkcshHOrXvPUq' }}
|
||||||
style={styles.backimg}
|
style={styles.backimg}
|
||||||
/>
|
/>
|
||||||
<ImageBackground
|
<ImageBackground
|
||||||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u8yqVl9y6fcU3fTDDTpK' }}
|
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u8yqVl9y6fcU3fTDDTpK' }}
|
||||||
style={styles.qrBack}
|
style={styles.qrBack}
|
||||||
>
|
>
|
||||||
<View style={styles.qrContainer}>
|
<Layout style={styles.qrContainer}>
|
||||||
<Image
|
<QRCode
|
||||||
source={{ uri: qrCodeUrl }}
|
value={`https://testlu.chuangtewl.com/prod-api?keyId=${QrId}`}
|
||||||
style={styles.qrCode}
|
size={rpx(438)}
|
||||||
|
getRef={(c) => setQrCodeRef(c)} // 保存二维码的引用
|
||||||
|
logo={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u3giTY4VkWYpnGWRuFHF' }} // 添加 logo
|
||||||
|
logoSize={rpx(100)} // 设置 logo 大小
|
||||||
|
logoBackgroundColor='transparent' // 设置 logo 背景透明
|
||||||
/>
|
/>
|
||||||
</View>
|
</Layout>
|
||||||
</ImageBackground>
|
</ImageBackground>
|
||||||
<Image source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uC6GRh4c76KgsbBYME5l' }} style={styles.tipImg} />
|
<Image source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uC6GRh4c76KgsbBYME5l' }} style={styles.tipImg} />
|
||||||
<TouchableOpacity style={styles.btn} onPress={saveToGallery}>
|
<TouchableOpacity style={styles.btn} onPress={saveToGallery}>
|
||||||
|
@ -105,14 +122,22 @@ const ShareQrcode = () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ... 其余代码保持不变 ...
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: '#F3FCFF',
|
backgroundColor: '#F3FCFF',
|
||||||
},
|
},
|
||||||
|
loadingContainer: {
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
loadingText: {
|
||||||
|
marginTop: 10,
|
||||||
|
fontSize: 16,
|
||||||
|
color: '#888',
|
||||||
|
},
|
||||||
btn: {
|
btn: {
|
||||||
marginTop: rpx(36),
|
marginTop: rpx(36),
|
||||||
width: rpx(614),
|
width: rpx(614),
|
||||||
|
@ -139,7 +164,6 @@ const styles = StyleSheet.create({
|
||||||
qrContainer: {
|
qrContainer: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
// marginTop: rpx(-50),
|
|
||||||
},
|
},
|
||||||
qrBack: {
|
qrBack: {
|
||||||
marginTop: rpx(-20),
|
marginTop: rpx(-20),
|
||||||
|
|
22
yarn.lock
22
yarn.lock
|
@ -7681,7 +7681,7 @@ prompts@^2.0.1, prompts@^2.3.2, prompts@^2.4.2:
|
||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.5"
|
sisteransi "^1.0.5"
|
||||||
|
|
||||||
prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
|
prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.0, prop-types@^15.8.1:
|
||||||
version "15.8.1"
|
version "15.8.1"
|
||||||
resolved "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz"
|
resolved "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz"
|
||||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||||
|
@ -7718,7 +7718,7 @@ qrcode-terminal@0.11.0:
|
||||||
resolved "https://registry.npmmirror.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz"
|
resolved "https://registry.npmmirror.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz"
|
||||||
integrity sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==
|
integrity sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==
|
||||||
|
|
||||||
qrcode@^1.5.4:
|
qrcode@^1.5.1, qrcode@^1.5.4:
|
||||||
version "1.5.4"
|
version "1.5.4"
|
||||||
resolved "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz"
|
resolved "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz"
|
||||||
integrity sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==
|
integrity sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==
|
||||||
|
@ -7876,6 +7876,15 @@ react-native-qrcode-scanner@^1.5.5:
|
||||||
prop-types "^15.5.10"
|
prop-types "^15.5.10"
|
||||||
react-native-permissions "^2.0.2"
|
react-native-permissions "^2.0.2"
|
||||||
|
|
||||||
|
react-native-qrcode-svg@^6.3.12:
|
||||||
|
version "6.3.12"
|
||||||
|
resolved "https://registry.npmmirror.com/react-native-qrcode-svg/-/react-native-qrcode-svg-6.3.12.tgz"
|
||||||
|
integrity sha512-7Bx23ZdFNJJdVXyW9BJmFWdI5kccjnpotzmL3exkV0irUKTmj51jesxpn5sqtgVdYFE4IUVoGzdS+8qg6Ua9BA==
|
||||||
|
dependencies:
|
||||||
|
prop-types "^15.8.0"
|
||||||
|
qrcode "^1.5.1"
|
||||||
|
text-encoding "^0.7.0"
|
||||||
|
|
||||||
react-native-reanimated@^3.16.1:
|
react-native-reanimated@^3.16.1:
|
||||||
version "3.16.3"
|
version "3.16.3"
|
||||||
resolved "https://registry.npmmirror.com/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz"
|
resolved "https://registry.npmmirror.com/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz"
|
||||||
|
@ -7911,7 +7920,7 @@ react-native-share@^11.0.4:
|
||||||
resolved "https://registry.npmmirror.com/react-native-share/-/react-native-share-11.1.0.tgz"
|
resolved "https://registry.npmmirror.com/react-native-share/-/react-native-share-11.1.0.tgz"
|
||||||
integrity sha512-kcpBR90d5//xc8H84HnX6YFeOk4A34mtHz4UEpb7Twbu049KafJwsp4KVVr/SrJwy8W0/Rbe880En9Hq0REamw==
|
integrity sha512-kcpBR90d5//xc8H84HnX6YFeOk4A34mtHz4UEpb7Twbu049KafJwsp4KVVr/SrJwy8W0/Rbe880En9Hq0REamw==
|
||||||
|
|
||||||
react-native-svg@*, react-native-svg@^15.10.1, react-native-svg@^9.4.0:
|
react-native-svg@*, react-native-svg@^15.10.1, react-native-svg@^9.4.0, react-native-svg@>=13.2.0:
|
||||||
version "15.10.1"
|
version "15.10.1"
|
||||||
resolved "https://registry.npmmirror.com/react-native-svg/-/react-native-svg-15.10.1.tgz"
|
resolved "https://registry.npmmirror.com/react-native-svg/-/react-native-svg-15.10.1.tgz"
|
||||||
integrity sha512-Hqz/doQciVFK/Df2v+wsW96oY5jxlta7rZ31KQYo78dlgvAHEaGr6paEOAMvlIruw7EHNQ0Vc1ZmJPJF2kfIPQ==
|
integrity sha512-Hqz/doQciVFK/Df2v+wsW96oY5jxlta7rZ31KQYo78dlgvAHEaGr6paEOAMvlIruw7EHNQ0Vc1ZmJPJF2kfIPQ==
|
||||||
|
@ -7939,7 +7948,7 @@ react-native-wheel-picker-android@^2.0.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
moment "^2.22.0"
|
moment "^2.22.0"
|
||||||
|
|
||||||
react-native@*, "react-native@^0.0.0-0 || >=0.60 <1.0", "react-native@^0.0.0-0 || >=0.65 <1.0", react-native@^0.74.6, react-native@>=0.60.0, react-native@>=0.70.0:
|
react-native@*, "react-native@^0.0.0-0 || >=0.60 <1.0", "react-native@^0.0.0-0 || >=0.65 <1.0", react-native@^0.74.6, react-native@>=0.60.0, react-native@>=0.63.4, react-native@>=0.70.0:
|
||||||
version "0.74.6"
|
version "0.74.6"
|
||||||
resolved "https://registry.npmmirror.com/react-native/-/react-native-0.74.6.tgz"
|
resolved "https://registry.npmmirror.com/react-native/-/react-native-0.74.6.tgz"
|
||||||
integrity sha512-TZ8uLf+dH+nO5nFwjhMd4PqtraeNT5cXQ0ySAhq7qqbTBgalxO3UklsLFW3cTSedC+eLw6J3P3H62e3/MjpWNw==
|
integrity sha512-TZ8uLf+dH+nO5nFwjhMd4PqtraeNT5cXQ0ySAhq7qqbTBgalxO3UklsLFW3cTSedC+eLw6J3P3H62e3/MjpWNw==
|
||||||
|
@ -9009,6 +9018,11 @@ test-exclude@^6.0.0:
|
||||||
glob "^7.1.4"
|
glob "^7.1.4"
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
|
|
||||||
|
text-encoding@^0.7.0:
|
||||||
|
version "0.7.0"
|
||||||
|
resolved "https://registry.npmmirror.com/text-encoding/-/text-encoding-0.7.0.tgz"
|
||||||
|
integrity sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==
|
||||||
|
|
||||||
text-segmentation@^1.0.3:
|
text-segmentation@^1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz"
|
resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user