diff --git a/package-lock.json b/package-lock.json index 123e84c..35fd3c6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,8 +30,10 @@ "react-native-contacts": "^8.0.4", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.20.2", + "react-native-image-picker": "^7.2.3", "react-native-linear-gradient": "^2.8.3", "react-native-permissions": "^5.2.1", + "react-native-qrcode": "^0.2.7", "react-native-qrcode-scanner": "^1.5.5", "react-native-qrcode-svg": "^6.3.12", "react-native-reanimated": "^3.16.1", @@ -7535,6 +7537,15 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmmirror.com/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "dependencies": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "node_modules/cross-fetch": { "version": "3.1.8", "resolved": "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-3.1.8.tgz", @@ -13964,6 +13975,11 @@ ], "license": "MIT" }, + "node_modules/qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmmirror.com/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==" + }, "node_modules/qrcode": { "version": "1.5.4", "resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz", @@ -14377,7 +14393,6 @@ "version": "2.20.0", "resolved": "https://registry.npmmirror.com/react-native-fs/-/react-native-fs-2.20.0.tgz", "integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==", - "license": "MIT", "dependencies": { "base-64": "^0.1.0", "utf8": "^3.0.0" @@ -14413,6 +14428,15 @@ "react-native": "*" } }, + "node_modules/react-native-image-picker": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/react-native-image-picker/-/react-native-image-picker-7.2.3.tgz", + "integrity": "sha512-zKIZUlQNU3EtqizsXSH92zPeve4vpUrsqHu2kkpCxWE9TZhJFZBb+irDsBOY8J21k0+Edgt06TMQGJ+iPUIXyA==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-linear-gradient": { "version": "2.8.3", "resolved": "https://registry.npmmirror.com/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz", @@ -14439,6 +14463,16 @@ } } }, + "node_modules/react-native-qrcode": { + "version": "0.2.7", + "resolved": "https://registry.npmmirror.com/react-native-qrcode/-/react-native-qrcode-0.2.7.tgz", + "integrity": "sha512-Xvc3T1h95zA9tbRxiMkKethDYpPwKcqDPIHe9Cxt7pM+lma9dSzd6yXGGLGeZmFU/SmHMK+4bTnDltUv1s4Jnw==", + "dependencies": { + "create-react-class": "^15.6.0", + "prop-types": "^15.5.10", + "qr.js": "0.0.0" + } + }, "node_modules/react-native-qrcode-scanner": { "version": "1.5.5", "resolved": "https://registry.npmmirror.com/react-native-qrcode-scanner/-/react-native-qrcode-scanner-1.5.5.tgz", diff --git a/package.json b/package.json index 5c8f81a..819ea9b 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,10 @@ "react-native-contacts": "^8.0.4", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "^2.20.2", + "react-native-image-picker": "^7.2.3", "react-native-linear-gradient": "^2.8.3", "react-native-permissions": "^5.2.1", + "react-native-qrcode": "^0.2.7", "react-native-qrcode-scanner": "^1.5.5", "react-native-qrcode-svg": "^6.3.12", "react-native-reanimated": "^3.16.1", diff --git a/src/views/bind/bind_index.tsx b/src/views/bind/bind_index.tsx index 9192a8a..d681cea 100644 --- a/src/views/bind/bind_index.tsx +++ b/src/views/bind/bind_index.tsx @@ -7,16 +7,28 @@ import { Keyboard, Text, TouchableOpacity, - Modal, - Image + Image, + Modal } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { StackNavigationProp } from '@react-navigation/stack'; import { rpx } from '../../utils/rpx'; import QRCodeScanner from 'react-native-qrcode-scanner'; import { RNCamera } from 'react-native-camera'; -import { TopNavigation, TopNavigationAction, Icon } from '@ui-kitten/components'; +import { TopNavigation, TopNavigationAction, Icon, Popover, Button } from '@ui-kitten/components'; import Toast from 'react-native-toast-message'; +import { launchImageLibrary } from 'react-native-image-picker'; + +// 假设你有一个函数 checkIfImageContainsQRCode 和 decodeQRCodeFromImage +const checkIfImageContainsQRCode = async (imageUri: string): Promise => { + // 实现判断图片是否包含二维码的逻辑 + return true; // 示例返回值 +}; + +const decodeQRCodeFromImage = async (imageUri: string): Promise => { + // 实现二维码解析的逻辑 + return 'example_sn=123456'; // 示例返回值 +}; type RootStackParamList = { Home: undefined; @@ -34,10 +46,15 @@ const BackIcon = (props: any) => ( ); +const MoreIcon = (props: any) => ( + +); + const SnBind = () => { const navigation = useNavigation(); const [sn, setSn] = useState(''); const [isScanning, setIsScanning] = useState(false); + const [popoverVisible, setPopoverVisible] = useState(false); const navigateBack = () => { navigation.goBack(); @@ -47,6 +64,10 @@ const SnBind = () => { ); + const togglePopover = () => { + setPopoverVisible(!popoverVisible); + }; + const handlePress = () => { if (!sn.trim()) { Toast.show({ @@ -58,8 +79,59 @@ const SnBind = () => { navigation.navigate('ConfirmBind', { sn: sn.trim() }); }; - const handleScan = () => { - setIsScanning(true); + const handleImagePicker = () => { + setPopoverVisible(false); + launchImageLibrary({ mediaType: 'photo' }, (response) => { + if (response.didCancel) { + console.log('User cancelled image picker'); + } else if (response.errorCode) { + console.log('ImagePicker Error: ', response.errorMessage); + } else if (response.assets && response.assets.length > 0) { + const imageUri = response.assets[0].uri; + // 判断图片是否包含二维码 + checkIfImageContainsQRCode(imageUri) + .then((containsQRCode) => { + if (!containsQRCode) { + Toast.show({ + type: 'error', + text1: '图片不包含二维码', + }); + return; + } + // 使用二维码解析库解析图片 + decodeQRCodeFromImage(imageUri) + .then((data) => { + console.log('二维码内容:', data); + // 处理解析结果 + const snMatch = data.match(/[?&]sn=([^&]+)/); + if (snMatch && snMatch[1]) { + setSn(snMatch[1]); + Toast.show({ + type: 'success', + text1: '图片解析成功', + }); + } else { + Toast.show({ + type: 'error', + text1: '未找到有效的SN码', + }); + } + }) + .catch((error) => { + Toast.show({ + type: 'error', + text1: '图片解析失败或不包含二维码', + }); + }); + }) + .catch((error) => { + Toast.show({ + type: 'error', + text1: '无法判断图片内容', + }); + }); + } + }); }; const onSuccess = (e: { data: string }) => { @@ -113,12 +185,26 @@ const SnBind = () => { value={sn} onChangeText={setSn} /> - - - + ( + + + + )} + visible={popoverVisible} + onBackdropPress={togglePopover} + > + + + + + {/* 提示文本 */} @@ -245,11 +331,17 @@ const styles = StyleSheet.create({ backgroundColor: '#4297F3', alignItems: 'center', justifyContent: 'center', + shadowColor: '#000', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.3, + shadowRadius: 4, + elevation: 5, }, scanIcon: { width: rpx(88), height: rpx(88), resizeMode: 'contain', + tintColor: '#fff', }, tip: { marginTop: rpx(40), diff --git a/yarn.lock b/yarn.lock index 90e6361..e341a20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3834,6 +3834,14 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" +create-react-class@^15.6.0: + version "15.7.0" + resolved "https://registry.npmmirror.com/create-react-class/-/create-react-class-15.7.0.tgz" + integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + cross-fetch@^3.1.5: version "3.1.8" resolved "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-3.1.8.tgz" @@ -6521,7 +6529,7 @@ logkitty@^0.7.1: dayjs "^1.8.15" yargs "^15.1.0" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -7671,6 +7679,11 @@ pure-rand@^6.0.0: resolved "https://registry.npmmirror.com/pure-rand/-/pure-rand-6.1.0.tgz" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== +qr.js@0.0.0: + version "0.0.0" + resolved "https://registry.npmmirror.com/qr.js/-/qr.js-0.0.0.tgz" + integrity sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ== + qrcode-terminal@0.11.0: version "0.11.0" resolved "https://registry.npmmirror.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz" @@ -7810,6 +7823,11 @@ react-native-gesture-handler@^2.20.2, "react-native-gesture-handler@>= 1.0.0": invariant "^2.2.4" prop-types "^15.7.2" +react-native-image-picker@^7.2.3: + version "7.2.3" + resolved "https://registry.npmmirror.com/react-native-image-picker/-/react-native-image-picker-7.2.3.tgz" + integrity sha512-zKIZUlQNU3EtqizsXSH92zPeve4vpUrsqHu2kkpCxWE9TZhJFZBb+irDsBOY8J21k0+Edgt06TMQGJ+iPUIXyA== + react-native-linear-gradient@^2.8.3: version "2.8.3" resolved "https://registry.npmmirror.com/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz" @@ -7843,6 +7861,15 @@ react-native-qrcode-svg@^6.3.12: qrcode "^1.5.1" text-encoding "^0.7.0" +react-native-qrcode@^0.2.7: + version "0.2.7" + resolved "https://registry.npmmirror.com/react-native-qrcode/-/react-native-qrcode-0.2.7.tgz" + integrity sha512-Xvc3T1h95zA9tbRxiMkKethDYpPwKcqDPIHe9Cxt7pM+lma9dSzd6yXGGLGeZmFU/SmHMK+4bTnDltUv1s4Jnw== + dependencies: + create-react-class "^15.6.0" + prop-types "^15.5.10" + qr.js "0.0.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"