diff --git a/src/components/DeviceControl.tsx b/src/components/DeviceControl.tsx new file mode 100644 index 0000000..4b2b3ce --- /dev/null +++ b/src/components/DeviceControl.tsx @@ -0,0 +1,452 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { View, Image, Text, StyleSheet, TouchableOpacity, Alert, Animated } from 'react-native'; +import { Spinner } from '@ui-kitten/components'; +import { apiService } from '../utils/api'; +import BluetoothManager, { CommandType, ConnectionState } from '../utils/BluetoothManager'; +import { rpx } from '../utils/rpx'; +import Slider from './slider'; + +interface DeviceControlProps { + defaultDevice: any; + onDeviceUpdate?: () => void; +} + +const DeviceControl: React.FC = ({ defaultDevice, onDeviceUpdate }) => { + const [isConnecting, setIsConnecting] = useState(false); + const [showBluetoothStatus, setShowBluetoothStatus] = useState(false); + const [connectionState, setConnectionState] = useState(ConnectionState.DISCONNECTED); + const retryAttemptRef = useRef(false); + const fadeAnim = useRef(new Animated.Value(0)).current; + const slideAnim = useRef(new Animated.Value(-rpx(272))).current; + + const showWithAnimation = () => { + setShowBluetoothStatus(true); + Animated.parallel([ + Animated.timing(fadeAnim, { + toValue: 1, + duration: 300, + useNativeDriver: true, + }), + Animated.spring(slideAnim, { + toValue: 0, + useNativeDriver: true, + friction: 8, + }) + ]).start(); + }; + + const hideWithAnimation = () => { + Animated.parallel([ + Animated.timing(fadeAnim, { + toValue: 0, + duration: 300, + useNativeDriver: true, + }), + Animated.timing(slideAnim, { + toValue: -rpx(272), + duration: 300, + useNativeDriver: true, + }) + ]).start(() => { + setShowBluetoothStatus(false); + }); + }; + + const handleBluetoothConnection = async (isRetry = false): Promise => { + if (isConnecting) return false; + + try { + setIsConnecting(true); + showWithAnimation(); + const targetMac = 'FD51BB7A4EE0'; // 暂时使用固定MAC + console.log(`${isRetry ? '重试' : '开始'}连接设备, 目标MAC:`, targetMac); + + const initialized = await BluetoothManager.init(); + if (!initialized) { + throw new Error('蓝牙初始化失败'); + } + + let targetDevice = null; + let scannedDevices = new Set(); + + await BluetoothManager.startScan((device) => { + const deviceName = device.name || device.localName || ''; + const macMatch = deviceName.match(/BBLE:([A-Fa-f0-9]{12})/); + const deviceMac = macMatch ? macMatch[1] : ''; + + if (!scannedDevices.has(deviceMac) && deviceMac) { + scannedDevices.add(deviceMac); + console.log('扫描到设备:', { + name: deviceName, + extractedMac: deviceMac, + rssi: device.rssi + }); + } + + if (deviceMac === targetMac) { + console.log('找到目标设备:', deviceMac); + targetDevice = device; + BluetoothManager.stopScan(); + } + }); + + await new Promise(resolve => setTimeout(resolve, 5000)); + BluetoothManager.stopScan(); + + if (!targetDevice) { + throw new Error('未找到指定设备,请确保设备在范围内且已开启'); + } + + const connected = await BluetoothManager.connectToDevice(targetDevice); + if (!connected) { + throw new Error('连接设备失败'); + } + + console.log('成功连接到设备'); + retryAttemptRef.current = false; + return true; + + } catch (error) { + console.error(`${isRetry ? '重试' : ''}蓝牙连接失败:`, error); + if (!isRetry && !retryAttemptRef.current) { + console.log('将在3秒后尝试重新连接...'); + retryAttemptRef.current = true; + setTimeout(async () => { + await handleBluetoothConnection(true); + }, 3000); + } else { + setTimeout(hideWithAnimation, 3000); + } + return false; + } finally { + setIsConnecting(false); + } + }; + + const handleRing = async () => { + console.log('响铃操作 - 设备信息:', { + 完整设备信息: defaultDevice, + 设备SN: defaultDevice?.sn, + 当前时间: new Date().toISOString() + }); + + if (!defaultDevice?.sn) { + Alert.alert('提示', '请先选择设备'); + return; + } + + try { + const response = await apiService.ring(defaultDevice.sn); + console.log('响铃API响应:', response); + + if (response.code != 200) { + retryAttemptRef.current = false; + const connected = await handleBluetoothConnection(false); + if (connected) { + await BluetoothManager.playResponse(); + } + } + } catch (error) { + console.error('响铃失败:', error); + retryAttemptRef.current = false; + const connected = await handleBluetoothConnection(false); + if (connected) { + await BluetoothManager.playResponse(); + } + } + }; + + const handleLockStatus = async (status: boolean) => { + if (!defaultDevice || !defaultDevice.sn) { + console.warn('设备数据无效:', { + 设备对象: defaultDevice, + 操作类型: status ? '开锁' : '关锁' + }); + Alert.alert('提示', '设备数据无效,请确保设备已正确选择'); + return; + } + + const response = await (status ? + apiService.unlocking(defaultDevice.sn) : + apiService.lock(defaultDevice.sn)); + + console.log('开关锁API响应:', { + 响应数据: response, + 操作类型: status ? '开锁' : '关锁', + 时间: new Date().toISOString() + }); + + if (response.code != 200) { + retryAttemptRef.current = false; + const connected = await handleBluetoothConnection(false); + + if (connected) { + try { + await (status ? + BluetoothManager.openDevice() : + BluetoothManager.closeDevice()); + + if (onDeviceUpdate) { + onDeviceUpdate(); // 蓝牙操作成功后调用更新 + } + } catch (bluetoothError) { + console.error('蓝牙命令执行失败:', bluetoothError); + Alert.alert('错误', '蓝牙命令执行失败,请重试'); + } + } else { + Alert.alert('提示', '蓝牙连接失败,请确保设备在范围内且已开启'); + } + } else { + // API 调用成功,直接更新状态 + if (onDeviceUpdate) { + onDeviceUpdate(); + } + } + }; + + const getPowerColor = (power: number): string => { + if (power >= 60) { + return 'rgba(89, 202, 112, 0.5)'; + } else if (power >= 20) { + return 'rgba(255, 149, 0, 0.5)'; + } else { + return 'rgba(255, 69, 58, 0.5)'; + } + }; + + useEffect(() => { + const removeListener = BluetoothManager.addConnectionStateListener((state) => { + console.log('蓝牙连接状态变化:', state); + setConnectionState(state); + if (state === ConnectionState.DISCONNECTED) { + hideWithAnimation(); + } + }); + + return () => { + removeListener(); + BluetoothManager.disconnect(); + hideWithAnimation(); + }; + }, []); + + return ( + <> + + + + {defaultDevice?.remainingPower || 0}% + + + + + + + 当前车辆状态: {defaultDevice?.lockStatus == 1 ? '开锁' : '关锁'} + + + {showBluetoothStatus && ( + + {isConnecting ? ( + <> + + 正在连接 + + + ) : ( + <> + 连接成功 + + + )} + + )} + + + + + + 鸣笛寻车 + + + {defaultDevice && ( + + )} + + + + 警报已开 + + + + ); +}; + +const styles = StyleSheet.create({ + infoBox: { + marginTop: rpx(66), + flexDirection: 'row', + justifyContent: 'space-between' + }, + carBox: { + width: rpx(440), + position: 'absolute', + top: rpx(20), + left: rpx(124), + zIndex: 0, + }, + switch: { + width: rpx(272), + height: rpx(60), + backgroundColor: '#FFFFFF', + borderRadius: rpx(30), + flexDirection: 'row', + alignItems: 'center', + paddingHorizontal: rpx(20), + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.1, + shadowRadius: 4, + elevation: 4, + }, + statusText: { + fontSize: rpx(32), + fontWeight: '400', + marginLeft: rpx(10), + }, + connecting: { + color: '#FF8282', + }, + connected: { + color: '#4297F3', + marginLeft: rpx(40), + }, + bluetooth: { + width: rpx(60), + height: rpx(60), + marginLeft: 'auto', + }, + Bind_type: { + flexDirection: 'row', + width: rpx(272), + height: rpx(60), + backgroundColor: '#fff', + borderRadius: rpx(30), + alignItems: 'center', + }, + txtbox: { + width: rpx(440), + justifyContent: 'center', + flexDirection: 'row', + alignItems: 'center', + }, + txt: { + marginLeft: rpx(14), + fontSize: rpx(28), + fontWeight: '400', + color: '#3D3D3D', + }, + yuan: { + width: rpx(22), + height: rpx(22), + borderRadius: rpx(11), + backgroundColor: 'rgba(255, 130, 130, 1)', + }, + eleBox: { + paddingTop: rpx(14), + paddingRight: rpx(6), + paddingBottom: rpx(6), + paddingLeft: rpx(6), + width: rpx(86), + height: rpx(166), + borderRadius: rpx(16), + backgroundColor: '#FFFFFF', + justifyContent: 'flex-end', + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.1, + shadowRadius: 4, + elevation: 4, + borderWidth: 1, + borderColor: '#E0E0E0', + }, + eleType: { + width: '100%', + minHeight: rpx(30), + borderRadius: rpx(16), + position: 'relative', + }, + eleTypeTxt: { + position: 'absolute', + top: rpx(-40), + width: '100%', + textAlign: 'center', + fontSize: rpx(32), + color: '#3D3D3D', + textShadowColor: 'rgba(255, 255, 255, 0.5)', + textShadowOffset: { width: 0, height: 1 }, + textShadowRadius: 2 + }, + car_stause_box: { + marginTop: rpx(308), + flexDirection: 'row', + justifyContent: 'space-around' + }, + car_stause_li: { + width: rpx(136), + justifyContent: 'center' + }, + stauseText: { + fontSize: rpx(32), + color: '#3D3D3D', + textAlign: 'center', + marginTop: rpx(24) + }, +}); + +export default DeviceControl; \ No newline at end of file diff --git a/src/components/slider.tsx b/src/components/slider.tsx index b001220..802b9a1 100644 --- a/src/components/slider.tsx +++ b/src/components/slider.tsx @@ -6,21 +6,21 @@ interface SliderProps { onStatusChange?: (status: boolean) => void; } -// 添加 rpx 计算函数 const { width: SCREEN_WIDTH } = Dimensions.get('window'); const rpx = (px: number) => { return (SCREEN_WIDTH / 750) * px; }; const Slider: React.FC = ({ lockStatus = 1, onStatusChange }) => { - const translateX = useRef(new Animated.Value(lockStatus === 0 ? rpx(180) : 0)).current; + // 修改初始值逻辑:lockStatus = 0(关锁)时滑块在左侧,lockStatus = 1(开锁)时滑块在右侧 + const translateX = useRef(new Animated.Value(lockStatus === 0 ? 0 : rpx(180))).current; const maxWidth = rpx(180); const buttonWidth = rpx(86); - const [isRight, setIsRight] = useState(lockStatus === 0); + // 修改状态判断:lockStatus = 1 表示开锁(isRight = true) + const [isRight, setIsRight] = useState(lockStatus === 1); const hasVibratedRef = useRef(false); const offsetRef = useRef(0); - // 添加监听器 useEffect(() => { const id = translateX.addListener(({ value }) => { if (value >= maxWidth * 0.95) { @@ -54,13 +54,7 @@ const Slider: React.FC = ({ lockStatus = 1, onStatusChange }) => { offsetRef.current = translateX._value; }, onPanResponderMove: (_, gestureState) => { - let newValue; - if (isRight) { - newValue = offsetRef.current + gestureState.dx; - } else { - newValue = offsetRef.current + gestureState.dx; - } - + let newValue = offsetRef.current + gestureState.dx; newValue = Math.max(0, Math.min(maxWidth, newValue)); translateX.setValue(newValue); @@ -100,7 +94,13 @@ const Slider: React.FC = ({ lockStatus = 1, onStatusChange }) => { useNativeDriver: false, }).start(() => { hasVibratedRef.current = false; - onStatusChange?.(finalIsRight); + console.log('Slider 状态改变:', { + finalIsRight, + 当前状态: finalIsRight ? '开锁' : '关锁' + }); + if (onStatusChange) { + onStatusChange(finalIsRight); + } }); }, }) @@ -109,10 +109,8 @@ const Slider: React.FC = ({ lockStatus = 1, onStatusChange }) => { return ( - {/* 默认背景 */} - {/* 蓝色滑动背景 */} = ({ lockStatus = 1, onStatusChange }) => { ]} /> - {/* 滑块 */} = ({ lockStatus = 1, onStatusChange }) => { /> - {/* 箭头图标 */} (); // 定义需要显示底部导航栏的路由名称 const showTabBarRoutes = ['爱车', '个人中心']; - const MainNavigator = () => { return ( { tabBarHideOnKeyboard: true, }} tabBar={props => { - const routeName = getFocusedRouteNameFromRoute(props.state.routes[props.state.index]) ?? '爱车'; - if (!showTabBarRoutes.includes(routeName)) { + // 获取当前路由名称和路由状态 + const currentRoute = props.state.routes[props.state.index]; + const routeName = getFocusedRouteNameFromRoute(currentRoute); + + // 只在主页面(爱车)和个人中心显示底部导航栏 + const showTabBarRoutes = ['Home', undefined]; // undefined 表示在根路由时显示 + + // 如果不是主页面或个人中心,则隐藏底部导航栏 + if (routeName && !showTabBarRoutes.includes(routeName)) { return null; } + return ( { ); diff --git a/src/utils/api.ts b/src/utils/api.ts index 5630d1b..111eefa 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -103,4 +103,7 @@ export const apiService = { 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}`), }; \ No newline at end of file diff --git a/src/views/Home/MiniMap.tsx b/src/views/Home/MiniMap.tsx index 9bb3bc0..aace6d2 100644 --- a/src/views/Home/MiniMap.tsx +++ b/src/views/Home/MiniMap.tsx @@ -9,54 +9,81 @@ import { StackNavigationProp } from '@react-navigation/stack'; type RootStackParamList = { Home: undefined; DeviceList: undefined; - DeviceMap: undefined; + DeviceMap: { + sn: string; + }; }; +interface DeviceControlProps { + defaultDevice: any; +} + type NavigationProp = StackNavigationProp; -const MiniMap = () => { +const MiniMap: React.FC = ({ defaultDevice }) => { const navigation = useNavigation(); - // useEffect(() => { - // AMapSdk.init( - // Platform.select({ - // android: "812efd3a950ba3675f928630302c6463", - // }) - // ); - // }, []); - - const handleMapPress = () => { - navigation.navigate('DeviceMap'); + // 确保经纬度是数字类型,使用设备的实际定位 + const latitude = defaultDevice?.latitude ? parseFloat(defaultDevice.latitude) : 26.95500669; + const longitude = defaultDevice?.longitude ? parseFloat(defaultDevice.longitude) : 120.32736769; + // const address = defaultDevice?.location || '位置获取中...'; + // console.log(defaultDevice.latitude, defaultDevice.longitude, 'defaultDevice'); + // console.log(latitude, longitude, 'latitude, longitude'); + // 格式化更新时间 + const formatUpdateTime = (timeStr: string): string => { + if (!timeStr) return '未知'; + + const timestamp = new Date(timeStr).getTime(); + const now = Date.now(); + const diff = now - timestamp; + + if (diff < 60000) { // 小于1分钟 + return '刚刚'; + } else if (diff < 3600000) { // 小于1小时 + return `${Math.floor(diff / 60000)}分钟前`; + } else if (diff < 86400000) { // 小于24小时 + return `${Math.floor(diff / 3600000)}小时前`; + } else { + return `${Math.floor(diff / 86400000)}天前`; + } }; - const latitude = 26.95500669; - const longitude = 120.32736769; - const imageUrl = "https://lxnapi.ccttiot.com/bike/img/static/uRx1B8B8acbquF2TO7Ry"; + const updateTime = defaultDevice?.lastLocationTime ? formatUpdateTime(defaultDevice.lastLocationTime) : '未知'; + + const handleMapPress = () => { + navigation.navigate('DeviceMap', { + sn: defaultDevice?.sn || '' + }); + }; return ( + + { defaultDevice&&( + - - + icon={{ uri: "https://lxnapi.ccttiot.com/bike/img/static/uRx1B8B8acbquF2TO7Ry" }} + /> + + )} + { - 上次蓝牙连接位置 + 上次车辆位置 - 更新于 3分钟前 + 更新于 {updateTime} - - 福建省宁德市福鼎市海滨路200号靠近福鼎第四中学 - + {/* + {address} + */} { return 'rgba(255, 69, 58, 0.5)'; // 红色 } }; + const handleDeviceUpdate = async () => { + console.log('handleDeviceUpdate'); + + const response = await apiService.getDeviceList(); + + if (response?.code == 200 && response.data) { + const defaultDev = response.data.find((device: DeviceType) => device.isDefault == 1); + if (defaultDev) { + // console.log(defaultDev, 'defaultDev'); + setDefaultDevice(defaultDev); + } + + } + }; const fetchDeviceList = async () => { try { @@ -134,7 +149,7 @@ const NormaIndex: React.FC = () => { if (response?.code === 200 && response.data) { const defaultDev = response.data.find((device: DeviceType) => device.isDefault == 1); if (defaultDev) { - console.log(defaultDev, 'defaultDev'); + // console.log(defaultDev, 'defaultDev'); setDefaultDevice(defaultDev); } @@ -202,8 +217,8 @@ const NormaIndex: React.FC = () => { - - + + {/* { /> 警报已开 - + */} - + diff --git a/src/views/ProfileScreen.jsx b/src/views/ProfileScreen.jsx index e0f5b8a..cc33ed6 100644 --- a/src/views/ProfileScreen.jsx +++ b/src/views/ProfileScreen.jsx @@ -5,15 +5,16 @@ import { Image, View, TouchableOpacity, - ImageBackground + ImageBackground, + Alert } from 'react-native'; -import { Text } from '@ui-kitten/components'; +import { Text, Button } from '@ui-kitten/components'; import { useNavigation } from '@react-navigation/native'; -import axios from 'axios'; + import { useAuth } from '../context/AuthContext'; import { rpx } from '../utils/rpx'; import { apiService } from '../utils/api'; - +import { auth } from '../utils/auth'; const ProfileScreen = () => { const navigation = useNavigation(); const { setIsLoggedIn } = useAuth(); @@ -39,6 +40,17 @@ const ProfileScreen = () => { } }; + const handleLogout = async () => { + try { + await auth.removeToken(); // 清除本地存储的 token + // setIsLoggedIn(false); // 更新登录状态 + // 不需要手动导航,因为 AppNavigator 会根据 isLoggedIn 自动处理导航 + getUserInfo(); + } catch (error) { + console.error('退出登录失败:', error); + } + }; + return ( { /> - {/* 我的设备 */} + {/* 管理与服务区域 */} 管理与服务 @@ -135,11 +147,15 @@ const ProfileScreen = () => { )} - - {/* TabBar */} - {/* - - */} + + {/* 退出登录按钮 */} + @@ -229,8 +245,10 @@ const styles = StyleSheet.create({ fontSize: rpx(32), color: '#3D3D3D', }, - tabBarContainer: { - marginLeft: rpx(-32), + logoutButton: { + marginTop: rpx(40), + marginBottom: rpx(40), + borderRadius: rpx(30), } }); diff --git a/src/views/device/deviceMap.tsx b/src/views/device/deviceMap.tsx index 7c140c7..e74fd4a 100644 --- a/src/views/device/deviceMap.tsx +++ b/src/views/device/deviceMap.tsx @@ -1,95 +1,102 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Image, StatusBar, Linking, Platform, PermissionsAndroid } from 'react-native'; import { MapView, Marker, MapType } from 'react-native-amap3d'; import Geolocation from '@react-native-community/geolocation'; import { rpx } from '../../utils/rpx'; -import { useNavigation } from '@react-navigation/native'; +import { useNavigation, useRoute } from '@react-navigation/native'; import { transformFromWGSToGCJ } from '../../utils/coordtransform'; +import { apiService } from '../../utils/api'; + +interface DeviceLocation { + latitude: number; + longitude: number; + address?: string; + updateTime?: string; +} + +interface DeviceInfo { + latitude: string; + longitude: string; + lastLocationTime: string; + location?: string; +} const DeviceMap = () => { const navigation = useNavigation(); - const [location, setLocation] = useState({ - latitude: 26.95500669, - longitude: 120.32736769, - }); - const [isLoading, setIsLoading] = useState(false); + const route = useRoute(); + const { sn } = route.params as { sn: string }; + const mapRef = useRef(null); + + const [userLocation, setUserLocation] = useState<{latitude: number; longitude: number} | null>(null); + const [deviceLocation, setDeviceLocation] = useState(null); + const [isLoading, setIsLoading] = useState(true); - // 请求 Android 定位权限 - const requestAndroidPermission = async () => { + // 获取设备位置信息 + const getDeviceLocation = async () => { try { - const granted = await PermissionsAndroid.request( - PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, - { - title: "位置信息权限", - message: "需要获取您的位置信息", - buttonNeutral: "稍后询问", - buttonNegative: "取消", - buttonPositive: "确定" - } - ); - return granted === PermissionsAndroid.RESULTS.GRANTED; - } catch (err) { - console.warn(err); - return false; - } - }; + if (!sn) { + console.warn('设备SN不存在'); + return; + } - const getCurrentLocation = async () => { - setIsLoading(true); - try { - // ... 权限检查和配置代码保持不变 - - // 同时发起高精度和低精度定位请求 - const highAccuracyPromise = new Promise((resolve, reject) => { - Geolocation.getCurrentPosition( - resolve, - reject, - { - enableHighAccuracy: true, - timeout: 5000, - maximumAge: 1000 - } - ); - }); - - const lowAccuracyPromise = new Promise((resolve, reject) => { - Geolocation.getCurrentPosition( - resolve, - reject, - { - enableHighAccuracy: false, - timeout: 10000, - maximumAge: 5000 - } - ); - }); - - Promise.race([highAccuracyPromise, lowAccuracyPromise]) - .then((position: any) => { - console.log('原始定位结果:', position); - // 转换坐标系 - const gcjLocation = transformFromWGSToGCJ( - position.coords.latitude, - position.coords.longitude - ); - console.log('转换后的坐标:', gcjLocation); - setLocation(gcjLocation); - setIsLoading(false); - }) - .catch((error) => { - console.error('定位失败:', error); - setIsLoading(false); + const response = await apiService.getDeviceInfo(sn); + if (response.code === 200 && response.data) { + const { latitude, longitude, lastLocationTime, location } = response.data; + setDeviceLocation({ + latitude: Number(latitude), + longitude: Number(longitude), + address: location || '', + updateTime: lastLocationTime || '' }); - + setIsLoading(false); + } else { + console.warn('获取设备信息失败:', response); + } } catch (error) { - console.error('获取位置信息失败:', error); - setIsLoading(false); + console.error('获取设备位置信息失败:', error); + } + }; + + const getCurrentLocation = () => { + // const watchId = Geolocation.watchPosition( + // (position) => { + // const gcjLocation = transformFromWGSToGCJ( + // position.coords.latitude, + // position.coords.longitude + // ); + // setUserLocation(gcjLocation); + // }, + // (error) => { + // console.error('位置监听错误:', error); + // }, + // { + // enableHighAccuracy: true, + // timeout: 5000, + // maximumAge: 1000, + // distanceFilter: 10 + // } + // ); + if (!userLocation) { + console.warn('用户位置未获取'); + return; + } + + try { + // 使用 setStatus 方法移动地图 + if (mapRef.current) { + mapRef.current.moveCamera({ + target: userLocation, + zoom: 15, + }, 1000); + } + } catch (error) { + console.error('移动地图失败:', error); } }; - // 位置监听也需要转换坐标系 useEffect(() => { getCurrentLocation(); + getDeviceLocation(); const watchId = Geolocation.watchPosition( (position) => { @@ -97,7 +104,9 @@ const DeviceMap = () => { position.coords.latitude, position.coords.longitude ); - setLocation(gcjLocation); + console.log(gcjLocation,'gcjLocation'); + + setUserLocation(gcjLocation); }, (error) => { console.error('位置监听错误:', error); @@ -113,37 +122,50 @@ const DeviceMap = () => { return () => { Geolocation.clearWatch(watchId); }; - }, []); + }, [sn]); // 跳转到高德地图 const openAMap = async () => { + if (!deviceLocation) return; + const url = Platform.select({ - android: `androidamap://navi?sourceApplication=appname&lat=${location.latitude}&lon=${location.longitude}&dev=0&style=2`, - ios: `iosamap://navi?sourceApplication=appname&lat=${location.latitude}&lon=${location.longitude}&dev=0&style=2`, + android: `androidamap://navi?sourceApplication=appname&lat=${deviceLocation.latitude}&lon=${deviceLocation.longitude}&dev=0&style=2`, + ios: `iosamap://navi?sourceApplication=appname&lat=${deviceLocation.latitude}&lon=${deviceLocation.longitude}&dev=0&style=2`, }); - const imageUrl = "https://lxnapi.ccttiot.com/bike/img/static/uRx1B8B8acbquF2TO7Ry"; - const fallbackUrl = `https://uri.amap.com/navigation?to=${location.longitude},${location.latitude},目的地&mode=car&coordinate=gaode`; + const fallbackUrl = `https://uri.amap.com/navigation?to=${deviceLocation.longitude},${deviceLocation.latitude},目的地&mode=car&coordinate=gaode`; try { - // 检查是否安装了高德地图 const supported = await Linking.canOpenURL(url); - if (supported) { await Linking.openURL(url); } else { - // 如果没有安装高德地图,则打开网页版 await Linking.openURL(fallbackUrl); } } catch (error) { console.error('无法打开高德地图:', error); - // 打开网页版作为后备方案 await Linking.openURL(fallbackUrl); } }; + // 格式化时间 + const formatTime = (timeString: string) => { + if (!timeString) return '12:00'; + const date = new Date(timeString); + return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; + }; + + if (isLoading || !deviceLocation) { + return ( + + 加载中... + + ); + } + return ( { zoomEnabled={true} initialCameraPosition={{ target: { - latitude: location.latitude, - longitude: location.longitude, + latitude: deviceLocation.latitude, + longitude: deviceLocation.longitude, }, zoom: 15, }} > - + {userLocation && ( + + )} + - + + + + + - 福建省宁德市福鼎市海滨路200号靠近福鼎第四中学 + {deviceLocation.address || '获取地址中...'} + { + const response = apiService.ring(sn); + console.log(response,'response'); + }}> + + - + - 12:00 + {deviceLocation.updateTime} { }; const styles = StyleSheet.create({ - container: { flex: 1, backgroundColor: '#FFFFFF', @@ -213,18 +262,17 @@ const styles = StyleSheet.create({ }, timeBlock: { display: 'flex', - flexDirection: 'row', // 确保内容水平排列 + flexDirection: 'row', alignSelf: 'flex-start', justifyContent:'center', alignItems:'center', - padding: rpx(8) , + padding: rpx(8), paddingHorizontal:rpx(18), backgroundColor: '#EFEFEF', borderRadius: rpx(29), - flexWrap: 'nowrap', // 防止换行 + flexWrap: 'nowrap', marginBottom:rpx(40), }, - timeClock:{ marginRight:rpx(14), width:rpx(26), @@ -233,47 +281,6 @@ const styles = StyleSheet.create({ timeText1:{ fontSize:rpx(24), color:'#808080', - - }, - header: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - height: rpx(88), - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: rpx(32), - backgroundColor: 'transparent', - }, - backButton: { - width: rpx(44), - height: rpx(44), - justifyContent: 'center', - alignItems: 'center', - }, - backIcon: { - width: rpx(32), - height: rpx(32), - }, - timeContainer: { - flex: 1, - alignItems: 'center', - }, - timeText: { - fontSize: rpx(28), - color: '#333333', - }, - menuButton: { - width: rpx(44), - height: rpx(44), - justifyContent: 'center', - alignItems: 'center', - }, - menuIcon: { - width: rpx(32), - height: rpx(32), }, bottomCard: { position: 'absolute',