VTJ:ProjectModel 核心设计

ProjectModel 核心设计

引言

本文件面向 VTJ 低代码平台的"项目模型"(ProjectModel)核心设计,系统性阐述其整体架构、数据模型、生命周期管理、事件系统集成以及与区块模型(BlockModel)、节点模型(NodeModel)的协作机制。文档同时提供 API 参考、使用示例路径与最佳实践,帮助开发者高效、安全地使用 ProjectModel 管理项目。

项目结构

ProjectModel 位于核心包中,承担项目级状态与文件管理职责;其事件系统通过全局发射器(mitt)统一广播;设计器引擎(Engine)订阅并驱动持久化、激活文件、历史记录等流程;BlockModel/NodeModel 则负责页面/区块的 DSL 结构与变更传播。

graph TB subgraph "核心模型" PM["ProjectModel
项目模型"] BM["BlockModel
区块模型"] NM["NodeModel
节点模型"] end subgraph "事件系统" EM["emitter(mitt)
全局事件发射器"] end subgraph "设计器引擎" ENG["Engine
设计器引擎"] end PM -- "emit EVENT_*" --> EM BM -- "emit EVENT_BLOCK_CHANGE" --> EM NM -- "emit EVENT_NODE_CHANGE" --> EM EM -- "on EVENT_*" --> ENG ENG -- "active/deactivate/保存/发布" --> PM ENG -- "构建/更新当前 Block" --> BM BM -- "构建/更新节点树" --> NM

核心组件

  • ProjectModel:项目级数据模型,提供项目属性、页面/区块/依赖/API/Meta 等管理能力,支持静默/非静默更新,内置 DSL 序列化与路由生成。
  • BlockModel:区块级数据模型,承载节点树、状态、方法、计算属性、数据源、插槽、事件等,支持节点增删改移动与静默/非静默更新。
  • NodeModel:节点级数据模型,描述组件/HTML 标签的属性、事件、指令、插槽及子节点,支持可见性、锁定、层级移动与 DSL 序列化。
  • 事件系统:基于 mitt 的全局发射器,定义多种事件常量(如项目变更、文件激活、区块/节点变更、发布、出码等),由各模型在关键操作后触发。

架构总览

ProjectModel 作为项目数据中枢,贯穿以下关键流程:

  • 初始化:从协议 Schema 构造,填充默认属性,调用 update 进行首次赋值。
  • 生命周期:支持 active/deactivate 打开/关闭当前文件;setConfig/setI18n/setEnv 等配置更新;lock/unlock 项目锁定。
  • 文件管理:页面/区块的创建、更新、复制、移动、删除;目录树清理(移除 dsl);页面树导出。
  • 事件驱动:所有重要变更均通过 emitter 发布事件,设计器引擎订阅并执行保存、激活、发布、历史记录等动作。
  • 序列化:toDsl 输出项目 DSL,用于持久化、渲染、发布与出码。
sequenceDiagram participant UI as "设计器UI" participant ENG as "Engine" participant PM as "ProjectModel" participant EM as "emitter" participant S as "服务端/存储" UI->>PM : 调用 createPage/updatePage/removePage... PM->>EM : emit EVENT_PROJECT_PAGES_CHANGE + EVENT_PROJECT_CHANGE EM-->>ENG : on(EVENT_PROJECT_PAGES_CHANGE / EVENT_PROJECT_CHANGE) ENG->>S : saveProject/saveFile(根据事件类型) S-->>ENG : 成功/失败 ENG-->>UI : 触发视图更新/提示 UI->>PM : active(file)/deactivate() PM->>EM : emit EVENT_PROJECT_ACTIVED EM-->>ENG : on(EVENT_PROJECT_ACTIVED) ENG->>S : getFile(file.id, project.toDsl()) S-->>ENG : 返回dsl ENG->>ENG : new BlockModel(dsl), 更新当前

详细组件分析

ProjectModel 类结构与属性

  • 核心属性
    • 标识与平台:id、UID、platform
    • 基础信息:name、description、homepage
    • 结构与状态:pages、blocks、currentFile、locked
    • 配置与国际化:config、uniConfig、globals、i18n、env
    • 外部依赖与资源:dependencies、apis、meta
  • 静态属性:attrs 列表,用于 update 的批量赋值范围控制
  • 构造函数:接收 ProjectSchema,自动生成 id/UID 并调用 update(silent=true)

事件系统集成

  • 事件常量
    • 项目级:EVENT_PROJECT_CHANGE、EVENT_PROJECT_ACTIVED、EVENT_PROJECT_DEPS_CHANGE、EVENT_PROJECT_PUBLISH、EVENT_PROJECT_FILE_PUBLISH、EVENT_PROJECT_GEN_SOURCE
    • 文件级:EVENT_PROJECT_PAGES_CHANGE、EVENT_PROJECT_BLOCKS_CHANGE、EVENT_PROJECT_APIS_CHANGE、EVENT_PROJECT_META_CHANGE
  • 触发时机
    • update:非静默时触发 EVENT_PROJECT_CHANGE
    • active/deactivate:非静默时触发 EVENT_PROJECT_ACTIVED
    • 依赖/页面/区块/API/Meta 变更:分别触发对应文件事件与通用变更事件
    • publish/genSource:触发发布/出码事件
  • 设计器引擎订阅
    • 订阅项目变更、文件激活、发布、出码、区块/节点变更等,驱动保存、激活文件、历史记录等

生命周期管理

  • 初始化
    • 从协议 Schema 构造 ProjectModel,设置 id/UID,调用 update(silent=true) 完成属性填充
  • 更新
    • update(schema, silent?):按 attrs 列表批量赋值,非静默则触发变更事件
    • setConfig/setI18n/setEnv/setUniConfig/setGloblas:局部配置更新,非静默触发变更事件
  • 序列化
    • toDsl(version?):生成项目 DSL,清理页面/区块 dsl 字段,保留必要元数据
  • 文件生命周期
    • active(file, silent?) / deactivate(silent?):切换当前文件,非静默触发激活事件
    • createPage/updatePage/removePage/movePageTo/clonePage:页面/目录管理
    • createBlock/updateBlock/removeBlock/cloneBlock:区块管理
    • saveToBlock:将页面保存为区块
  • 项目状态
    • lock(id)/unlock(id):项目锁定/解锁,非静默触发变更事件
    • publish(file?)/genSource():触发发布/出码事件

与 BlockModel/NodeModel 的协作

  • 页面/区块文件以 DSL 形式存在,打开文件时由引擎通过服务端获取 DSL,再由 ProjectModel.active 切换当前文件,随后由引擎创建 BlockModel 并更新当前上下文
  • BlockModel.update/toDsl 与 NodeModel.update/toDsl 协同,形成从节点到区块再到项目的完整变更链路
  • 设计器引擎订阅 BLOCK/ NODE 变更事件,自动保存当前文件并维护历史记录
classDiagram class ProjectModel { +id : string +platform : PlatformType +pages : PageFile[] +blocks : BlockFile[] +currentFile : PageFile|BlockFile|null +update(schema, silent) +active(file, silent) +deactivate(silent) +createPage(...) +updatePage(...) +createBlock(...) +updateBlock(...) +toDsl(version?) } class BlockModel { +id : string +nodes : NodeModel[] +update(schema, silent) +toDsl(version?) +addNode(...) +move(...) +removeNode(...) } class NodeModel { +id : string +name : string +from : NodeFrom +children : NodeModel[]|string|JSExpression +props : Record +events : Record +directives : DirectiveModel[] +update(schema, silent) +toDsl() } ProjectModel --> BlockModel : "打开文件时创建" BlockModel --> NodeModel : "持有节点树"

API 参考(核心方法)

  • update(schema: Partial, silent?: boolean): void
    • 参数:部分项目 Schema;silent 控制是否触发事件
    • 行为:按静态 attrs 列表批量赋值;非静默触发 EVENT_PROJECT_CHANGE
  • active(file: BlockFile|PageFile, silent?: boolean): void
    • 行为:设置 currentFile;非静默触发 EVENT_PROJECT_ACTIVED
  • deactivate(silent?: boolean): void
    • 行为:清空 currentFile;非静默触发 EVENT_PROJECT_ACTIVED
  • createPage(page: PageFile, parentId?: string, silent?: boolean): Promise
    • 行为:生成页面 ID,必要时创建默认 DSL,插入目录或根;非静默触发 PAGE/PROJECT 变更事件;无目录且未打开文件时自动激活新建页面
  • updatePage(page: PageFile, silent?: boolean): PageFile | undefined
    • 行为:按 id 查找并合并更新;非静默触发 PAGE/PROJECT 变更事件
  • removePage(id: string, silent?: boolean): void
    • 行为:递归删除页面/目录;若为首页或当前文件则同步取消激活;非静默触发 PAGE/PROJECT 变更事件
  • movePageTo(pageId: string, parentId?: string, silent?: boolean): boolean
    • 行为:移动页面至指定父目录;非静默触发 PAGE/PROJECT 变更事件
  • clonePage(page: PageFile, parentId?: string, silent?: boolean): void
    • 行为:克隆页面并插入相邻位置;非静默触发 PAGE/PROJECT 变更事件
  • saveToBlock(page: PageFile, silent?: boolean): Promise
    • 行为:将页面转换为区块并追加到 blocks;非静默触发 BLOCK/PROJECT 变更事件
  • createBlock(block: BlockFile, silent?: boolean): Promise
    • 行为:生成区块 ID,创建默认 DSL;非静默触发 BLOCK/PROJECT 变更事件;无当前文件且来自 Schema 时自动激活
  • updateBlock(block: BlockFile, silent?: boolean): BlockFile | undefined
    • 行为:按 id 查找并合并更新;必要时同步更新 DSL 名称;非静默触发 BLOCK/PROJECT 变更事件
  • removeBlock(id: string, silent?: boolean): void
    • 行为:从 blocks 中删除;若为当前文件则取消激活;非静默触发 BLOCK/PROJECT 变更事件
  • cloneBlock(block: BlockFile, silent?: boolean): void
    • 行为:克隆区块并插入相邻位置;非静默触发 BLOCK/PROJECT 变更事件
  • setDeps(item: Dependencie, silent?: boolean): void
    • 行为:新增/更新依赖;非静默触发 DEPS/PROJECT 变更事件
  • removeDeps(item: Dependencie, silent?: boolean): void
    • 行为:删除依赖;非静默触发 DEPS/PROJECT 变更事件
  • setApi(item: ApiSchema, silent?: boolean): ApiSchema
  • setApis(items: ApiSchema[], silent?: boolean): void
  • removeApi(name: string, silent?: boolean): void
  • setMeta(item: MetaSchema, silent?: boolean): void
  • removeMeta(code: string, silent?: boolean): void
  • existMetaCode(code: string, excludes?: string[]): boolean
  • setHomepage(id: string, silent?: boolean): void
  • setConfig(config: ProjectConfig, silent?: boolean): void
  • setUniConfig(key: keyof UniConfig, value: Record<string, any>, silent?: boolean): void
  • setGloblas(key: keyof GlobalConfig, value: string|JSFunction, silent?: boolean): void
  • setI18n(i18n: I18nConfig, silent?: boolean): void
  • setEnv(env: EnvConfig[], silent?: boolean): void
  • publish(file?: PageFile|BlockFile): void
  • genSource(): void
  • lock(id: string): void
  • unlock(id: string): void
  • getPageRoutes(pageRouteName?: string, pageBasePath?: string): { id, path, name, title, meta }[]
  • toDsl(version?: string): ProjectSchema

使用示例(路径指引)

  • 在设计器中获取当前项目实例
  • 在 AI 功能中使用项目 DSL
  • 引擎初始化并创建 ProjectModel
  • 引擎订阅事件并处理保存/激活/发布/出码

依赖关系分析

  • 内聚性
    • ProjectModel 聚合了项目级所有实体与行为,内聚度高
  • 耦合性
    • 与 BlockModel/NodeModel 通过 DSL 间接耦合;与引擎通过事件耦合
  • 事件耦合
    • 设计器引擎通过 emitter 订阅项目/文件/区块/节点事件,形成解耦的观察者模式
  • 外部依赖
    • 工具库 uid、cloneDeep、mitt 等
graph LR PM["ProjectModel"] --> EM["emitter"] EM --> ENG["Engine"] ENG --> S["服务/存储"] PM --> BM["BlockModel"] BM --> NM["NodeModel"]

性能考量

  • 静默模式:大量批量更新建议使用 silent=true,减少事件风暴与重复渲染
  • DSL 清理:toDsl 与 cleanPagesDsl 会移除 dsl 字段,避免序列化体积过大
  • 事件粒度:区分通用变更与文件级变更(如 pages/blocks/apis/meta),有助于前端选择性刷新
  • 异步策略:创建/保存页面/区块时采用延迟激活与异步保存,提升交互流畅度

故障排查指南

  • 事件未触发
    • 检查是否传入 silent=true 导致静默更新
    • 确认 emitter.on 是否已订阅对应事件
  • 文件未激活
    • 确认 active(file) 调用与 EVENT_PROJECT_ACTIVED 订阅链路
    • 检查服务端 getFile 返回的 dsl 是否为空
  • 保存失败
    • 检查引擎锁状态(checkLocked),确认项目未被他人锁定
    • 确认服务端 saveProject/saveFile 接口返回成功
  • 页面/区块未更新
    • 确认 updatePage/createPage/removePage 等方法的 id/parentId 参数正确
    • 确认事件类型(create/update/delete/clone)与订阅处理逻辑一致

结论

ProjectModel 以清晰的数据模型与事件驱动机制,实现了项目级状态管理与文件生命周期控制;配合 BlockModel/NodeModel 的层级结构与变更传播,形成了从页面/区块到项目的完整数据流。通过静默模式、事件粒度与异步策略,可在保证一致性的同时兼顾性能与用户体验。建议在复杂批量操作中优先使用静默更新,并在关键节点订阅相应事件以确保持久化与渲染同步。

附录

  • 项目与区块模型关系概览

参考资料

VTJ.PRO 是一个开源的、AI 驱动的 Vue 3 企业级应用开发平台。它通过 AI 智能体与可视化编排实现高效开发,并支持导出标准 Vue 代码以避免平台锁定。更多信息请访问:

相关推荐
深度学习机器2 小时前
GenericAgent:一个充分利用上下文信息的自主进化智能体
llm·agent·ai编程
ZZH_AI项目交付2 小时前
一个 iOS 埋点 SDK 从 0 到 1,再到真实项目接入打磨
ios·app·ai编程
容沁风2 小时前
保持上网认证
ai编程·智谱
threelab2 小时前
从工厂模式到简化封装:三维引擎架构演进之路 threejs设计
javascript·3d·架构·webgl
灵机一物2 小时前
灵机一物AI原生电商小程序、PC端(已上线)-从 Vibe Coding 到 Wish Coding:AI 编程范式跃迁与蚂蚁灵光技术解读
ai编程
踩着两条虫2 小时前
VTJ:项目模型系统
前端·低代码·ai编程
小谢小哥2 小时前
51-限流算法详解
java·后端·架构
sunneo2 小时前
专栏A-AI原生产品设计-02-Agent设计范式
人工智能·产品运营·产品经理·ai编程·ai-native
扬帆破浪2 小时前
免费开源的WPS AI插件 察元AI助手:generateMultimodalAsset:类型校验与分支派发
人工智能·开源·ai编程·wps