From 05872f47d7fa4a78e3007d1b8215205cc4664af4 Mon Sep 17 00:00:00 2001 From: tx <2622874537@qq.com> Date: Thu, 26 Dec 2024 14:12:13 +0800 Subject: [PATCH] =?UTF-8?q?=E9=92=A5=E5=8C=99=E5=85=B1=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 2 + package-lock.json | 22 + package.json | 1 + src/navigation/HomeStack.tsx | 8 + src/navigation/types.tsx | 1 + src/utils/api.ts | 3 + src/views/device/DeviceShare.tsx | 27 +- src/views/device/ExpiredKeysScreen.tsx | 106 +++++ src/views/device/KeyDetail.tsx | 536 ++++++++++++++++------- src/views/device/shareQrcode.tsx | 170 ++++--- yarn.lock | 22 +- 11 files changed, 657 insertions(+), 241 deletions(-) create mode 100644 src/views/device/ExpiredKeysScreen.tsx diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index b78688e..a28bc4d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -19,6 +19,8 @@ + + =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": { "version": "3.16.3", "resolved": "https://registry.npmmirror.com/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz", @@ -16440,6 +16456,12 @@ "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": { "version": "1.0.3", "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz", diff --git a/package.json b/package.json index 19708c8..d364818 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "react-native-linear-gradient": "^2.8.3", "react-native-permissions": "^5.2.1", "react-native-qrcode-scanner": "^1.5.5", + "react-native-qrcode-svg": "^6.3.12", "react-native-reanimated": "^3.16.1", "react-native-safe-area-context": "^4.14.0", "react-native-screens": "^3.35.0", diff --git a/src/navigation/HomeStack.tsx b/src/navigation/HomeStack.tsx index b02db8d..3900489 100644 --- a/src/navigation/HomeStack.tsx +++ b/src/navigation/HomeStack.tsx @@ -16,6 +16,7 @@ import { getFocusedRouteNameFromRoute } from '@react-navigation/native'; import { HomeStackParamList } from './types'; import TestBule from '../views/device/test_bule'; import ShareDetailScreen from '../views/device/KeyDetail'; +import ExpiredKeysScreen from '../views/device/ExpiredKeysScreen'; const Stack = createStackNavigator(); const createScreenOptions = (title: string): StackNavigationOptions => { @@ -84,6 +85,13 @@ export default function HomeStackNavigator({ navigation, route }: Props) { component={SnBind} options={createScreenOptions('手动绑车')} /> */} + 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'), }; \ No newline at end of file diff --git a/src/views/device/DeviceShare.tsx b/src/views/device/DeviceShare.tsx index 3a7f79f..c02f76c 100644 --- a/src/views/device/DeviceShare.tsx +++ b/src/views/device/DeviceShare.tsx @@ -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 { useNavigation } from '@react-navigation/native'; +import { useNavigation ,useFocusEffect} from '@react-navigation/native'; import { apiService } from '../../utils/api'; import { rpx } from '../../utils/rpx'; interface KeyItem { @@ -18,7 +18,7 @@ const DeviceShare = () => { const getKeyList = async () => { const response = await apiService.getKeyListByOwnerId(); - + // console.log(response); if (response.code == 200) { setKeyList(response.data); @@ -59,9 +59,11 @@ const DeviceShare = () => { return '未知状态'; } }; - useEffect(() => { - getKeyList(); - }, []); + useFocusEffect( + useCallback(() => { + getKeyList(); + }, []) + ); return ( @@ -121,14 +123,17 @@ const DeviceShare = () => { )} - - - 查看已失效共享 - { + navigation.navigate('ExpiredKeysScreen' as never ); + }}> + + 查看已失效共享 + - + + ); }; diff --git a/src/views/device/ExpiredKeysScreen.tsx b/src/views/device/ExpiredKeysScreen.tsx new file mode 100644 index 0000000..6e1574c --- /dev/null +++ b/src/views/device/ExpiredKeysScreen.tsx @@ -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) => ( + +); + +const ExpiredKeysScreen = ({ navigation }) => { + const [data, setData] = useState([]); + + const navigateBack = () => { + navigation.goBack(); + }; + + const BackAction = () => ( + + ); + + const getExpiredKeys = async () => { + const res = await apiService.getExpiredKeys(); + setData(res || []); + }; + + const renderItem = ({ item }) => ( + + {item.name} {item.number} + 失效时间:{item.date} + + ); + + useEffect(() => { + getExpiredKeys(); + }, []); + + return ( + + + {data.length > 0 ? ( + item.id} + contentContainerStyle={styles.list} + /> + ) : ( + + {/* */} + 暂无失效分享 + + )} + + ); +}; + +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; \ No newline at end of file diff --git a/src/views/device/KeyDetail.tsx b/src/views/device/KeyDetail.tsx index 8a8aa33..213abc6 100644 --- a/src/views/device/KeyDetail.tsx +++ b/src/views/device/KeyDetail.tsx @@ -1,179 +1,409 @@ import React from 'react'; -import { StyleSheet, View, Image,TouchableOpacity } from 'react-native'; -import { Layout, Text, Avatar, Button, Divider, TopNavigation, TopNavigationAction, Icon } from '@ui-kitten/components'; +import { StyleSheet, View, Image, TouchableOpacity, Modal } from 'react-native'; +import { Layout, Text, Avatar, Button, TopNavigation, TopNavigationAction, Icon, Card } from '@ui-kitten/components'; 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 { - id: string; + keyId: string; avatarUrl: string; shareUserName: string; sharePhone: string; status: string; expirationTime: string; } + const BackIcon = (props) => ( - + ); const KeyDetail = () => { - const navigation = useNavigation(); + const navigation = useNavigation(); + const route = useRoute(); + 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 route = useRoute(); - const keyItem = route.params?.keyItem as KeyItem; - - - const navigateBack = () => { - navigation.goBack(); - }; + const showDeleteModal = () => { + setVisible(true); + }; - const BackAction = () => ( - - ); + const hideDeleteModal = () => { + setVisible(false); - const RightIcon = (props) => ( - - ); + }; - return ( - - + const handleDelete = () => { + // 这里添加删除逻辑 + hideDeleteModal(); + apiService.deleteKey(keyItem.keyId).then(res => { + console.log(res,'resresres'); + if (res.code == 200) { + navigation.goBack(); + } + }); + }; - - { + navigation.goBack(); + }; + + const handleTimeSelect = (time: string) => { + setSelectedTime(time); + setShowTimeModal(false); + // 这里添加更新有效期的逻辑 + }; + + const BackAction = () => ( + - 小黄鸭 - 13569254567 - 剩余有效期:23小时54分钟 - - 修改钥匙有效期 - - - - 删除共享人 - - - + ); + const calculateRemainingTime = (expirationTime: string): string => { + const now = new Date(); + const expiration = new Date(expirationTime); + const diffTime = expiration.getTime() - now.getTime(); - - - - - - ); + // 如果已过期 + 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) => ( + + ); + const toQrCode = () => { + navigation.navigate('ShareQrcode', { QrId: keyItem.keyId }); + }; + return ( + + + + + + {keyItem.shareUserName} + {keyItem.sharePhone} + 剩余有效期:{calculateRemainingTime(keyItem.expirationTime)} + setShowTimeModal(true)}> + + 修改钥匙有效期 + + + + + 删除共享人 + + + + + + + + {/* 删除确认弹窗 */} + + + + 删除后,被共享人将无法再操控 您的车辆,确定删除吗? + + + + + + + + + {/* 时间选择弹窗 */} + setShowTimeModal(false)}> + + + + setShowTimeModal(false)} + > + 取消 + + 选择有效期 + setShowTimeModal(false)} + > + 确定 + + + + {timeOptions.map((option, index) => ( + handleTimeSelect(option)} + > + + {option} + + + ))} + + + + + + ); }; const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#F5F5F5', - }, - topNav: { - backgroundColor: '#fff', - borderBottomWidth: 1, - borderBottomColor: '#E8E8E8', - }, - header: { - alignItems: 'center', - backgroundColor: '#fff', - paddingVertical: rpx(40), - marginTop: rpx(20), - }, - avatar: { - width: rpx(188), - height: rpx(188), - marginBottom: rpx(16), - }, - name: { - fontWeight: 'bold', - fontSize: rpx(48), - color: '#333', - marginBottom: rpx(8), - }, - deleteBtn:{ - marginTop: rpx(56), - - }, - deleteText:{ - fontWeight: 'bold', - fontSize: rpx(40), - color: '#FF8282', - }, - eidtBtn: { - width: rpx(592), - marginTop: rpx(20), - height: rpx(108), - display: 'flex', - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - padding: rpx(16), - backgroundColor: '#EEEFF9', - borderRadius: rpx(16), - }, - phone: { - - fontSize: rpx(36), - color: '#808080', - marginBottom: rpx(8), - }, - expireTime: { - marginTop: rpx(20), - fontWeight: '400', - fontSize: rpx(36), - color: '#808080', - }, - actionContainer: { - backgroundColor: '#fff', - marginTop: rpx(20), - }, - actionButton: { - justifyContent: 'space-between', - paddingHorizontal: rpx(32), - paddingVertical: rpx(24), - backgroundColor: '#fff', - borderRadius: 0, - }, - buttonText: { - fontSize: rpx(28), - color: '#333', - }, - arrowIcon: { - width: rpx(38), - height: rpx(38), - tintColor: '#999', - }, - deleteButton: { - paddingVertical: rpx(24), - backgroundColor: '#fff', - borderRadius: 0, - }, - - divider: { - backgroundColor: '#E8E8E8', - }, + container: { + width: rpx(750), + flex: 1, + backgroundColor: '#F3FCFF', + }, + topNav: { + backgroundColor: '#F3FCFF', + borderBottomWidth: 1, + borderBottomColor: '#fff', + }, + header: { + marginHorizontal: 'auto', + width: rpx(700), + alignItems: 'center', + backgroundColor: '#fff', + paddingVertical: rpx(40), + marginTop: rpx(20), + alignSelf: 'center', + borderRadius: rpx(16), + }, + avatar: { + width: rpx(188), + height: rpx(188), + marginBottom: rpx(16), + }, + name: { + fontWeight: 'bold', + fontSize: rpx(48), + color: '#333', + marginBottom: rpx(8), + }, + deleteBtn: { + marginTop: rpx(56), + }, + deleteText: { + fontWeight: 'bold', + fontSize: rpx(40), + color: '#FF8282', + }, + eidtBtn: { + width: rpx(592), + marginTop: rpx(20), + height: rpx(108), + backgroundColor: '#EEEFF9', + borderRadius: rpx(16), + }, + editBtnContent: { + flex: 1, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: rpx(16), + }, + editBtnText: { + fontSize: rpx(36), + color: '#808080', + }, + phone: { + fontSize: rpx(36), + color: '#808080', + marginBottom: rpx(8), + }, + expireTime: { + marginTop: rpx(20), + fontWeight: '400', + fontSize: rpx(36), + color: '#808080', + }, + actionContainer: { + marginHorizontal: 'auto', + width: rpx(700), + backgroundColor: '#fff', + marginTop: rpx(20), + }, + actionButton: { + justifyContent: 'space-between', + paddingHorizontal: rpx(32), + paddingVertical: rpx(24), + backgroundColor: '#fff', + borderRadius: 0, + }, + buttonText: { + fontSize: rpx(36), + color: '#3D3D3D', + }, + arrowIcon: { + width: rpx(38), + height: rpx(38), + tintColor: '#999', + }, + deleteButton: { + paddingVertical: rpx(24), + backgroundColor: '#fff', + borderRadius: 0, + }, + divider: { + 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; \ No newline at end of file diff --git a/src/views/device/shareQrcode.tsx b/src/views/device/shareQrcode.tsx index e076ce1..b0996c9 100644 --- a/src/views/device/shareQrcode.tsx +++ b/src/views/device/shareQrcode.tsx @@ -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 { rpx } from '../../utils/rpx'; import { RouteProp, useRoute } from '@react-navigation/native'; import RNFS from 'react-native-fs'; 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 route = useRoute>(); const { QrId } = route.params; - - const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${rpx(400)}x${rpx(400)}&data=https://your-domain.com/share?id=${QrId}`; - console.log(qrCodeUrl); - - // const qrCodeUrl = `https://lxnapi.ccttiot.com/bike/img/static/upCrcuiBaoZrd9ZRZayj` - // https://lxnapi.ccttiot.com/bike/img/static/upCrcuiBaoZrd9ZRZayj + const [loading, setLoading] = useState(true); + const [qrCodeRef, setQrCodeRef] = useState(null); // 用于保存二维码的引用 + + useEffect(() => { + const timer = setTimeout(() => { + setLoading(false); + }, 2000); + + return () => clearTimeout(timer); + }, []); + const saveToGallery = async () => { try { - // 检查写入权限 - const writePermission = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); - const readPermission = await request(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); - - if (writePermission === RESULTS.GRANTED && readPermission === RESULTS.GRANTED) { - try { - const directoryPath = `${RNFS.DownloadDirectoryPath}`; - 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); - const options = { - fromUrl: qrCodeUrl, - toFile: downloadDest, - }; - - const response = await RNFS.downloadFile(options).promise; - console.log('下载响应:', response); - - if (response.statusCode === 200) { - const fileExists = await RNFS.exists(downloadDest); - if (fileExists) { - // 使用原生模块刷新媒体库 - NativeModules.MediaScanner.scanFile(downloadDest, 'image/jpeg', (err) => { - if (err) { - console.error('媒体扫描错误:', err); - Alert.alert('错误', '无法刷新媒体库'); - } else { - Alert.alert('成功', '二维码已保存到相册'); - } - }); - } else { - throw new Error('文件未能成功创建'); - } - } else { - Alert.alert('错误', '下载失败,请检查网络连接'); - } - } catch (err) { - console.error('文件操作详细错误:', JSON.stringify(err)); - Alert.alert('错误', '保存失败,无法访问存储空间'); + // 检查并请求权限 + let permissionResult; + if (Platform.OS === 'android') { + if (Platform.Version >= 33) { + permissionResult = await request(PERMISSIONS.ANDROID.READ_MEDIA_IMAGES); + } else { + permissionResult = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); } + } + + if (permissionResult === RESULTS.GRANTED || Platform.OS === 'ios') { + qrCodeRef.toDataURL(async (data) => { + try { + // 使用 ExternalDirectoryPath,这个目录在大多数 Android 设备上都可以访问 + const basePath = Platform.OS === 'android' + ? `${RNFS.ExternalDirectoryPath}` + : RNFS.DocumentDirectoryPath; + + const fileName = `qrcode_${Date.now()}.png`; + const filePath = `${basePath}/${fileName}`; + + // 直接写入文件 + await RNFS.writeFile(filePath, data, 'base64'); + + if (Platform.OS === 'android') { + // 使用 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) { + console.error('媒体扫描错误:', err); + Alert.alert('提示', '二维码已保存,但可能需要手动刷新相册'); + } else { + Alert.alert('成功', '二维码已保存到相册'); + } + }); + } + } else { + // iOS 处理 + Alert.alert('成功', '二维码已保存'); + } + } catch (err) { + console.error('文件操作错误:', err); + Alert.alert('错误', '保存失败,请检查存储权限'); + } + }); } else { - Alert.alert('权限不足', '请在设置中授予存储权限'); + Alert.alert('提示', '需要存储权限才能保存二维码,请在设置中授予权限'); } } catch (error) { - console.error('整体错误:', error); + console.error('保存过程错误:', error); Alert.alert('错误', '保存失败,请重试'); } }; + + if (loading) { + return ( + + + 加载中... + + ); + } + return ( - - + setQrCodeRef(c)} // 保存二维码的引用 + logo={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u3giTY4VkWYpnGWRuFHF' }} // 添加 logo + logoSize={rpx(100)} // 设置 logo 大小 + logoBackgroundColor='transparent' // 设置 logo 背景透明 /> - + @@ -105,14 +122,22 @@ const ShareQrcode = () => { ); } - -// ... 其余代码保持不变 ... const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: '#F3FCFF', }, + loadingContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + loadingText: { + marginTop: 10, + fontSize: 16, + color: '#888', + }, btn: { marginTop: rpx(36), width: rpx(614), @@ -139,7 +164,6 @@ const styles = StyleSheet.create({ qrContainer: { alignItems: 'center', justifyContent: 'center', - // marginTop: rpx(-50), }, qrBack: { marginTop: rpx(-20), diff --git a/yarn.lock b/yarn.lock index 0a18f93..34865d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7681,7 +7681,7 @@ prompts@^2.0.1, prompts@^2.3.2, prompts@^2.4.2: kleur "^3.0.3" 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" resolved "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz" 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" integrity sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ== -qrcode@^1.5.4: +qrcode@^1.5.1, qrcode@^1.5.4: version "1.5.4" resolved "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz" integrity sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg== @@ -7876,6 +7876,15 @@ react-native-qrcode-scanner@^1.5.5: prop-types "^15.5.10" 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: version "3.16.3" 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" 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" resolved "https://registry.npmmirror.com/react-native-svg/-/react-native-svg-15.10.1.tgz" integrity sha512-Hqz/doQciVFK/Df2v+wsW96oY5jxlta7rZ31KQYo78dlgvAHEaGr6paEOAMvlIruw7EHNQ0Vc1ZmJPJF2kfIPQ== @@ -7939,7 +7948,7 @@ react-native-wheel-picker-android@^2.0.6: dependencies: 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" resolved "https://registry.npmmirror.com/react-native/-/react-native-0.74.6.tgz" integrity sha512-TZ8uLf+dH+nO5nFwjhMd4PqtraeNT5cXQ0ySAhq7qqbTBgalxO3UklsLFW3cTSedC+eLw6J3P3H62e3/MjpWNw== @@ -9009,6 +9018,11 @@ test-exclude@^6.0.0: glob "^7.1.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: version "1.0.3" resolved "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz"