在这里插入图片描述

📌 模块概述

活动记录功能为用户提供全维度的操作追踪能力,在基础操作记录的基础上,新增操作类型分类、时间筛选、记录搜索、批量管理、操作溯源等实用功能,帮助用户清晰追溯笔记的创建、编辑、删除等所有操作行为,同时支持记录的筛选和清理,提升操作日志的实用性。

🔗 完整流程

第一步:精细化记录活动

记录操作类型(创建 / 编辑 / 删除 / 导入 / 导出 / 同步等)、操作对象、操作结果;
补充设备信息、操作 IP(可选)等溯源数据,完善记录维度。

第二步:结构化存储活动

按时间分片存储记录,避免单文件过大;
支持记录的持久化存储,可配置保留时长。

第三步:多维度展示与管理

按时间 / 类型筛选记录,支持关键词搜索;
展示操作记录详情,支持批量删除 / 清空记录;
对敏感操作(如删除)进行醒目标识

🔧 Web代码实现

// 活动记录页面(扩展版)
async renderActivity() {
  const activities = await noteDB.getAllActivities();
  // 按时间降序排序
  const sortedActivities = activities.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
  
  // 提取所有操作类型用于筛选
  const activityTypes = [...new Set(sortedActivities.map(act => act.type))];

  return `
    <div class="page active">
      <div class="page-header">
        <h1 class="page-title">📅 活动记录</h1>
      </div>
      
      <!-- 新增:筛选和搜索功能 -->
      <div class="activity-filter" style="margin: 16px 0;">
        <select id="activity-type-filter" class="form-control" onchange="app.filterActivities()">
          <option value="all">所有操作类型</option>
          ${activityTypes.map(type => `<option value="${type}">${type}</option>`).join('')}
        </select>
        <input type="search" id="activity-search" class="form-control" 
               placeholder="搜索操作描述..." style="margin-top: 8px;"
               oninput="app.filterActivities()">
        <div class="activity-actions" style="margin-top: 8px; display: flex; gap: 8px;">
          <button class="btn btn-outline" onclick="app.clearAllActivities()">清空记录</button>
          <button class="btn btn-outline" onclick="app.exportActivities()">导出记录</button>
        </div>
      </div>

      <!-- 活动记录列表 -->
      <div class="activity-list" id="activity-list">
        ${sortedActivities.map(activity => {
          // 新增:为不同操作类型添加样式标识
          const typeClass = {
            '删除': 'activity-delete',
            '创建': 'activity-create',
            '编辑': 'activity-edit',
            '导入': 'activity-import',
            '导出': 'activity-export',
            '同步': 'activity-sync'
          }[activity.type] || 'activity-default';
          
          return `
            <div class="activity-item ${typeClass}">
              <div class="activity-header">
                <span class="activity-type">${activity.type}</span>
                <span class="activity-time">${Utils.formatDate(activity.createdAt)}</span>
                <!-- 新增:设备信息展示 -->
                <span class="activity-device">${activity.device || '未知设备'}</span>
              </div>
              <div class="activity-description">${activity.description}</div>
              <!-- 新增:操作ID和快捷操作 -->
              <div class="activity-footer">
                <span class="activity-id">ID: ${activity.id}</span>
                <button class="btn btn-text" onclick="app.deleteSingleActivity(${activity.id})">删除</button>
              </div>
            </div>
          `;
        }).join('') || '<div class="empty-state">暂无活动记录</div>'}
      </div>
    </div>
  `;
}

// 记录活动(扩展版)
async recordActivity(type, description, extra = {}) {
  try {
    // 新增:获取设备信息(调用原生能力)
    const deviceInfo = await new Promise(resolve => {
      cordova.exec(resolve, () => resolve('未知设备'), 'activityPlugin', 'getDeviceInfo', []);
    });
    
    const activity = {
      id: Date.now(),
      type: type,
      description: description,
      createdAt: new Date().toISOString(),
      device: deviceInfo,
      // 新增:支持扩展字段
      ...extra
    };

    await noteDB.addActivity(activity);
    // 可选:超过1000条记录时自动清理最早的记录
    await this.cleanOldActivities(1000);
  } catch (error) {
    console.error('记录活动失败:', error);
  }
}

// 新增:筛选活动记录
async filterActivities() {
  try {
    const typeFilter = document.getElementById('activity-type-filter').value;
    const searchText = document.getElementById('activity-search').value.toLowerCase();
    const activities = await noteDB.getAllActivities();
    
    let filtered = activities;
    // 按类型筛选
    if (typeFilter !== 'all') {
      filtered = filtered.filter(act => act.type === typeFilter);
    }
    // 按关键词搜索
    if (searchText) {
      filtered = filtered.filter(act => 
        act.description.toLowerCase().includes(searchText) || 
        act.type.toLowerCase().includes(searchText)
      );
    }
    // 按时间降序排序
    filtered.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
    
    // 更新列表DOM
    const listContainer = document.getElementById('activity-list');
    listContainer.innerHTML = filtered.map(activity => {
      const typeClass = {
        '删除': 'activity-delete',
        '创建': 'activity-create',
        '编辑': 'activity-edit'
      }[activity.type] || 'activity-default';
      return `
        <div class="activity-item ${typeClass}">
          <div class="activity-header">
            <span class="activity-type">${activity.type}</span>
            <span class="activity-time">${Utils.formatDate(activity.createdAt)}</span>
            <span class="activity-device">${activity.device || '未知设备'}</span>
          </div>
          <div class="activity-description">${activity.description}</div>
          <div class="activity-footer">
            <span class="activity-id">ID: ${activity.id}</span>
            <button class="btn btn-text" onclick="app.deleteSingleActivity(${activity.id})">删除</button>
          </div>
        </div>
      `;
    }).join('') || '<div class="empty-state">暂无符合条件的记录</div>';
  } catch (error) {
    console.error('筛选活动记录失败:', error);
    Utils.showToast('筛选失败,请重试', 'error');
  }
}

// 新增:删除单条记录
async deleteSingleActivity(activityId) {
  if (confirm('确定删除这条活动记录吗?')) {
    try {
      await noteDB.deleteActivity(activityId);
      Utils.showToast('记录已删除', 'success');
      await this.renderActivity(); // 刷新页面
    } catch (error) {
      console.error('删除记录失败:', error);
      Utils.showToast('删除失败,请重试', 'error');
    }
  }
}

// 新增:清空所有记录
async clearAllActivities() {
  if (confirm('确定清空所有活动记录吗?此操作不可恢复!')) {
    try {
      await noteDB.clearAllActivities();
      Utils.showToast('所有记录已清空', 'success');
      await this.renderActivity(); // 刷新页面
    } catch (error) {
      console.error('清空记录失败:', error);
      Utils.showToast('清空失败,请重试', 'error');
    }
  }
}

// 新增:导出活动记录
async exportActivities() {
  try {
    const activities = await noteDB.getAllActivities();
    const content = JSON.stringify(activities, null, 2);
    const blob = new Blob([content], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `activity_logs_${Date.now()}.json`;
    a.click();
    URL.revokeObjectURL(url);
    Utils.showToast('活动记录导出成功', 'success');
  } catch (error) {
    console.error('导出记录失败:', error);
    Utils.showToast('导出失败,请重试', 'error');
  }
}

// 新增:清理旧记录(防止数据过多)
async cleanOldActivities(maxCount = 1000) {
  try {
    const activities = await noteDB.getAllActivities();
    if (activities.length > maxCount) {
      // 保留最新的maxCount条记录
      const sorted = activities.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
      const toDelete = sorted.slice(maxCount);
      for (const act of toDelete) {
        await noteDB.deleteActivity(act.id);
      }
    }
  } catch (error) {
    console.error('清理旧记录失败:', error);
  }
}

// 挂载全局方法
window.app = {
  ...window.app,
  renderActivity: () => this.renderActivity(),
  recordActivity: (type, desc, extra) => this.recordActivity(type, desc, extra),
  filterActivities: () => this.filterActivities(),
  deleteSingleActivity: (id) => this.deleteSingleActivity(id),
  clearAllActivities: () => this.clearAllActivities(),
  exportActivities: () => this.exportActivities()
};

🔌 OpenHarmony 原生代码

// ActivityPlugin.ets - 活动记录插件(扩展版)
import { webview } from '@kit.ArkWeb';
import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
import { deviceInfo } from '@kit.DeviceInfoKit';

@NativeComponent
export class ActivityPlugin {
  private context: common.UIAbilityContext;
  private maxRecordCount = 1000; // 最大记录数限制

  constructor(context: common.UIAbilityContext) {
    this.context = context;
  }

  // 初始化插件(扩展方法注册)
  public init(webviewController: webview.WebviewController): void {
    webviewController.registerJavaScriptProxy(
      new ActivityJSProxy(this),
      'activityPlugin',
      ['recordActivity', 'getActivities', 'deleteActivity', 'clearAllActivities', 'getDeviceInfo']
    );
  }

  // 记录活动(扩展版)
  public recordActivity(type: string, description: string, extra?: any): Promise<boolean> {
    return new Promise((resolve) => {
      try {
        const activitiesPath = this.context.cacheDir + '/activities.json';
        let activities: Array<any> = [];
        
        // 读取现有记录
        try {
          if (fileIo.accessSync(activitiesPath)) {
            const content = fileIo.readTextSync(activitiesPath);
            activities = JSON.parse(content);
          }
        } catch {
          activities = [];
        }

        // 新增:获取设备信息
        const deviceId = deviceInfo.getDeviceId() || 'unknown';
        const deviceModel = deviceInfo.getModel() || 'unknown device';
        
        // 构建完整活动记录
        const activity = {
          id: Date.now(),
          type: type,
          description: description,
          createdAt: new Date().toISOString(),
          device: `${deviceModel} (${deviceId.substring(0, 8)})`, // 设备信息脱敏
          ...(extra || {})
        };

        activities.push(activity);
        
        // 新增:限制记录数量,自动清理旧记录
        if (activities.length > this.maxRecordCount) {
          // 按时间降序排序,保留最新的maxRecordCount条
          activities.sort((a: any, b: any) => 
            new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
          );
          activities = activities.slice(0, this.maxRecordCount);
        }

        // 写入文件
        fileIo.writeTextSync(activitiesPath, JSON.stringify(activities, null, 2));
        resolve(true);
      } catch (error) {
        console.error('Failed to record activity:', error);
        resolve(false);
      }
    });
  }

  // 获取活动列表(扩展版:支持筛选)
  public getActivities(filter?: {type?: string, keyword?: string}): Promise<Array<any>> {
    return new Promise((resolve) => {
      try {
        const activitiesPath = this.context.cacheDir + '/activities.json';
        if (!fileIo.accessSync(activitiesPath)) {
          resolve([]);
          return;
        }
        
        const content = fileIo.readTextSync(activitiesPath);
        let activities = JSON.parse(content);
        
        // 新增:筛选逻辑
        if (filter) {
          // 按类型筛选
          if (filter.type && filter.type !== 'all') {
            activities = activities.filter((act: any) => act.type === filter.type);
          }
          // 按关键词筛选
          if (filter.keyword) {
            const keyword = filter.keyword.toLowerCase();
            activities = activities.filter((act: any) => 
              act.description.toLowerCase().includes(keyword) || 
              act.type.toLowerCase().includes(keyword)
            );
          }
        }
        
        // 按时间降序排序
        activities.sort((a: any, b: any) => 
          new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
        );
        
        resolve(activities);
      } catch (error) {
        console.error('Failed to get activities:', error);
        resolve([]);
      }
    });
  }

  // 新增:删除单条记录
  public deleteActivity(activityId: number): Promise<boolean> {
    return new Promise((resolve) => {
      try {
        const activitiesPath = this.context.cacheDir + '/activities.json';
        if (!fileIo.accessSync(activitiesPath)) {
          resolve(false);
          return;
        }
        
        const content = fileIo.readTextSync(activitiesPath);
        let activities = JSON.parse(content);
        // 过滤掉要删除的记录
        activities = activities.filter((act: any) => act.id !== activityId);
        
        fileIo.writeTextSync(activitiesPath, JSON.stringify(activities, null, 2));
        resolve(true);
      } catch (error) {
        console.error('Failed to delete activity:', error);
        resolve(false);
      }
    });
  }

  // 新增:清空所有记录
  public clearAllActivities(): Promise<boolean> {
    return new Promise((resolve) => {
      try {
        const activitiesPath = this.context.cacheDir + '/activities.json';
        // 写入空数组
        fileIo.writeTextSync(activitiesPath, '[]');
        resolve(true);
      } catch (error) {
        console.error('Failed to clear activities:', error);
        resolve(false);
      }
    });
  }

  // 新增:获取设备信息
  public getDeviceInfo(): Promise<string> {
    return new Promise((resolve) => {
      try {
        const model = deviceInfo.getModel() || '未知设备';
        const brand = deviceInfo.getBrand() || '未知品牌';
        resolve(`${brand} ${model}`);
      } catch (error) {
        console.error('Failed to get device info:', error);
        resolve('未知设备');
      }
    });
  }
}

// ActivityJSProxy.ets - JavaScript代理类(扩展版)
class ActivityJSProxy {
  private plugin: ActivityPlugin;

  constructor(plugin: ActivityPlugin) {
    this.plugin = plugin;
  }

  // 异步包装:记录活动
  async recordActivity(type: string, description: string, extra?: any): Promise<boolean> {
    return await this.plugin.recordActivity(type, description, extra);
  }

  // 异步包装:获取活动列表
  async getActivities(filter?: {type?: string, keyword?: string}): Promise<Array<any>> {
    return await this.plugin.getActivities(filter);
  }

  // 异步包装:删除单条记录
  async deleteActivity(activityId: number): Promise<boolean> {
    return await this.plugin.deleteActivity(activityId);
  }

  // 异步包装:清空所有记录
  async clearAllActivities(): Promise<boolean> {
    return await this.plugin.clearAllActivities();
  }

  // 异步包装:获取设备信息
  async getDeviceInfo(): Promise<string> {
    return await this.plugin.getDeviceInfo();
  }
}

📝 总结

活动记录功能实现了核心能力增强,主要优化点包括:
记录维度扩展:新增设备信息、操作溯源等字段,完善操作记录的完整性;
交互体验优化:支持按类型筛选、关键词搜索,不同操作类型区分样式展示;
记录管理能力:新增单条删除、批量清空、导出记录等功能,支持记录数量限制;
数据安全保障:自动清理旧记录防止数据膨胀,敏感操作(删除)添加二次确认;
原生能力扩展:OpenHarmony 端新增设备信息获取、记录删除 / 清空等方法,与 Web 端逻辑对齐。
扩展后的代码保持原有简洁架构,同时增强了功能实用性和用户体验,符合 Cordova+OpenHarmony 混合开发的设计规范,满足用户对操作日志的精细化管理需求。
活动记录功能的筛选和搜索功能如何实现?
如何确保活动记录的准确性和完整性?
除了 JavaScript,还可以用哪些语言实现活动记录功能?

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐