diff --git a/package-lock.json b/package-lock.json index b64fc1a..dc183be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2302,8 +2302,7 @@ "node_modules/@eva-design/eva": { "version": "2.2.0", "resolved": "https://registry.npmmirror.com/@eva-design/eva/-/eva-2.2.0.tgz", - "integrity": "sha512-Wh98ex5cCK+YYSQNpthX1bT4CA3zDRR1WnJv0YlyvULAkmjaEvqtoGMCXzu5DH8v1fGIggu/OpAokLS7UVPe+A==", - "license": "MIT" + "integrity": "sha512-Wh98ex5cCK+YYSQNpthX1bT4CA3zDRR1WnJv0YlyvULAkmjaEvqtoGMCXzu5DH8v1fGIggu/OpAokLS7UVPe+A==" }, "node_modules/@eva-design/processor": { "version": "2.2.0", @@ -4226,7 +4225,6 @@ "version": "5.3.1", "resolved": "https://registry.npmmirror.com/@ui-kitten/components/-/components-5.3.1.tgz", "integrity": "sha512-Oj1WePUQtpNfH7ftXGdkkFVmJI+JcR3cBryPJV0E+JAUdH2dbJ0oG/VA+UAgk27/u0K0OZSUkdMFuGnkDAVuYA==", - "license": "MIT", "dependencies": { "@eva-design/dss": "^2.2.0", "@eva-design/processor": "^2.2.0", diff --git a/src/components/slider.tsx b/src/components/slider.tsx index efff8ee..b001220 100644 --- a/src/components/slider.tsx +++ b/src/components/slider.tsx @@ -1,39 +1,69 @@ import React, { useRef, useEffect, useState } from 'react'; -import { View, Text, StyleSheet, Animated, Image, PanResponder, Vibration } from 'react-native'; -import { rpx } from '../utils/rpx'; +import { View, Text, StyleSheet, Animated, Image, PanResponder, Vibration, Dimensions } from 'react-native'; -const Slider: React.FC = () => { - const translateX = useRef(new Animated.Value(0)).current; +interface SliderProps { + lockStatus?: number; + 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; const maxWidth = rpx(180); const buttonWidth = rpx(86); - const [iconOpacity, setIconOpacity] = useState(1); - const [isRight, setIsRight] = useState(false); + const [isRight, setIsRight] = useState(lockStatus === 0); const hasVibratedRef = useRef(false); + const offsetRef = useRef(0); + + // 添加监听器 + useEffect(() => { + const id = translateX.addListener(({ value }) => { + if (value >= maxWidth * 0.95) { + setIsRight(true); + } else if (value <= maxWidth * 0.05) { + setIsRight(false); + } + }); + + return () => translateX.removeListener(id); + }, []); + + const iconOpacity = translateX.interpolate({ + inputRange: [maxWidth * 0.9, maxWidth], + outputRange: [1, 0], + extrapolate: 'clamp' + }); + + const backgroundWidth = translateX.interpolate({ + inputRange: [0, maxWidth], + outputRange: [buttonWidth - rpx(2), maxWidth + buttonWidth - rpx(2)], + extrapolate: 'clamp' + }); const panResponder = useRef( PanResponder.create({ - onMoveShouldSetPanResponder: (_, gestureState) => { - return Math.abs(gestureState.dx) > 10; - }, + onStartShouldSetPanResponder: () => true, + onMoveShouldSetPanResponder: () => true, onPanResponderGrant: () => { hasVibratedRef.current = false; + offsetRef.current = translateX._value; }, onPanResponderMove: (_, gestureState) => { - const currentValue = translateX.__getValue(); let newValue; - if (isRight) { - newValue = maxWidth + gestureState.dx; + newValue = offsetRef.current + gestureState.dx; } else { - newValue = gestureState.dx; + newValue = offsetRef.current + gestureState.dx; } newValue = Math.max(0, Math.min(maxWidth, newValue)); translateX.setValue(newValue); - // 根据滑动位置更新状态 - setIsRight(newValue > maxWidth / 2); - if (!hasVibratedRef.current) { if (newValue >= maxWidth * 0.95 || newValue <= maxWidth * 0.05) { Vibration.vibrate(20); @@ -42,98 +72,86 @@ const Slider: React.FC = () => { } }, onPanResponderRelease: (_, gestureState) => { - const currentValue = translateX.__getValue(); + const currentValue = translateX._value; let toValue; + let finalIsRight; if (isRight) { if (gestureState.dx < -maxWidth / 4) { toValue = 0; - setIsRight(false); + finalIsRight = false; } else { toValue = maxWidth; - setIsRight(true); + finalIsRight = true; } } else { if (gestureState.dx > maxWidth / 4) { toValue = maxWidth; - setIsRight(true); + finalIsRight = true; } else { toValue = 0; - setIsRight(false); + finalIsRight = false; } } - Animated.spring(translateX, { + Animated.timing(translateX, { toValue, - tension: 50, - friction: 7, + duration: 100, useNativeDriver: false, }).start(() => { hasVibratedRef.current = false; + onStatusChange?.(finalIsRight); }); }, }) ).current; - const backgroundColorWidth = translateX.interpolate({ - inputRange: [0, maxWidth], - outputRange: [0, maxWidth + buttonWidth], - extrapolate: 'clamp', - }); - - useEffect(() => { - const listenerId = translateX.addListener(({ value }) => { - const newOpacity = value < maxWidth ? (1 - value / maxWidth) : 0; - setIconOpacity(newOpacity); - }); - - return () => { - translateX.removeListener(listenerId); - }; - }, [translateX]); - return ( + {/* 默认背景 */} + + + {/* 蓝色滑动背景 */} - + {/* 滑块 */} + {/* 箭头图标 */} - {isRight ? '左滑关闭' : '右滑启动'} + + {isRight ? '左滑关闭' : '右滑启动'} + ); }; @@ -153,17 +171,23 @@ const styles = StyleSheet.create({ overflow: 'hidden', }, background: { - height: '100%', - borderRadius: rpx(45), position: 'absolute', left: 0, top: 0, + height: '100%', + backgroundColor: '#4297F3', + borderRadius: rpx(45), + zIndex: 1, }, defaultBackground: { - width: rpx(268), + position: 'absolute', + left: 0, + top: 0, + width: '100%', height: '100%', backgroundColor: '#EBEBEB', borderRadius: rpx(45), + zIndex: 0, }, imageContainer: { width: rpx(86), @@ -195,4 +219,4 @@ const styles = StyleSheet.create({ }, }); -export default Slider; \ No newline at end of file +export default React.memo(Slider); \ No newline at end of file diff --git a/src/navigation/HomeStack.tsx b/src/navigation/HomeStack.tsx index 6996376..7c2e472 100644 --- a/src/navigation/HomeStack.tsx +++ b/src/navigation/HomeStack.tsx @@ -14,7 +14,7 @@ import AddShare from '../views/device/AddShare'; import ShareQrcode from '../views/device/shareQrcode'; import { getFocusedRouteNameFromRoute } from '@react-navigation/native'; import { HomeStackParamList } from './types'; - +import TestBule from '../views/device/test_bule'; const Stack = createStackNavigator(); const createScreenOptions = (title: string): StackNavigationOptions => { @@ -50,10 +50,19 @@ export default function HomeStackNavigator({ navigation, route }: Props) { headerShown: false, }} /> + (); const Tab = createBottomTabNavigator(); -// 定义需要显示绑定底部栏的路由名称 -const bindNavBarRoutes = ['BindIndex', 'SnBind', 'ConfirmBind']; +// 定义需要显示底部导航栏的路由名称 +const showTabBarRoutes = ['爱车', '个人中心']; const MainNavigator = () => { return ( @@ -30,8 +29,8 @@ const MainNavigator = () => { tabBarHideOnKeyboard: true, }} tabBar={props => { - const routeName = getFocusedRouteNameFromRoute(props.state.routes[props.state.index]) ?? 'Home'; - if (bindNavBarRoutes.includes(routeName)) { + const routeName = getFocusedRouteNameFromRoute(props.state.routes[props.state.index]) ?? '爱车'; + if (!showTabBarRoutes.includes(routeName)) { return null; } return ( diff --git a/src/navigation/types.tsx b/src/navigation/types.tsx index 99012d0..5d38714 100644 --- a/src/navigation/types.tsx +++ b/src/navigation/types.tsx @@ -27,6 +27,7 @@ export type HomeStackParamList = { DeviceShare: undefined; AddShare: undefined; ShareQrcode: undefined; + TestBule: undefined; }; // 导航属性类型 diff --git a/src/utils/api.ts b/src/utils/api.ts index 9db16f7..5630d1b 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -26,7 +26,7 @@ const api = axios.create({ api.interceptors.request.use( async (config) => { if (__DEV__) { - console.log('[Request]:', config.url, config.data); + // console.log('[Request]:', config.url, config.data); } const token = await auth.getToken(); @@ -42,7 +42,7 @@ api.interceptors.request.use( api.interceptors.response.use( response => { if (__DEV__) { - console.log('[Response]:', response.config.url, response.data); + // console.log('[Response]:', response.config.url, response.data); } const { code, msg, data } = response.data; @@ -100,5 +100,7 @@ export const apiService = { bindSn: (sn: string) => api.post('/appVerify/userBandDevice?sn=' + sn), - getDeviceList: () => api.get('/appVerify/getDeviceListByToken'), + getDeviceList: () => api.get('/appVerify/getDeviceListByMerchantToken'), + + toggleDefault: (sn: string) => api.put(`/appVerify/toggleDefault?sn=${sn}`), }; \ No newline at end of file diff --git a/src/views/Home/HomeScreen.tsx b/src/views/Home/HomeScreen.tsx index 08fe42a..1689ba3 100644 --- a/src/views/Home/HomeScreen.tsx +++ b/src/views/Home/HomeScreen.tsx @@ -37,7 +37,8 @@ const HomeScreen = () => { const fetchDeviceList = async () => { try { const response = await apiService.getDeviceList(); - if (response && response.data && response.data.length > 1) { + console.log(response.data.length,'response'); + if (response && response.data && response.data.length > 0) { setHasMultipleDevices(true); } else { setHasMultipleDevices(false); diff --git a/src/views/Home/NormaIndex.tsx b/src/views/Home/NormaIndex.tsx index b84ee89..9b66be6 100644 --- a/src/views/Home/NormaIndex.tsx +++ b/src/views/Home/NormaIndex.tsx @@ -1,14 +1,14 @@ import React, { useEffect, useState, useRef } from 'react'; -import { - View, - Text, - StyleSheet, - Image, - PanResponder, - Animated, - ScrollView, +import { + View, + Text, + StyleSheet, + Image, + PanResponder, + Animated, + ScrollView, TouchableOpacity, - TouchableWithoutFeedback , + TouchableWithoutFeedback, StatusBar } from 'react-native'; import { useNavigation } from '@react-navigation/native'; @@ -17,15 +17,26 @@ import http from '../../utils/http'; import { rpx } from '../../utils/rpx'; import Slider from '../../components/slider'; import MiniMap from './MiniMap'; - +import { apiService } from '../../utils/api'; // 定义导航参数类型 type RootStackParamList = { - Home: undefined; - DeviceList: undefined; - DeviceMap: undefined; - DeviceSet: undefined; - DeviceShare: undefined; - // 添加其他页面的路由参数类型 + Home: undefined; + DeviceList: undefined; + DeviceMap: undefined; + DeviceSet: undefined; + DeviceShare: undefined; + TestBule: undefined; + // 添加其他页面的路由参数类型 +}; +type DeviceType = { + id: number; + sn: string; + vehicleNum: string; + model: string; + remainingPower: number; + remainingMileage: number; + isDefault: number; + lockStatus: number; }; // 定义导航类型 @@ -37,7 +48,7 @@ const NormaIndex: React.FC = () => { const translateX = useRef(new Animated.Value(0)).current; const bgColor = useRef(new Animated.Value(0)).current; const navigation = useNavigation(); - + const [defaultDevice, setDefaultDevice] = useState(null); const handlePress = () => { navigation.navigate('DeviceList'); }; @@ -51,7 +62,9 @@ const NormaIndex: React.FC = () => { const toShare = () => { navigation.navigate('DeviceShare'); }; - + const toTestBule = () => { + navigation.navigate('TestBule'); + }; const panResponder = useRef( PanResponder.create({ onStartShouldSetPanResponder: () => true, @@ -102,154 +115,185 @@ const NormaIndex: React.FC = () => { }); useEffect(() => { - http.get('/app/article/9') - .then(response => { - // setData(response); - }) - .catch(error => { - console.error('请求错误', error); - }); + fetchDeviceList(); }, []); + 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)'; // 红色 + } + }; + const fetchDeviceList = async () => { + try { + 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); + } + + } + } catch (error) { + console.error('获取设备列表失败:', error); + } finally { + + } + }; return ( - - - - - - - 朵VFLU-13762 - - - - - - - - - 110 - km - - - + + + + + + {defaultDevice?.model || '未选择车辆'} + + - 剩余里程 - - - - 110 - km - - - - 剩余里程 - - - - - - - - 90% - - - - - - - 当前车辆状态:锁车 - - - - - - - - - - - - 鸣笛寻车 - - { - console.log('滑动完成'); - // 处理滑动完成后的逻辑 - }} - /> - - - 警报已开 - - - - - - - - - - - - - - - - - - - - + + + + + {defaultDevice?.remainingMileage} + km + + + + 剩余里程 + + + + + 110 + km + + + + 剩余里程 + + + + + + + + {defaultDevice?.remainingPower || 0}% + + + + + + + 当前车辆状态: {defaultDevice?.lockStatus == 1 ? '开锁' : '关锁'} + + + + + + + + + + + + + + + 鸣笛寻车 + + { + // 处理状态改变 + console.log('Lock status changed:', status); + }} + /> + + + 警报已开 + + + + + + + + + + + + + + + + + + + + + + - - + ); }; @@ -266,12 +310,12 @@ const styles = StyleSheet.create({ marginVertical: rpx(20), }, stauseText: { - fontSize: rpx(32), - color: '#3D3D3D', - textAlign: 'center', + fontSize: rpx(32), + color: '#3D3D3D', + textAlign: 'center', marginTop: rpx(24) }, - + otherSet: { marginTop: rpx(30), // display:f,\ @@ -355,14 +399,6 @@ const styles = StyleSheet.create({ borderRadius: rpx(11), backgroundColor: 'rgba(255, 130, 130, 1)', }, - eleTypeTxt: { - position: 'absolute', - top: rpx(16), - left: rpx(6), - fontSize: rpx(32), - color: '#3D3D3D', - fontWeight: 'bold' - }, eleBox: { paddingTop: rpx(14), paddingRight: rpx(6), @@ -371,29 +407,59 @@ const styles = StyleSheet.create({ width: rpx(86), height: rpx(166), borderRadius: rpx(16), - backgroundColor: '#fff' + backgroundColor: '#FFFFFF', + justifyContent: 'flex-end', + // 添加阴影效果 + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.1, + shadowRadius: 4, + elevation: 4, // Android 阴影 + // 添加边框使其更加醒目 + borderWidth: 1, + borderColor: '#E0E0E0', }, eleType: { width: '100%', - height: '100%', + minHeight: rpx(30), borderRadius: rpx(16), - backgroundColor: 'rgba(89,202,112,0.5)' + position: 'relative', + + }, + eleTypeTxt: { + position: 'absolute', + top: rpx(-40), + width: '100%', + textAlign: 'center', + fontSize: rpx(32), + color: '#3D3D3D', + // fontWeight: 'bold', + // 为文字添加阴影效果使其更清晰 + textShadowColor: 'rgba(255, 255, 255, 0.5)', + textShadowOffset: { width: 0, height: 1 }, + textShadowRadius: 2 + }, + titBox: { + flexDirection: 'row', + alignItems: 'center', + display: 'flex', + flexWrap: 'nowrap', + maxWidth: rpx(600), // 增加最大宽度 }, titTxts: { - maxWidth: rpx(480), + width: rpx(250), fontSize: rpx(48), fontWeight: '500', color: '#3D3D3D', + // flex: 2, // 添加 flex 属性 }, - titBox: { - // width: rpx(750), - flexDirection: 'row', // 添加这行 - alignItems: 'center', // 添加这行 - // // 移除这些不需要的属性 - display: 'flex', - flexWrap: 'nowrap', - // // flex: 1, - // justifyContent: 'center', + arrowIcon: { + width: rpx(24), + height: rpx(14), + marginLeft: rpx(8) }, KmLi_bot: { marginTop: rpx(4), diff --git a/src/views/ProfileScreen.jsx b/src/views/ProfileScreen.jsx index 4151e8d..e0f5b8a 100644 --- a/src/views/ProfileScreen.jsx +++ b/src/views/ProfileScreen.jsx @@ -1,63 +1,237 @@ -import React from 'react'; -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; -import { auth } from '../utils/auth'; +import React, { useState, useEffect } from 'react'; +import { + StyleSheet, + ScrollView, + Image, + View, + TouchableOpacity, + ImageBackground +} from 'react-native'; +import { Text } from '@ui-kitten/components'; import { useNavigation } from '@react-navigation/native'; -import { useAuth } from '../context/AuthContext'; // 添加这行 +import axios from 'axios'; +import { useAuth } from '../context/AuthContext'; +import { rpx } from '../utils/rpx'; +import { apiService } from '../utils/api'; const ProfileScreen = () => { const navigation = useNavigation(); - const { setIsLoggedIn } = useAuth(); // 添加这行 + const { setIsLoggedIn } = useAuth(); + const [userInfo, setUserInfo] = useState({}); - const handleLogout = async () => { + useEffect(() => { + getUserInfo(); + }, []); + + const formatName = (name) => { + if (!name) return ''; + return name.charAt(0) + '*'.repeat(name.length - 1); + }; + + const getUserInfo = async () => { try { - await auth.removeToken(); // 清除本地存储的 token - setIsLoggedIn(false); // 更新登录状态 - // 不需要手动导航,因为 AppNavigator 会根据 isLoggedIn 自动处理导航 + const response = await apiService.getUserInfo(); + if (response.code === 200) { + setUserInfo(response.user); + } } catch (error) { - console.error('退出登录失败:', error); + console.error('获取用户信息失败:', error); } }; return ( - - 个人中心 - - - 退出登录 - - + + + + {/* 头部区域 */} + + + + + + {formatName(userInfo.realName)} + + + {userInfo.phonenumber} + + + + navigation.navigate('QrBind')} + > + + + + {/* 我的设备 */} + {/* 管理与服务区域 */} + 管理与服务 + + navigation.navigate('OrderList')} + > + + 我的订单 + + + navigation.navigate('HelpCenter')} + > + + 帮助和客服 + + + navigation.navigate('Feedback')} + > + + 意见和反馈 + + + {userInfo.isAuthentication === false && ( + navigation.navigate('IdVerification')} + > + + 实名认证 + + )} + + {userInfo.userType === '02' && ( + navigation.navigate('MerchantPortal')} + > + + 商户端 + + )} + + + {/* TabBar */} + {/* + + */} + + + ); }; const styles = StyleSheet.create({ - container: { + background: { flex: 1, - alignItems: 'center', - backgroundColor: '#F3FCFF', + width: '100%', }, - title: { - fontSize: 20, - fontWeight: 'bold', - marginTop: 20, + scrollView: { + flex: 1, }, - logoutButton: { - position: 'absolute', - bottom: 40, - width: '90%', - height: 44, - backgroundColor: '#FF4D4F', - borderRadius: 22, - justifyContent: 'center', + page: { + flex: 1, + paddingTop: rpx(200), + paddingHorizontal: rpx(32), + }, + header: { + flexDirection: 'row', + justifyContent: 'space-between', alignItems: 'center', }, - logoutText: { - color: '#FFFFFF', - fontSize: 16, - fontWeight: '500', + headerLeft: { + flexDirection: 'row', + alignItems: 'center', }, + avatar: { + width: rpx(108), + height: rpx(108), + borderRadius: rpx(54), + }, + userinfo: { + marginLeft: rpx(40), + }, + username: { + fontWeight: '700', + fontSize: rpx(36), + color: '#3D3D3D', + }, + userphone: { + fontWeight: '400', + fontSize: rpx(28), + color: '#3D3D3D', + }, + headerRight: { + flexDirection: 'row', + alignItems: 'center', + }, + code: { + width: rpx(40), + height: rpx(40), + }, + tit: { + marginTop: rpx(40), + fontWeight: '700', + fontSize: rpx(36), + color: '#3D3D3D', + }, + content: { + marginTop: rpx(24), + width: rpx(688), + padding: rpx(42), + backgroundColor: '#FFFFFF', + borderRadius: rpx(30), + }, + item: { + width: '100%', + paddingVertical: rpx(34), + flexDirection: 'row', + alignItems: 'center', + borderBottomWidth: 1, + borderBottomColor: '#D8D8D8', + }, + lastItem: { + borderBottomWidth: 0, + }, + itemIcon: { + width: rpx(38), + height: rpx(38), + marginTop: rpx(4), + marginRight: rpx(34), + }, + itemText: { + fontWeight: '400', + fontSize: rpx(32), + color: '#3D3D3D', + }, + tabBarContainer: { + marginLeft: rpx(-32), + } }); export default ProfileScreen; \ No newline at end of file diff --git a/src/views/device/deviceList.tsx b/src/views/device/deviceList.tsx index 55b26d4..fad4e2b 100644 --- a/src/views/device/deviceList.tsx +++ b/src/views/device/deviceList.tsx @@ -1,225 +1,311 @@ -import React, { useState } from 'react'; -import { View, Text, StyleSheet, ScrollView, Image, TouchableOpacity } from 'react-native'; +import React, { useState, useEffect } from 'react'; +import { View, StyleSheet, ScrollView, Image, TouchableOpacity, SafeAreaView } from 'react-native'; import { useNavigation } from '@react-navigation/native'; +import { + TopNavigation, + TopNavigationAction, + Icon, + Text, + Layout, + Spinner +} from '@ui-kitten/components'; import { rpx } from '../../utils/rpx'; +import { apiService } from '../../utils/api'; type CarItem = { id: number; - title: string; + sn: string; + vehicleNum: string; model: string; - status: string; - isShared: boolean; + remainingPower: number; + remainingMileage: number; + isDefault: number; }; +const BackIcon = (props: any) => ( + +); + export default function DeviceList() { const navigation = useNavigation(); - const [selectedItem, setSelectedItem] = useState(null); - const handlePress = () => { - - navigation.navigate('BindIndex' as never); - // console.log(navigation); -}; + const [devices, setDevices] = useState([]); + const [loading, setLoading] = useState(true); -const handleCancel = () => { - navigation.goBack(); -}; + useEffect(() => { + fetchDeviceList(); + }, []); - // 示例数据保持不变 - const carList: CarItem[] = [ - - { - id: 1, - title: '备注1376', - model: '车型:飞过的魔毯不须归于温暖', - status: '车辆登入X小时出租', - isShared: false, - }, - { - id: 2, - title: '备注1376', - model: '车型:飞过的魔毯不须归于温暖', - status: '车辆登入X小时出租', - isShared: true, - }, - ]; - - const toggleSelect = (id: number) => { - setSelectedItem(prev => prev === id ? null : id); + const fetchDeviceList = async () => { + try { + setLoading(true); + const response = await apiService.getDeviceList(); + if (response?.code === 200 && response.data) { + setDevices(response.data); + } + } catch (error) { + console.error('获取设备列表失败:', error); + } finally { + setLoading(false); + } }; - const renderCarItem = (item: CarItem) => ( - + const handlePress = () => { + navigation.navigate('BindIndex' as never); + }; + + const handleCancel = () => { + navigation.goBack(); + }; + + const selectCar = async (item: CarItem) => { + try { + const response = await apiService.toggleDefault(item.sn); + if (response.code === 200) { + console.log(response,'response'); + fetchDeviceList(); + // TODO: 添加成功提示 + } + } catch (error) { + console.error('切换默认车辆失败:', error); + } + }; + + const renderBackAction = () => ( + + ); + + const renderPowerIcons = (power: number) => { + const icons = []; + const fullPowerIcon = 'https://lxnapi.ccttiot.com/bike/img/static/uhxmJlps8lrRRTmBIFpl'; + const emptyPowerIcon = 'https://lxnapi.ccttiot.com/bike/img/static/u1CcbtQydd107cOUEZ1l'; + const powerPerGrid = power / 10; + + for (let i = 0; i < 10; i++) { + icons.push( + + ); + } + return icons; + }; + + const renderCarItem = (item: CarItem, index: number) => ( + selectCar(item)} + > - {item.title} - {item.model} - {item.status} - - {item.isShared ? '临时共享' : '车主'} - + + + + {renderPowerIcons(item.remainingPower)} + + {item.remainingMileage}KM + + 车型:{item.model} + {item.vehicleNum} + 租赁中 选择车辆 - toggleSelect(item.id)} - style={styles.checkboxContainer} - > - - + - + ); return ( - - - {carList.map(item => renderCarItem(item))} - + + + + {loading ? ( + + + + ) : ( + <> + + {devices.length > 0 ? ( + devices.map((device, index) => renderCarItem(device, index)) + ) : ( + + 暂无设备数据 + + )} + - - - + 添加车辆 - - - 取消 - - - + + + + 添加车辆 + + + 取消 + + + + )} + ); } const styles = StyleSheet.create({ container: { flex: 1, - backgroundColor: '#F3FCFF', + backgroundColor: '#fff', + }, + topNav: { + backgroundColor: '#fff', + }, + loadingContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + noDataContainer: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + paddingTop: rpx(100), }, scrollContent: { - marginBottom: rpx(300), flex: 1, - paddingHorizontal: rpx(20), - // marginBottom: rpx(160), + paddingHorizontal: rpx(40), }, carItem: { flexDirection: 'row', backgroundColor: '#EEF2FD', - borderRadius: rpx(20), - padding: rpx(30), + borderRadius: rpx(28), + padding: rpx(48), marginTop: rpx(20), - alignItems: 'center', }, marginTop: { marginTop: rpx(20), }, leftContent: { flex: 1, - justifyContent: 'center', }, - rightContent: { + carInfo: { + flexDirection: 'row', alignItems: 'center', - justifyContent: 'center', - marginLeft: rpx(20), }, - title: { - fontSize: rpx(40), - fontWeight: '500', - color: '#3D3D3D', - marginBottom: rpx(16), + titleIcon: { + width: rpx(30), + height: rpx(30), + marginRight: rpx(12), + marginBottom: rpx(8), }, - subTitle: { - fontWeight: '500', - fontSize: rpx(24), + power: { + flexDirection: 'row', + alignItems: 'center', + marginRight: rpx(12), + }, + powerIcon: { + width: rpx(18), + height: rpx(36), + }, + mileage: { + fontSize: rpx(36), + fontWeight: '700', + color: '#3D3D3D', + }, + model: { + marginTop: rpx(15), + fontSize: rpx(32), + fontWeight: '700', + color: '#3D3D3D', + }, + carNum: { + marginTop: rpx(15), + fontSize: rpx(32), + fontWeight: '700', color: '#3D3D3D', - marginBottom: rpx(12), }, status: { - fontSize: rpx(24), - color: '#666', - marginBottom: rpx(16), - }, - tag: { - alignSelf: 'flex-start', - paddingVertical: rpx(6), - paddingHorizontal: rpx(30), + marginTop: rpx(20), + paddingVertical: rpx(8), + paddingHorizontal: rpx(19), backgroundColor: '#D2E8FF', borderRadius: rpx(29), - fontSize: rpx(24), + fontSize: rpx(28), color: '#4297F3', - marginTop: rpx(10), - fontWeight: '500' + alignSelf: 'flex-start', + fontWeight: '500', }, - tagShare: { - color: '#FF9500', - backgroundColor: '#FFEEDE' + rightContent: { + marginLeft: 'auto', + width: rpx(200), + alignItems: 'center', }, carImage: { - width: rpx(232), - height: rpx(180), - marginBottom: rpx(16), - }, - checkboxContainer: { - width: rpx(44), - height: rpx(44), - justifyContent: 'center', - alignItems: 'center', + width: rpx(212), + height: rpx(164), }, checkboxWrapper: { flexDirection: 'row', alignItems: 'center', + marginTop: rpx(22), }, - checkboxText: { - fontSize: rpx(32), + checkboxText: { + fontSize: rpx(30), color: '#3D3D3D', - marginRight: rpx(8), + marginRight: rpx(12), }, checkboxImage: { - width: rpx(44), - height: rpx(44), - resizeMode: 'contain', + width: rpx(29), + height: rpx(29), }, bottomButtons: { - position: 'absolute', - bottom: rpx(30), - left: 0, - right: 0, - padding: rpx(20), - backgroundColor: '#F3FCFF', + padding: rpx(38), }, addButton: { - backgroundColor: '#4297F3', height: rpx(92), - borderRadius: rpx(20), + backgroundColor: '#4297F3', + borderRadius: rpx(16), justifyContent: 'center', alignItems: 'center', marginBottom: rpx(20), }, addButtonText: { + fontSize: rpx(40), + fontWeight: '500', color: '#FFFFFF', - fontSize: rpx(32), }, cancelButton: { - backgroundColor: '#fff', height: rpx(92), - borderRadius: rpx(20), + backgroundColor: '#fff', + borderRadius: rpx(16), borderWidth: rpx(2), borderColor: '#4297F3', - justifyContent: 'center', alignItems: 'center', }, cancelButtonText: { + fontSize: rpx(40), + fontWeight: '500', color: '#4297F3', - fontSize: rpx(32), }, }); \ No newline at end of file diff --git a/src/views/device/test_bule.tsx b/src/views/device/test_bule.tsx new file mode 100644 index 0000000..8105c85 --- /dev/null +++ b/src/views/device/test_bule.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { View, StyleSheet } from 'react-native'; +import { TopNavigation, TopNavigationAction, Icon, Text } from '@ui-kitten/components'; +import { useNavigation } from '@react-navigation/native'; + +const BackIcon = (props) => ( + +); + +const TestBule = () => { + const navigation = useNavigation(); + + const navigateBack = () => { + navigation.goBack(); + }; + + const BackAction = () => ( + + ); + + return ( + + + + TestBule + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + content: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, +}); + +export default TestBule; \ No newline at end of file