数据模型与持久化存储

第二章:数据模型与持久化存储

在自动化系统中,清晰的数据模型是逻辑复用与系统扩展的基础。本章将介绍:

  • 如何使用 TypeScript 定义核心数据结构
  • 如何利用 electron-store 实现数据的本地持久化

2.1 类型定义(TypeScript Interfaces)

我们使用 TypeScript 接口来严格定义数据结构,确保代码在开发与运行阶段都具备良好的类型安全性。


🧩 基础工作流模型

首先定义通用的工作流结构。

每个工作流包含一系列步骤(WorkflowStep)。

动作类型枚举
ts 复制代码
// 动作类型枚举
export type ActionType =
  | 'input'
  | 'click'
  | 'wait'
  | 'scroll'
  | 'select'
  | 'date';
动作模式(ActionMode)

例如 input 类型可以是直接赋值(set),也可以模拟打字(type)。

ts 复制代码
// 动作模式:定义更细粒度的操作行为
export type ActionMode =
  | 'set'
  | 'type'
  | 'inner_text'  // 输入相关
  | 'value'
  | 'text'
  | 'index';      // select 相关
WorkflowStep
ts 复制代码
export interface WorkflowStep {
  id: string;
  type: ActionType;
  desc?: string;      // 步骤描述
  selector?: string;  // CSS 选择器 (公共工作流可能为空)
  value?: string;     // 输入/选择的值
  mode?: ActionMode;  // 动作模式
  delay?: number;     // 执行后的延时(ms)
}
Workflow
ts 复制代码
export interface Workflow {
  id: string;
  title: string;
  desc?: string;
  steps: WorkflowStep[];
  createdAt: number;
  updatedAt: number;
}

🧩 页面工作流模型

页面工作流(PageWorkflow)是公共工作流的具体化:

  • 继承 Workflow
  • 绑定了具体 URL
  • 步骤包含对页面定制的 selector 或参数
ts 复制代码
export interface PageWorkflow extends Workflow {
  workflowId: string;  // 公共工作流的 ID
  url: string;         // 绑定的目标 URL
}

2.2 本地存储实现(electron-store)

为了保存用户创建的工作流,我们使用 electron-store

它基于 JSON 文件进行持久化,并存储于用户的应用数据目录中。


⚠️ Store 初始化与兼容性踩坑

在集成新版 electron-store (v9+) 时,会出现典型的 ESM vs CommonJS 兼容性问题。

❌ 问题复现

报错:

复制代码
Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported.
📌 原因分析
  • Electron 主进程默认运行在 CommonJS 环境
  • electron-store v9+ 强制使用 ESM
  • 导致 require/import 不兼容问题
✅ 解决方案(实战经验)

为了保持项目稳定并避免复杂的构建配置,我们采用:

  1. 降级到 electron-store@8.1.0(最后一个支持 CJS 的版本)
  2. 使用:
ts 复制代码
import Store from 'electron-store'; // 配合 tsconfig: esModuleInterop=true

Store 初始化

ts 复制代码
import Store from 'electron-store';

// 定义 Store 的 Schema
interface StoreSchema {
  workflows: Workflow[];
  pageWorkflows: PageWorkflow[];
}

// 初始化 Store 实例
const store = new Store<StoreSchema>({
  defaults: {
    workflows: [],
    pageWorkflows: [],
  },
});

export default store;

2.3 封装 CRUD 操作(数据访问层 DAO)

为了保持代码整洁,不应直接在 IPC Handler 中操作 Store。

我们创建一个 数据访问层 (DAO) 来封装存储逻辑。

ts 复制代码
export class WorkflowStore {
  // 获取所有工作流
  static getWorkflows(): Workflow[] {
    return store.get('workflows') || [];
  }

  // 根据 ID 获取
  static getWorkflowById(id: string): Workflow | undefined {
    return this.getWorkflows().find((w) => w.id === id);
  }

  // 保存或更新工作流
  static saveWorkflow(workflow: Workflow): void {
    const workflows = this.getWorkflows();
    const index = workflows.findIndex((w) => w.id === workflow.id);

    if (index > -1) {
      workflows[index] = workflow; // 更新
    } else {
      workflows.push(workflow);    // 新增
    }

    store.set('workflows', workflows);
  }

  // 删除工作流
  static deleteWorkflow(id: string): void {
    const workflows = this.getWorkflows();
    store.set(
      'workflows',
      workflows.filter((w) => w.id !== id)
    );
  }
}

2.4 暴露 IPC 接口

通过 IPC 让渲染进程能够访问工作流数据。

ts 复制代码
import { ipcMain } from 'electron';

// 获取所有工作流
ipcMain.handle('workflow:get-all', () => {
  return WorkflowStore.getWorkflows();
});

// 保存工作流
ipcMain.handle('workflow:save', (_event, workflow) => {
  WorkflowStore.saveWorkflow(workflow);
  return { success: true };
});

📝 教学笔记(深入理解)

在 Electron 开发中,追求依赖最新版并不总是最佳选择

  • Electron 环境由 Node.js、Chromium 混合组成

  • 模块规范(CJS vs ESM)兼容性问题非常常见

  • 遇到问题时:

    • 检查依赖包 package.json 是否包含 "type": "module"
    • 选择回退版本往往是最快捷且稳定的解决方式

相关推荐
哇哈哈&1 小时前
awk与sed的基本使用
linux·运维·服务器
水天需0101 小时前
Vim 搜索和替换详解
linux
乔碧萝成都分萝1 小时前
十六、一个基本的GPIO驱动程序
linux·驱动开发·嵌入式
ModestCoder_1 小时前
Ubuntu 22.04,Isaac Sim 5.1.0 + Isaac Lab 2.3.0 Conda 环境安装指南
linux·ubuntu·conda
水天需0101 小时前
Vim 学习全面指南
linux
9ilk2 小时前
【Linux】--- 多路转接select / poll / epoll
linux·运维·网络
jason成都2 小时前
emqx的docker部署
运维·docker·容器
赖small强2 小时前
【Linux驱动开发】Linux 中断机制深度解析:原理、监控与实战
linux·中断·硬件中断
buyutang_2 小时前
Linux 网络编程:TCP协议Socket开发全流程,理解多线程多进程实现的多连接网络通讯模型
linux·网络·tcp/ip