欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

在这里插入图片描述

📌 概述

行程规划功能允许用户为旅行创建详细的日程安排。用户可以为每一天添加活动、景点、餐厅等信息,形成完整的行程计划。行程规划提供了日历视图和列表视图,用户可以灵活地查看和编辑行程。在 Cordova 与 OpenHarmony 的混合开发框架中,行程规划需要实现日程管理和日历展示功能。

🔗 完整流程

第一步:日程数据模型设计

行程规划需要为每一天的活动创建数据模型。每个活动包括时间、地点、描述、类型等信息。活动需要与旅行关联,一个旅行可以有多个活动。

第二步:日程列表与日历展示

行程规划页面需要提供两种视图:列表视图和日历视图。列表视图按时间顺序展示所有活动,日历视图在日历上标记有活动的日期。

第三步:原生层日历集成与提醒

OpenHarmony 原生层可以集成系统日历,将行程同步到系统日历。原生层还可以实现行程提醒功能,在活动开始前通知用户。

🔧 Web 代码实现

行程规划页面 HTML 结构

<div id="itinerary-page" class="page">
    <div class="page-header">
        <h1>行程规划</h1>
        <button class="btn btn-primary" onclick="openActivityModal()">
            ➕ 添加活动
        </button>
    </div>
    
    <div class="itinerary-container">
        <div class="view-toggle">
            <button class="btn-toggle active" onclick="switchView('list')">列表视图</button>
            <button class="btn-toggle" onclick="switchView('calendar')">日历视图</button>
        </div>
        
        <div id="listView" class="itinerary-list">
            <!-- 活动列表动态加载 -->
        </div>
        
        <div id="calendarView" class="itinerary-calendar" style="display: none;">
            <!-- 日历视图动态加载 -->
        </div>
    </div>
</div>

HTML 结构包含列表视图和日历视图的切换。

加载行程函数

async function loadItinerary(tripId) {
    try {
        // 获取旅行数据
        const trip = await db.getTrip(tripId);
        
        // 获取所有活动
        const activities = await db.getActivitiesByTrip(tripId);
        
        // 按日期排序
        activities.sort((a, b) => new Date(a.date) - new Date(b.date));
        
        // 渲染列表视图
        renderActivityList(activities, trip);
        
        // 渲染日历视图
        renderCalendarView(activities, trip);
    } catch (error) {
        console.error('Error loading itinerary:', error);
        showToast('加载行程失败');
    }
}

这个函数加载旅行的所有活动,然后渲染两种视图。loadItinerary 函数是行程规划的核心加载函数。函数首先从数据库获取旅行数据,然后获取该旅行的所有活动。接着按照活动的日期进行排序,确保活动按时间顺序显示。然后调用 renderActivityList 函数渲染列表视图,用户可以看到按日期分组的所有活动。同时调用 renderCalendarView 函数渲染日历视图,用户可以在日历上看到有活动的日期。这种双视图设计提供了灵活的查看方式,用户可以根据需要选择合适的视图。通过这个函数,用户可以全面了解旅行的行程安排。

活动列表渲染函数

function renderActivityList(activities, trip) {
    const container = document.getElementById('listView');
    container.innerHTML = '';
    
    // 按日期分组
    const groupedActivities = {};
    activities.forEach(activity => {
        const date = activity.date;
        if (!groupedActivities[date]) {
            groupedActivities[date] = [];
        }
        groupedActivities[date].push(activity);
    });
    
    // 渲染每一天的活动
    Object.keys(groupedActivities).sort().forEach(date => {
        const dayActivities = groupedActivities[date];
        
        const dayElement = document.createElement('div');
        dayElement.className = 'day-activities';
        dayElement.innerHTML = `<h3>${formatDate(date)}</h3>`;
        
        dayActivities.forEach(activity => {
            const activityElement = document.createElement('div');
            activityElement.className = 'activity-item';
            activityElement.innerHTML = `
                <div class="activity-time">${activity.time || '全天'}</div>
                <div class="activity-content">
                    <h4>${activity.title}</h4>
                    <p>${activity.description || ''}</p>
                    <span class="activity-location">📍 ${activity.location || '未设置'}</span>
                </div>
                <div class="activity-actions">
                    <button class="btn-small" onclick="editActivity(${activity.id})">编辑</button>
                    <button class="btn-small btn-danger" onclick="deleteActivity(${activity.id})">删除</button>
                </div>
            `;
            dayElement.appendChild(activityElement);
        });
        
        container.appendChild(dayElement);
    });
}

活动列表渲染函数按日期分组展示所有活动。

保存活动函数

async function saveActivity(activityData) {
    try {
        // 验证数据
        if (!activityData.title || activityData.title.trim() === '') {
            showToast('活动标题不能为空');
            return;
        }
        
        // 创建活动对象
        const activity = {
            id: activityData.id || Date.now(),
            tripId: activityData.tripId,
            title: activityData.title,
            description: activityData.description,
            date: activityData.date,
            time: activityData.time,
            location: activityData.location,
            type: activityData.type,
            createdAt: activityData.createdAt || new Date().toISOString(),
            updatedAt: new Date().toISOString()
        };
        
        // 保存到数据库
        if (activityData.id) {
            await db.updateActivity(activity);
            showToast('活动已更新');
        } else {
            await db.addActivity(activity);
            showToast('活动已添加');
        }
        
        // 关闭模态框
        closeModal();
        
        // 重新加载行程
        loadItinerary(activity.tripId);
        
        // 通知原生层
        if (window.cordova) {
            cordova.exec(
                (result) => console.log('Activity saved:', result),
                (error) => console.error('Save error:', error),
                'ItineraryPlugin',
                'onActivitySaved',
                [{ activityId: activity.id, tripId: activity.tripId, timestamp: Date.now() }]
            );
        }
    } catch (error) {
        console.error('Error saving activity:', error);
        showToast('保存失败,请重试');
    }
}

保存活动函数创建或更新活动,然后保存到数据库。

日历视图渲染函数

function renderCalendarView(activities, trip) {
    const container = document.getElementById('calendarView');
    container.innerHTML = '';
    
    // 获取旅行的日期范围
    const startDate = new Date(trip.startDate);
    const endDate = new Date(trip.endDate);
    
    // 创建日历
    const calendar = document.createElement('div');
    calendar.className = 'calendar';
    
    // 获取有活动的日期
    const activityDates = new Set(activities.map(a => a.date));
    
    // 遍历每一天
    let currentDate = new Date(startDate);
    while (currentDate <= endDate) {
        const dateStr = currentDate.toISOString().split('T')[0];
        const dayElement = document.createElement('div');
        dayElement.className = 'calendar-day';
        
        if (activityDates.has(dateStr)) {
            dayElement.classList.add('has-activity');
        }
        
        dayElement.innerHTML = `
            <div class="day-number">${currentDate.getDate()}</div>
            <div class="day-activities-count">
                ${activities.filter(a => a.date === dateStr).length}
            </div>
        `;
        
        calendar.appendChild(dayElement);
        currentDate.setDate(currentDate.getDate() + 1);
    }
    
    container.appendChild(calendar);
}

日历视图渲染函数在日历上标记有活动的日期。

🔌 OpenHarmony 原生代码实现

行程规划插件

// ItineraryPlugin.ets
import { BusinessError } from '@ohos.base';

export class ItineraryPlugin {
    // 处理活动保存事件
    onActivitySaved(args: any, callback: Function): void {
        try {
            const activityId = args[0].activityId;
            const tripId = args[0].tripId;
            const timestamp = args[0].timestamp;
            
            console.log(`[Itinerary] Activity saved: ${activityId} for trip ${tripId}`);
            
            callback({ success: true, message: '活动已保存' });
        } catch (error) {
            callback({ success: false, error: error.message });
        }
    }
    
    // 设置活动提醒
    setActivityReminder(args: any, callback: Function): void {
        try {
            const activityId = args[0].activityId;
            const reminderTime = args[0].reminderTime;
            
            console.log(`[Itinerary] Reminder set for activity ${activityId}`);
            
            callback({ success: true, message: '提醒已设置' });
        } catch (error) {
            callback({ success: false, error: error.message });
        }
    }
}

行程规划插件处理活动保存和提醒设置。

📝 总结

行程规划功能展示了如何在 Cordova 与 OpenHarmony 框架中实现一个完整的日程管理系统。Web 层负责 UI 渲染和日程操作,原生层负责提醒管理。通过行程规划,用户可以详细规划旅行的每一天。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐