在React Native中开发一个"保养计划"功能,你可以按照以下步骤进行:
- 确定需求
首先,明确"保养计划"功能的具体需求,例如:
- 用户可以查看车辆的保养历史记录。
- 用户可以设置下一次保养的提醒。
- 用户可以预约保养服务。
-
设计数据模型
根据需求设计数据模型,例如使用MongoDB或Firebase作为后端数据库来存储车辆信息、保养记录和预约信息。
-
搭建开发环境
确保你的开发环境已经设置好React Native和相应的后端服务。
-
创建项目结构
在React Native项目中,你可以创建以下文件和目录结构:
- components/
- MaintenanceHistory.js
- MaintenanceReminder.js
- MaintenanceBooking.js
- screens/
- MaintenanceScreen.js
- services/
- api.js
- styles/
- styles.js
- components/
-
开发前端界面
使用React Native组件来开发前端界面。例如:
MaintenanceHistory.js
jsx
import React from 'react';
import { View, Text, FlatList } from 'react-native';
import { getMaintenanceHistory } from '../services/api';
class MaintenanceHistory extends React.Component {
state = { history: [] };
componentDidMount() {
this.fetchData();
}
fetchData = async () => {
const history = await getMaintenanceHistory();
this.setState({ history });
};
renderItem = ({ item }) => (
<View>
<Text>{item.date}</Text>
<Text>{item.description}</Text>
</View>
);
render() {
return (
<FlatList data={this.state.history} renderItem={this.renderItem} />
);
}
}
export default MaintenanceHistory;
MaintenanceReminder.js 和 MaintenanceBooking.js 可以类似地开发。
- 开发后端APIs
在后端服务中创建APIs来处理数据的获取和更新。例如,使用Node.js和Express:
api.js (后端API)
javascript
const express = require('express');
const router = express.Router();
const maintenanceService = require('../services/maintenanceService'); // 假设的服务层代码
router.get('/maintenance/history', async (req, res) => {
try {
const history = await maintenanceService.getHistory();
res.json(history);
} catch (error) {
res.status(500).send(error);
}
});
// 其他APIs...
确保你的后端服务能够正确处理跨域请求(CORS)。
-
集成与测试
将前端与后端集成,进行全面的测试以确保功能的正确性。测试包括单元测试和端到端测试。
-
部署应用
将应用部署到目标平台,如Harmony或Harmony。你可以使用Expo或通过Xcode和Harmony Studio进行原生打包。
-
维护与更新
根据用户反馈进行必要的维护和功能更新。
通过以上步骤,你可以在React Native中成功开发一个"保养计划"功能。记得在开发过程中不断优化用户体验和功能完善。
真实项目案例演示效果:
js
// app.tsx
import React, { useState } from 'react';
import { SafeAreaView, View, Text, StyleSheet, TouchableOpacity, ScrollView, Modal, Alert } from 'react-native';
// Base64 图标库
const ICONS = {
car: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik01IDE4LjV2LTEuNWgydi0yaC0ydjFoLTJ2Mmg0djFoM3YxaDN2LTFoM3YtMWgydi0xaC0ydi0yaC0ydjJoLTJ2LTJoLTJ2MmgtMnYtMmgtMnYyem0xLTcuNWgydi0yaC0yeiIvPjxwYXRoIGQ9Ik0xOSA2LjVoLTIuNWwtMS43NS0xLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAxLjVIMTQuNWwtMS43NSAx......',
engine: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHptLTMtOWgyLjVWN2gydjJoMnYyaC0ydiJoLTJ2LTJoLTIuNVY5eiIvPjxwYXRoIGQ9Ik0xMiAxN2MtMi43NiAwLTUtMi4yNC01LTVzMi4yNC01IDUtNSA1IDIuMjQgNSA1LTIuMjQgNS01IDV6Ii8+PC9zdmc+',
oil: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHptLTMtOWgyLjVWN2gydjJoMnYyaC0ydiJoLTJ2LTJoLTIuNVY5eiIvPjxwYXRoIGQ9Ik0xMiAxN2MtMi43NiAwLTUtMi4yNC01LTVzMi4yNC01IDUtNSA1IDIuMjQgNSA1LTIuMjQgNS01IDV6Ii8+PC9zdmc+',
tire: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHptLTMtOWgyLjVWN2gydjJoMnYyaC0ydiJoLTJ2LTJoLTIuNVY5eiIvPjxwYXRoIGQ9Ik0xMiAxN2MtMi43NiAwLTUtMi4yNC01LTVzMi4yNC01IDUtNSA1IDIuMjQgNSA1LTIuMjQgNS01IDV6Ii8+PC9zdmc+',
battery: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHptLTMtOWgyLjVWN2gydjJoMnYyaC0ydiJoLTJ2LTJoLTIuNVY5eiIvPjxwYXRoIGQ9Ik0xMiAxN2MtMi43NiAwLTUtMi4yNC01LTVzMi4yNC01IDUtNSA1IDIuMjQgNSA1LTIuMjQgNS01IDV6Ii8+PC9zdmc+',
calendar: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xOSA0aC0xVjJoLTJ2Mkg4VjJINlY0SDVjLTEuMSAwLTIgLjktMiAydjEzYzAgMS4xLjkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJWNmMwLTEuMS0uOS0yLTItMnptMCAxNUg1VjhoMTR2MTF6bS05LTVoMlY3aC0yeiIvPjwvc3ZnPg==',
check: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik05IDE2LjE3TDQuODMgMTJsLTEuNDIgMS40MUw5IDE5IDIxIDdsLTEuNDEtMS40MXoiLz48L3N2Zz4=',
alert: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQxIDAtOC0zLjU5LTgtOHMzLjU5LTggOC04IDggMy41OSA4IDgtMy41OSA4LTggOHptLTMtOWgyLjVWN2gydjJoMnYyaC0ydiJoLTJ2LTJoLTIuNVY5eiIvPjxwYXRoIGQ9Ik0xMiAxN2MtMi43NiAwLTUtMi4yNC01LTVzMi4yNC01IDUtNSA1IDIuMjQgNSA1LTIuMjQgNS01IDV6Ii8+PC9zdmc+',
close: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xOSA2LjQxTDE3LjU5IDUgMTIgMTAuNTkgNi40MSA1IDUgNi40MSAxMC41OSAxMiA1IDE3LjU5IDYuNDEgMTkgMTIgMTMuNDEgMTcuNTkgMTkgMTkgMTcuNTkgMTMuNDEgMTJ6Ii8+PC9zdmc+'
};
// 默认保养计划数据
const DEFAULT_MAINTENANCE_PLANS = [
{
id: '1',
title: '更换机油和滤清器',
type: 'oil',
date: '2023-07-15',
mileage: '15000公里',
status: 'pending',
description: '定期更换机油和机油滤清器,保持发动机良好运转'
},
{
id: '2',
title: '检查轮胎磨损',
type: 'tire',
date: '2023-06-30',
mileage: '12000公里',
status: 'completed',
description: '检查轮胎磨损情况,必要时进行轮胎换位'
},
{
id: '3',
title: '更换空气滤清器',
type: 'engine',
date: '2023-08-20',
mileage: '20000公里',
status: 'pending',
description: '更换空气滤清器,保证进气清洁'
},
{
id: '4',
title: '检查电瓶状态',
type: 'battery',
date: '2023-07-10',
mileage: '18000公里',
status: 'overdue',
description: '检查电瓶电压和电解液水平'
}
];
const MaintenancePlanner: React.FC = () => {
const [plans, setPlans] = useState(DEFAULT_MAINTENANCE_PLANS);
const [selectedPlan, setSelectedPlan] = useState<any>(null);
const [modalVisible, setModalVisible] = useState(false);
// 获取保养类型图标
const getTypeIcon = (type: string) => {
switch (type) {
case 'car': return ICONS.car;
case 'engine': return ICONS.engine;
case 'oil': return ICONS.oil;
case 'tire': return ICONS.tire;
case 'battery': return ICONS.battery;
default: return ICONS.car;
}
};
// 获取保养类型颜色
const getTypeColor = (type: string) => {
switch (type) {
case 'car': return '#4361ee';
case 'engine': return '#3a0ca3';
case 'oil': return '#f72585';
case 'tire': return '#4cc9f0';
case 'battery': return '#2ec4b6';
default: return '#4361ee';
}
};
// 获取状态颜色
const getStatusColor = (status: string) => {
switch (status) {
case 'completed': return '#4ade80';
case 'pending': return '#facc15';
case 'overdue': return '#f87171';
default: return '#94a3b8';
}
};
// 获取状态文本
const getStatusText = (status: string) => {
switch (status) {
case 'completed': return '已完成';
case 'pending': return '待执行';
case 'overdue': return '已逾期';
default: return '未知';
}
};
// 查看保养详情
const viewPlanDetails = (plan: any) => {
setSelectedPlan(plan);
setModalVisible(true);
};
// 标记为已完成
const markAsCompleted = (id: string) => {
setPlans(plans.map(plan =>
plan.id === id ? { ...plan, status: 'completed' } : plan
));
Alert.alert('成功', '保养计划已标记为完成');
};
// 提醒设置
const setReminder = (id: string) => {
Alert.alert('提醒设置', '保养提醒已设置');
};
return (
<SafeAreaView style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>🔧 保养计划</Text>
<Text style={styles.subtitle}>爱车保养,安心出行</Text>
<View style={styles.statsContainer}>
<View style={styles.statBox}>
<Text style={styles.statNumber}>{plans.filter(p => p.status === 'pending').length}</Text>
<Text style={styles.statLabel}>待执行</Text>
</View>
<View style={styles.statBox}>
<Text style={styles.statNumber}>{plans.filter(p => p.status === 'overdue').length}</Text>
<Text style={styles.statLabel}>已逾期</Text>
</View>
</View>
</View>
<ScrollView contentContainerStyle={styles.content}>
{plans.length === 0 ? (
<View style={styles.emptyContainer}>
<Text style={styles.emptyIcon}>{decodeURIComponent(escape(atob(ICONS.car.split(',')[1])))}</Text>
<Text style={styles.emptyText}>暂无保养计划</Text>
<Text style={styles.emptySubtext}>添加您的第一个保养计划</Text>
</View>
) : (
plans.map((plan) => (
<View key={plan.id} style={styles.planCard}>
<View style={[styles.typeBadge, { backgroundColor: getTypeColor(plan.type) }]}>
<Text style={styles.typeIcon}>
{decodeURIComponent(escape(atob(getTypeIcon(plan.type).split(',')[1])))}
</Text>
</View>
<View style={styles.planHeader}>
<Text style={styles.planTitle}>{plan.title}</Text>
<View style={[styles.statusBadge, { backgroundColor: getStatusColor(plan.status) }]}>
<Text style={styles.statusText}>{getStatusText(plan.status)}</Text>
</View>
</View>
<View style={styles.planInfo}>
<View style={styles.dateRow}>
<Text style={styles.calendarIcon}>
{decodeURIComponent(escape(atob(ICONS.calendar.split(',')[1])))}
</Text>
<Text style={styles.planDate}>{plan.date}</Text>
</View>
<View style={styles.mileageRow}>
<Text style={styles.carIcon}>
{decodeURIComponent(escape(atob(ICONS.car.split(',')[1])))}
</Text>
<Text style={styles.planMileage}>{plan.mileage}</Text>
</View>
</View>
<Text style={styles.planDescription}>{plan.description}</Text>
<View style={styles.planActions}>
{plan.status !== 'completed' && (
<TouchableOpacity
style={[styles.actionButton, styles.completeButton]}
onPress={() => markAsCompleted(plan.id)}
>
<Text style={styles.checkIcon}>
{decodeURIComponent(escape(atob(ICONS.check.split(',')[1])))}
</Text>
<Text style={styles.actionText}>标记完成</Text>
</TouchableOpacity>
)}
<TouchableOpacity
style={[styles.actionButton, styles.remindButton]}
onPress={() => setReminder(plan.id)}
>
<Text style={styles.alertIcon}>
{decodeURIComponent(escape(atob(ICONS.alert.split(',')[1])))}
</Text>
<Text style={styles.actionText}>设置提醒</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.actionButton, styles.viewButton]}
onPress={() => viewPlanDetails(plan)}
>
<Text style={styles.viewButtonText}>查看详情</Text>
</TouchableOpacity>
</View>
</View>
))
)}
</ScrollView>
{/* 保养详情模态框 */}
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => setModalVisible(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}>保养详情</Text>
<TouchableOpacity onPress={() => setModalVisible(false)}>
<Text style={styles.closeButton}>×</Text>
</TouchableOpacity>
</View>
{selectedPlan && (
<View style={styles.modalBody}>
<View style={[styles.modalTypeBadge, { backgroundColor: getTypeColor(selectedPlan.type) }]}>
<Text style={styles.modalTypeIcon}>
{decodeURIComponent(escape(atob(getTypeIcon(selectedPlan.type).split(',')[1])))}
</Text>
</View>
<Text style={styles.modalTitleText}>{selectedPlan.title}</Text>
<View style={[styles.modalStatusBadge, { backgroundColor: getStatusColor(selectedPlan.status) }]}>
<Text style={styles.modalStatusText}>{getStatusText(selectedPlan.status)}</Text>
</View>
<View style={styles.modalInfoRow}>
<Text style={styles.modalLabel}>计划日期:</Text>
<Text style={styles.modalValue}>{selectedPlan.date}</Text>
</View>
<View style={styles.modalInfoRow}>
<Text style={styles.modalLabel}>行驶里程:</Text>
<Text style={styles.modalValue}>{selectedPlan.mileage}</Text>
</View>
<View style={styles.modalInfoRow}>
<Text style={styles.modalLabel}>保养说明:</Text>
<Text style={styles.modalDescription}>{selectedPlan.description}</Text>
</View>
</View>
)}
<View style={styles.modalActions}>
<TouchableOpacity
style={[styles.modalButton, styles.modalCompleteButton]}
onPress={() => {
if (selectedPlan?.status !== 'completed') {
markAsCompleted(selectedPlan?.id);
}
setModalVisible(false);
}}
>
<Text style={styles.modalButtonText}>
{selectedPlan?.status === 'completed' ? '已完成' : '标记完成'}
</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f1f5f9',
},
header: {
paddingTop: 30,
paddingBottom: 20,
paddingHorizontal: 20,
backgroundColor: '#ffffff',
borderBottomWidth: 1,
borderBottomColor: '#e2e8f0',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#1e293b',
textAlign: 'center',
},
subtitle: {
fontSize: 14,
color: '#64748b',
textAlign: 'center',
marginTop: 4,
},
statsContainer: {
flexDirection: 'row',
justifyContent: 'space-around',
marginTop: 15,
},
statBox: {
alignItems: 'center',
paddingHorizontal: 20,
paddingVertical: 10,
backgroundColor: '#f8fafc',
borderRadius: 12,
minWidth: 100,
},
statNumber: {
fontSize: 20,
fontWeight: 'bold',
color: '#1e293b',
},
statLabel: {
fontSize: 14,
color: '#64748b',
marginTop: 2,
},
content: {
padding: 16,
},
emptyContainer: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 60,
},
emptyIcon: {
fontSize: 64,
color: '#cbd5e1',
marginBottom: 20,
},
emptyText: {
fontSize: 20,
fontWeight: '600',
color: '#1e293b',
marginBottom: 8,
},
emptySubtext: {
fontSize: 16,
color: '#64748b',
},
planCard: {
backgroundColor: '#ffffff',
borderRadius: 16,
padding: 20,
marginBottom: 16,
elevation: 3,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
position: 'relative',
},
typeBadge: {
position: 'absolute',
top: -12,
right: 20,
width: 40,
height: 40,
borderRadius: 20,
alignItems: 'center',
justifyContent: 'center',
zIndex: 1,
},
typeIcon: {
fontSize: 20,
color: '#ffffff',
},
planHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start',
marginBottom: 15,
marginTop: 10,
},
planTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#1e293b',
flex: 1,
marginRight: 10,
},
statusBadge: {
paddingHorizontal: 10,
paddingVertical: 4,
borderRadius: 12,
},
statusText: {
fontSize: 12,
fontWeight: '600',
color: '#ffffff',
},
planInfo: {
marginBottom: 15,
},
dateRow: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 8,
},
calendarIcon: {
fontSize: 16,
color: '#4361ee',
marginRight: 8,
},
planDate: {
fontSize: 14,
color: '#1e293b',
},
mileageRow: {
flexDirection: 'row',
alignItems: 'center',
},
carIcon: {
fontSize: 16,
color: '#f72585',
marginRight: 8,
},
planMileage: {
fontSize: 14,
color: '#1e293b',
},
planDescription: {
fontSize: 14,
color: '#64748b',
lineHeight: 20,
marginBottom: 20,
},
planActions: {
flexDirection: 'row',
justifyContent: 'space-between',
},
actionButton: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 10,
paddingHorizontal: 15,
borderRadius: 8,
borderWidth: 1,
borderColor: '#e2e8f0',
},
completeButton: {
backgroundColor: '#dcfce7',
borderColor: '#bbf7d0',
},
remindButton: {
backgroundColor: '#fef3c7',
borderColor: '#fde68a',
},
viewButton: {
backgroundColor: '#4361ee',
borderColor: '#4361ee',
},
checkIcon: {
fontSize: 16,
color: '#16a34a',
marginRight: 6,
},
alertIcon: {
fontSize: 16,
color: '#d97706',
marginRight: 6,
},
actionText: {
fontSize: 14,
color: '#1e293b',
fontWeight: '600',
},
viewButtonText: {
color: '#ffffff',
fontWeight: '600',
},
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
},
modalContent: {
backgroundColor: '#ffffff',
width: '85%',
borderRadius: 20,
padding: 25,
maxHeight: '80%',
},
modalHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
},
modalTitle: {
fontSize: 20,
fontWeight: 'bold',
color: '#1e293b',
},
closeButton: {
fontSize: 30,
color: '#94a3b8',
fontWeight: '200',
},
modalBody: {
marginBottom: 25,
},
modalTypeBadge: {
width: 50,
height: 50,
borderRadius: 25,
alignItems: 'center',
justifyContent: 'center',
alignSelf: 'center',
marginBottom: 15,
},
modalTypeIcon: {
fontSize: 24,
color: '#ffffff',
},
modalTitleText: {
fontSize: 20,
fontWeight: 'bold',
color: '#1e293b',
textAlign: 'center',
marginBottom: 15,
},
modalStatusBadge: {
alignSelf: 'center',
paddingHorizontal: 15,
paddingVertical: 6,
borderRadius: 15,
marginBottom: 20,
},
modalStatusText: {
fontSize: 14,
fontWeight: '600',
color: '#ffffff',
},
modalInfoRow: {
flexDirection: 'row',
marginBottom: 15,
alignItems: 'flex-start',
},
modalLabel: {
fontSize: 16,
fontWeight: '600',
color: '#64748b',
width: 90,
},
modalValue: {
flex: 1,
fontSize: 16,
color: '#1e293b',
},
modalDescription: {
flex: 1,
fontSize: 16,
color: '#1e293b',
lineHeight: 22,
},
modalActions: {
flexDirection: 'row',
justifyContent: 'center',
},
modalButton: {
flex: 1,
paddingVertical: 15,
borderRadius: 12,
alignItems: 'center',
marginHorizontal: 5,
},
modalCompleteButton: {
backgroundColor: '#4ade80',
},
modalButtonText: {
fontSize: 16,
fontWeight: 'bold',
color: '#ffffff',
},
});
export default MaintenancePlanner;
这段代码实现了一个车辆保养计划管理界面,采用了React函数组件的开发模式。从鸿蒙开发的角度来看,这个组件体现了现代移动应用开发的核心理念,其设计思想和实现方式在鸿蒙应用开发中具有很好的借鉴意义。
在数据结构设计上,DEFAULT_MAINTENANCE_PLANS数组通过ID、标题、类型、日期、里程、状态和描述等属性来描述保养计划。这种数据模型设计在鸿蒙开发中同样适用,鸿蒙的ArkTS语言支持类似的对象数组结构,可以通过定义interface接口来规范数据结构,确保类型安全和数据一致性。鸿蒙应用中推荐使用资源管理机制来处理图标和颜色,将资源文件放置在对应的资源目录中,通过$r('app.media.icon_name')的方式进行引用,这样更符合鸿蒙的设计规范。
状态管理方面,React使用useState来维护组件的内部状态,包括保养计划列表数据、选中的保养计划和模态框显示状态。在鸿蒙开发中,可以使用@State装饰器来实现类似的状态管理机制,通过状态变量的变化来驱动UI的自动更新。鸿蒙的声明式UI框架具有高效的渲染机制,能够通过状态变化自动计算最小渲染代价来更新界面元素,这与React的状态驱动理念是一致的。
UI布局采用了卡片列表的设计模式,通过ScrollView容器来展示保养计划卡片。在鸿蒙开发中,可以使用Column和Row组合配合ForEach循环渲染来实现类似的列表布局效果。每个保养计划卡片包含了类型标识、标题信息、状态标签、时间信息和操作按钮等多个功能区域,这种模块化的设计便于维护和功能扩展。
在图标和颜色处理方面,代码通过getTypeIcon、getTypeColor、getStatusColor等函数根据保养类型和状态动态选择不同的图标和颜色。这种动态绑定的设计在鸿蒙应用中同样重要,可以通过条件渲染或者资源绑定的方式实现类似功能。鸿蒙支持通过资源文件统一管理颜色值,在不同主题模式下自动适配颜色,确保应用在各种环境下都有良好的视觉效果。
模态框的实现体现了良好的用户体验设计,通过遮罩层来突出操作焦点,这种交互模式在鸿蒙系统中同样适用。鸿蒙提供了丰富的弹窗组件和动画API,可以实现更加流畅和原生的用户交互体验。保养详情查看功能可以通过鸿蒙的Sheet组件或者自定义弹窗来实现,提供更加丰富的信息展示。
状态管理通过不同的颜色和文本标签来区分待执行、已完成和已逾期三种状态,这种可视化设计在鸿蒙应用中同样重要。鸿蒙支持通过条件渲染来实现不同的状态展示,同时可以利用系统的主题色和动画效果来增强用户体验。
打包
接下来通过打包命令npn run harmony将reactNative的代码打包成为bundle,这样可以进行在开源鸿蒙OpenHarmony中进行使用。

打包之后再将打包后的鸿蒙OpenHarmony文件拷贝到鸿蒙的DevEco-Studio工程目录去:

最后运行效果图如下显示: