细节修改

This commit is contained in:
tx 2024-12-30 13:47:31 +08:00
parent e54344328f
commit c2e52df560
8 changed files with 145 additions and 173 deletions

View File

@ -58,7 +58,7 @@ const DeviceControl: React.FC<DeviceControlProps> = ({ defaultDevice, onDeviceUp
try {
setIsConnecting(true);
showWithAnimation();
const targetMac = 'FD51BB7A4EE0'; // 暂时使用固定MAC
const targetMac = defaultDevice?.mac// 暂时使用固定MAC
console.log(`${isRetry ? '重试' : '开始'}连接设备, 目标MAC:`, targetMac);
const initialized = await BluetoothManager.init();
@ -165,27 +165,27 @@ const DeviceControl: React.FC<DeviceControlProps> = ({ defaultDevice, onDeviceUp
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(); // 蓝牙操作成功后调用更新
}
@ -199,7 +199,7 @@ const DeviceControl: React.FC<DeviceControlProps> = ({ defaultDevice, onDeviceUp
} else {
// API 调用成功,直接更新状态
if (onDeviceUpdate) {
onDeviceUpdate();
onDeviceUpdate();
}
}
};
@ -213,6 +213,19 @@ const DeviceControl: React.FC<DeviceControlProps> = ({ defaultDevice, onDeviceUp
return 'rgba(255, 69, 58, 0.5)';
}
};
const calculateTimeRemaining = (expirationTime: string): string => {
const expiration = new Date(expirationTime).getTime();
const now = new Date().getTime();
const diff = expiration - now;
if (diff <= 0) return '已过期';
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
return `${days}${hours}小时${minutes}`;
};
useEffect(() => {
const removeListener = BluetoothManager.addConnectionStateListener((state) => {
@ -253,6 +266,13 @@ const DeviceControl: React.FC<DeviceControlProps> = ({ defaultDevice, onDeviceUp
<View style={styles.yuan}></View>
<Text style={styles.txt}> {defaultDevice?.lockStatus == 1 ? '开锁' : '关锁'}</Text>
</View>
{defaultDevice?.type == 2 && defaultDevice?.expirationTime && (
<View style={styles.txtbox1}>
<Text style={styles.txt1}>
{calculateTimeRemaining(defaultDevice.expirationTime)}
</Text>
</View>
)}
</View>
{showBluetoothStatus && (
<Animated.View
@ -382,6 +402,19 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
},
txtbox1: {
marginTop: rpx(10),
width: rpx(440),
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
},
txt1: {
marginLeft: rpx(14),
fontSize: rpx(32),
fontWeight: '400',
color: '#3D3D3D',
},
txt: {
marginLeft: rpx(14),
fontSize: rpx(28),

View File

@ -131,17 +131,17 @@ const NormaIndex: React.FC = () => {
};
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) {
setDefaultDevice(defaultDev);
// 存储设备 sn 到本地存储
}
}
};
@ -149,11 +149,11 @@ const NormaIndex: React.FC = () => {
try {
const response = await apiService.getDeviceList();
console.log(response,'response');
console.log(response, 'response');
if (response?.code === 200 && response.data) {
const defaultDev = response.data.find((device: DeviceType) => device.isDefault == 1);
if (defaultDev) {
console.log(defaultDev.sn,'defaultDev.sn');
console.log(defaultDev.sn, 'defaultDev.sn');
await AsyncStorage.setItem('defaultDeviceSN', defaultDev.sn);
// console.log(defaultDev, 'defaultDev');
setDefaultDevice(defaultDev);
@ -223,96 +223,39 @@ const NormaIndex: React.FC = () => {
</View>
</View>
</View>
<DeviceControl defaultDevice={defaultDevice} onDeviceUpdate={handleDeviceUpdate}/>
{/* <View style={styles.infoBox}>
<View style={styles.eleBox}>
<View style={[
styles.eleType,
{
height: `${defaultDevice?.remainingPower || 0}%`,
backgroundColor: getPowerColor(defaultDevice?.remainingPower || 0)
}
]}>
<Text style={styles.eleTypeTxt}>{defaultDevice?.remainingPower || 0}%</Text>
</View>
</View>
<View style={styles.carBox}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
style={{ width: rpx(440), height: rpx(340) }}
/>
<View style={styles.txtbox}>
<View style={styles.yuan}></View>
<Text style={styles.txt}> {defaultDevice?.lockStatus == 1 ? '开锁' : '关锁'}</Text>
</View>
</View>
<TouchableOpacity onPress={toTestBule}>
<View style={styles.Bind_type}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uQdjlI2DLfXmABfynycn' }}
style={{ width: rpx(32), height: rpx(32) }}
/>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uLizPj6UxdjBsiqhxZB8' }}
style={{ width: rpx(60), height: rpx(60), marginLeft: 'auto' }}
/>
</View>
</TouchableOpacity>
</View>
<View style={styles.car_stause_box}>
<View style={styles.car_stause_li}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uro1vIU1WydjNWgi7PUg' }}
style={{ width: rpx(90), height: rpx(90), marginLeft: rpx(18) }}
/>
<Text style={styles.stauseText}></Text>
</View>
<Slider
lockStatus={defaultDevice?.lockStatus}
onStatusChange={(status) => {
// 处理状态改变
console.log('Lock status changed:', status);
}}
/>
<View style={styles.car_stause_li}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uVpJNxwWXlyXt4IdHQoe' }}
style={{ width: rpx(90), height: rpx(90), marginLeft: rpx(18) }}
/>
<Text style={styles.stauseText}></Text>
</View>
</View> */}
<TouchableWithoutFeedback >
<DeviceControl defaultDevice={defaultDevice} onDeviceUpdate={handleDeviceUpdate} />
<TouchableWithoutFeedback>
<View style={styles.mapWrapper}>
<MiniMap defaultDevice={defaultDevice}/>
<MiniMap defaultDevice={defaultDevice} />
</View>
</TouchableWithoutFeedback>
{defaultDevice?.type == 1 && (
<>
<TouchableOpacity onPress={toSet}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/ucYQHQ2Ep4odL8JpbtfT' }}
style={styles.carSet}
/>
</TouchableOpacity>
<View style={styles.otherSet}>
<TouchableOpacity onPress={toShare}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/ulDHhC4MrH3FO0AeTqVg' }}
style={styles.otherImg}
/>
</TouchableOpacity>
<TouchableOpacity onPress={toSet}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/ucYQHQ2Ep4odL8JpbtfT' }}
style={styles.carSet}
/>
</TouchableOpacity>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u849NsNxdtzxhUkUJnfW' }}
style={styles.otherImg}
/>
</View>
<View style={styles.otherSet}>
<TouchableOpacity onPress={toShare}>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/ulDHhC4MrH3FO0AeTqVg' }}
style={styles.otherImg}
/>
</TouchableOpacity>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/u849NsNxdtzxhUkUJnfW' }}
style={styles.otherImg}
/>
</View>
</>
)}
</View>
</ScrollView>
</View>

View File

@ -76,7 +76,7 @@ const ProfileScreen = () => {
</View>
<TouchableOpacity
style={styles.headerRight}
onPress={() => navigation.navigate('QrBind')}
onPress={() => navigation.navigate('BindIndex')}
>
<Image
source={{ uri: 'https://lxnapi.ccttiot.com/bike/img/static/uyb0iFo50FJ0MZg3RKkV' }}
@ -88,7 +88,7 @@ const ProfileScreen = () => {
{/* 管理与服务区域 */}
<Text style={styles.tit}>管理与服务</Text>
<View style={styles.content}>
<TouchableOpacity
{/* <TouchableOpacity
style={styles.item}
onPress={() => navigation.navigate('OrderList')}
>
@ -97,7 +97,7 @@ const ProfileScreen = () => {
style={styles.itemIcon}
/>
<Text style={styles.itemText}>我的订单</Text>
</TouchableOpacity>
</TouchableOpacity> */}
<TouchableOpacity
style={styles.item}
@ -134,7 +134,7 @@ const ProfileScreen = () => {
</TouchableOpacity>
)}
{userInfo.userType === '02' && (
{/* {userInfo.userType === '02' && (
<TouchableOpacity
style={[styles.item, styles.lastItem]}
onPress={() => navigation.navigate('MerchantPortal')}
@ -145,7 +145,7 @@ const ProfileScreen = () => {
/>
<Text style={styles.itemText}>商户端</Text>
</TouchableOpacity>
)}
)} */}
</View>
{/* 退出登录按钮 */}

View File

@ -19,6 +19,7 @@ const DeviceShare = () => {
const getKeyList = async () => {
const response = await apiService.getKeyListByOwnerId();
console.log('response', response);
if (response.code == 200) {
setKeyList(response.data);
}
@ -47,12 +48,13 @@ const DeviceShare = () => {
};
const getStatusText = (status: string | number) => {
console.log('status', status);
switch (status) {
case '0':
case 0:
return '待领取';
case '1':
case 1:
case '2':
case 2:
return '已领取';
default:
return '未知状态';

View File

@ -95,7 +95,7 @@ const KeyDetail = () => {
const handleTimeSelect = async (time: string) => {
setSelectedTime(time);
if (!keyItem) return;
let days = 0;
@ -105,14 +105,16 @@ const KeyDetail = () => {
case '30天': days = 30; break;
case '永久': days = 36500; break;
}
const baseDate = new Date(keyItem.createTime);
const newExpirationDate = new Date(baseDate.getTime() + days * 24 * 60 * 60 * 1000);
// 使用当前时间作为基准
const now = new Date();
const newExpirationDate = new Date(now.getTime() + days * 24 * 60 * 60 * 1000);
// 设置为当天的最后一秒
newExpirationDate.setHours(23);
newExpirationDate.setMinutes(59);
newExpirationDate.setSeconds(59);
const formattedDate = newExpirationDate.getFullYear() + '-' +
String(newExpirationDate.getMonth() + 1).padStart(2, '0') + '-' +
String(newExpirationDate.getDate()).padStart(2, '0') + ' ' +
@ -132,7 +134,6 @@ const KeyDetail = () => {
type: 'success',
text1: '更新成功',
});
// 更新成功后重新获取钥匙信息
await fetchKeyInfo();
} else {
Toast.show({
@ -184,6 +185,7 @@ const KeyDetail = () => {
navigation.navigate('ShareQrcode', { QrId: keyId });
};
return (
<Layout style={styles.container}>
<TopNavigation
@ -193,36 +195,41 @@ const KeyDetail = () => {
style={styles.topNav}
/>
<Layout style={styles.header}>
<Avatar
style={styles.avatar}
size="giant"
source={{ uri: keyItem.avatarUrl || 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
/>
<Text style={styles.name}>{keyItem.shareUserName}</Text>
<Text style={styles.phone}>{keyItem.sharePhone}</Text>
<Text style={styles.expireTime}>{calculateRemainingTime(keyItem.expirationTime)}</Text>
<TouchableOpacity style={styles.eidtBtn} onPress={() => setShowTimeModal(true)}>
<View style={styles.editBtnContent}>
<Text style={styles.editBtnText}></Text>
<Icon name='arrow-ios-forward-outline' style={styles.arrowIcon} />
</View>
</TouchableOpacity>
<TouchableOpacity style={styles.deleteBtn} onPress={showDeleteModal}>
<Text style={styles.deleteText}></Text>
</TouchableOpacity>
</Layout>
<Layout style={styles.actionContainer}>
<Button
appearance='ghost'
style={styles.actionButton}
accessoryRight={RightIcon}
onPress={toQrCode}
>
{evaProps => <Text {...evaProps} style={styles.buttonText}></Text>}
</Button>
</Layout>
{keyItem && ( // 添加条件渲染检查
<>
<Layout style={styles.header}>
<Avatar
style={styles.avatar}
size="giant"
source={{ uri: keyItem.avatarUrl || 'https://lxnapi.ccttiot.com/bike/img/static/uVnIDwcwQP7oo12PeYVJ' }}
/>
<Text style={styles.name}>{keyItem.shareUserName}</Text>
<Text style={styles.phone}>{keyItem.sharePhone}</Text>
<Text style={styles.expireTime}>{calculateRemainingTime(keyItem.expirationTime)}</Text>
<TouchableOpacity style={styles.eidtBtn} onPress={() => setShowTimeModal(true)}>
<View style={styles.editBtnContent}>
<Text style={styles.editBtnText}></Text>
<Icon name='arrow-ios-forward-outline' style={styles.arrowIcon} />
</View>
</TouchableOpacity>
<TouchableOpacity style={styles.deleteBtn} onPress={showDeleteModal}>
<Text style={styles.deleteText}></Text>
</TouchableOpacity>
</Layout>
<Layout style={styles.actionContainer}>
<Button
appearance='ghost'
style={styles.actionButton}
accessoryRight={RightIcon}
onPress={toQrCode}
>
{evaProps => <Text {...evaProps} style={styles.buttonText}></Text>}
</Button>
</Layout>
</>
)}
{/* 删除确认弹窗 */}
<Modal

View File

View File

@ -111,7 +111,7 @@ export default function DeviceList() {
</View>
<Text style={styles.model}>{item.model}</Text>
<Text style={styles.carNum}>{item.vehicleNum}</Text>
<Text style={styles.status}></Text>
<Text style={styles.status}>{item.type == 1 ? '车主' : '临时租赁'}</Text>
</View>
<View style={styles.rightContent}>
<Image

View File

@ -58,55 +58,40 @@ const DeviceMap = () => {
};
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;
}
// 移除原有的检查,因为 userLocation 可能还未获取到
try {
// 使用 setStatus 方法移动地图
if (mapRef.current) {
if (mapRef.current && userLocation) {
mapRef.current.moveCamera({
target: userLocation,
zoom: 15,
}, 1000);
} else {
// 如果还没有获取到位置,等待位置信息
console.log('等待获取用户位置...');
}
} catch (error) {
console.error('移动地图失败:', error);
}
};
useEffect(() => {
getCurrentLocation();
getDeviceLocation();
useEffect(() => {
// 先获取位置,再调用 getCurrentLocation
const watchId = Geolocation.watchPosition(
(position) => {
const gcjLocation = transformFromWGSToGCJ(
position.coords.latitude,
position.coords.longitude
);
console.log(gcjLocation,'gcjLocation');
setUserLocation(gcjLocation);
// 位置获取成功后自动移动地图
if (mapRef.current) {
mapRef.current.moveCamera({
target: gcjLocation,
zoom: 15,
}, 1000);
}
},
(error) => {
console.error('位置监听错误:', error);
@ -118,7 +103,9 @@ const DeviceMap = () => {
distanceFilter: 10
}
);
getDeviceLocation();
return () => {
Geolocation.clearWatch(watchId);
};