311 lines
7.6 KiB
TypeScript
311 lines
7.6 KiB
TypeScript
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;
|
||
sn: string;
|
||
vehicleNum: string;
|
||
model: string;
|
||
remainingPower: number;
|
||
remainingMileage: number;
|
||
isDefault: number;
|
||
};
|
||
|
||
const BackIcon = (props: any) => (
|
||
<Icon {...props} name='arrow-back-outline'/>
|
||
);
|
||
|
||
export default function DeviceList() {
|
||
const navigation = useNavigation();
|
||
const [devices, setDevices] = useState<CarItem[]>([]);
|
||
const [loading, setLoading] = useState(true);
|
||
|
||
useEffect(() => {
|
||
fetchDeviceList();
|
||
}, []);
|
||
|
||
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 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 = () => (
|
||
<TopNavigationAction icon={BackIcon} onPress={handleCancel}/>
|
||
);
|
||
|
||
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(
|
||
<Image
|
||
key={`power-${i}`}
|
||
source={{ uri: i < Math.floor(powerPerGrid) ? fullPowerIcon : emptyPowerIcon }}
|
||
style={styles.powerIcon}
|
||
/>
|
||
);
|
||
}
|
||
return icons;
|
||
};
|
||
|
||
const renderCarItem = (item: CarItem, index: number) => (
|
||
<TouchableOpacity
|
||
key={`device-${item.sn}-${index}`}
|
||
style={[styles.carItem, index !== 0 && styles.marginTop]}
|
||
onPress={() => selectCar(item)}
|
||
>
|
||
<View style={styles.leftContent}>
|
||
<View style={styles.carInfo}>
|
||
<Image
|
||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uUIunSd0CSU3ovogLJHk' }}
|
||
style={styles.titleIcon}
|
||
/>
|
||
<View style={styles.power}>
|
||
{renderPowerIcons(item.remainingPower)}
|
||
</View>
|
||
<Text style={styles.mileage}>{item.remainingMileage}KM</Text>
|
||
</View>
|
||
<Text style={styles.model}>车型:{item.model}</Text>
|
||
<Text style={styles.carNum}>{item.vehicleNum}</Text>
|
||
<Text style={styles.status}>租赁中</Text>
|
||
</View>
|
||
<View style={styles.rightContent}>
|
||
<Image
|
||
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uB1F5aibooguILH8uB4F' }}
|
||
style={styles.carImage}
|
||
/>
|
||
<View style={styles.checkboxWrapper}>
|
||
<Text style={styles.checkboxText}>选择车辆</Text>
|
||
<Image
|
||
source={{
|
||
uri: item.isDefault == 1
|
||
? 'https://lxnapi.ccttiot.com/bike/img/static/uj7bE7GMcCm6g2igeo7k'
|
||
: 'https://lxnapi.ccttiot.com/bike/img/static/uN3QtzNuM2CMTLUm3joR'
|
||
}}
|
||
style={styles.checkboxImage}
|
||
/>
|
||
</View>
|
||
</View>
|
||
</TouchableOpacity>
|
||
);
|
||
|
||
return (
|
||
<SafeAreaView style={styles.container}>
|
||
<TopNavigation
|
||
title="选择车辆"
|
||
alignment="center"
|
||
accessoryLeft={renderBackAction}
|
||
style={styles.topNav}
|
||
/>
|
||
|
||
{loading ? (
|
||
<View style={styles.loadingContainer}>
|
||
<Spinner size="large"/>
|
||
</View>
|
||
) : (
|
||
<>
|
||
<ScrollView style={styles.scrollContent}>
|
||
{devices.length > 0 ? (
|
||
devices.map((device, index) => renderCarItem(device, index))
|
||
) : (
|
||
<View style={styles.noDataContainer}>
|
||
<Text category="s1">暂无设备数据</Text>
|
||
</View>
|
||
)}
|
||
</ScrollView>
|
||
|
||
<View style={styles.bottomButtons}>
|
||
<TouchableOpacity onPress={handlePress} style={styles.addButton}>
|
||
<Text style={styles.addButtonText}>+ 添加车辆</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity onPress={handleCancel} style={styles.cancelButton}>
|
||
<Text style={styles.cancelButtonText}>取消</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
</>
|
||
)}
|
||
</SafeAreaView>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
flex: 1,
|
||
backgroundColor: '#fff',
|
||
},
|
||
topNav: {
|
||
backgroundColor: '#fff',
|
||
},
|
||
loadingContainer: {
|
||
flex: 1,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
noDataContainer: {
|
||
flex: 1,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
paddingTop: rpx(100),
|
||
},
|
||
scrollContent: {
|
||
flex: 1,
|
||
paddingHorizontal: rpx(40),
|
||
},
|
||
carItem: {
|
||
flexDirection: 'row',
|
||
backgroundColor: '#EEF2FD',
|
||
borderRadius: rpx(28),
|
||
padding: rpx(48),
|
||
marginTop: rpx(20),
|
||
},
|
||
marginTop: {
|
||
marginTop: rpx(20),
|
||
},
|
||
leftContent: {
|
||
flex: 1,
|
||
},
|
||
carInfo: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
},
|
||
titleIcon: {
|
||
width: rpx(30),
|
||
height: rpx(30),
|
||
marginRight: rpx(12),
|
||
marginBottom: rpx(8),
|
||
},
|
||
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',
|
||
},
|
||
status: {
|
||
marginTop: rpx(20),
|
||
paddingVertical: rpx(8),
|
||
paddingHorizontal: rpx(19),
|
||
backgroundColor: '#D2E8FF',
|
||
borderRadius: rpx(29),
|
||
fontSize: rpx(28),
|
||
color: '#4297F3',
|
||
alignSelf: 'flex-start',
|
||
fontWeight: '500',
|
||
},
|
||
rightContent: {
|
||
marginLeft: 'auto',
|
||
width: rpx(200),
|
||
alignItems: 'center',
|
||
},
|
||
carImage: {
|
||
width: rpx(212),
|
||
height: rpx(164),
|
||
},
|
||
checkboxWrapper: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
marginTop: rpx(22),
|
||
},
|
||
checkboxText: {
|
||
fontSize: rpx(30),
|
||
color: '#3D3D3D',
|
||
marginRight: rpx(12),
|
||
},
|
||
checkboxImage: {
|
||
width: rpx(29),
|
||
height: rpx(29),
|
||
},
|
||
bottomButtons: {
|
||
padding: rpx(38),
|
||
},
|
||
addButton: {
|
||
height: rpx(92),
|
||
backgroundColor: '#4297F3',
|
||
borderRadius: rpx(16),
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
marginBottom: rpx(20),
|
||
},
|
||
addButtonText: {
|
||
fontSize: rpx(40),
|
||
fontWeight: '500',
|
||
color: '#FFFFFF',
|
||
},
|
||
cancelButton: {
|
||
height: rpx(92),
|
||
backgroundColor: '#fff',
|
||
borderRadius: rpx(16),
|
||
borderWidth: rpx(2),
|
||
borderColor: '#4297F3',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
},
|
||
cancelButtonText: {
|
||
fontSize: rpx(40),
|
||
fontWeight: '500',
|
||
color: '#4297F3',
|
||
},
|
||
}); |