# 改进数据结构设计 **Session ID:** ses_225b130dcffeK0m8Ys1edhMomF **Created:** 2026/4/30 01:34:51 **Updated:** 2026/4/30 10:19:51 --- ## User [search-mode] MAXIMIZE SEARCH EFFORT. Launch multiple background agents IN PARALLEL: - explore agents (codebase patterns, file structures, ast-grep) - librarian agents (remote repos, official docs, GitHub examples) Plus direct tools: Grep, ripgrep (rg), ast-grep (sg) NEVER stop at first result - be exhaustive. [analyze-mode] ANALYSIS MODE. Gather context before diving deep: CONTEXT GATHERING (parallel): - 1-2 explore agents (codebase patterns, implementations) - 1-2 librarian agents (if external library involved) - Direct tools: Grep, AST-grep, LSP for targeted searches IF COMPLEX - DO NOT STRUGGLE ALONE. Consult specialists: - **Oracle**: Conventional problems (architecture, debugging, complex logic) - **Artistry**: Non-conventional problems (different approach needed) SYNTHESIZE findings before proceeding. --- MANDATORY delegate_task params: ALWAYS include load_skills=[] and run_in_background when calling delegate_task. Example: delegate_task(subagent_type="explore", prompt="...", run_in_background=true, load_skills=[]) --- Create or update `AGENTS.md` for this repository. The goal is a compact instruction file that helps future OpenCode sessions avoid mistakes and ramp up quickly. Every line should answer: "Would an agent likely miss this without help?" If not, leave it out. User-provided focus or constraints (honor these): ## How to investigate Read the highest-value sources first: - `README*`, root manifests, workspace config, lockfiles - build, test, lint, formatter, typecheck, and codegen config - CI workflows and pre-commit / task runner config - existing instruction files (`AGENTS.md`, `CLAUDE.md`, `.cursor/rules/`, `.cursorrules`, `.github/copilot-instructions.md`) - repo-local OpenCode config such as `opencode.json` If architecture is still unclear after reading config and docs, inspect a small number of representative code files to find the real entrypoints, package boundaries, and execution flow. Prefer reading the files that explain how the system is wired together over random leaf files. Prefer executable sources of truth over prose. If docs conflict with config or scripts, trust the executable source and only keep what you can verify. ## What to extract Look for the highest-signal facts for an agent working in this repo: - exact developer commands, especially non-obvious ones - how to run a single test, a single package, or a focused verification step - required command order when it matters, such as `lint -> typecheck -> test` - monorepo or multi-package boundaries, ownership of major directories, and the real app/library entrypoints - framework or toolchain quirks: generated code, migrations, codegen, build artifacts, special env loading, dev servers, infra deploy flow - repo-specific style or workflow conventions that differ from defaults - testing quirks: fixtures, integration test prerequisites, snapshot workflows, required services, flaky or expensive suites - important constraints from existing instruction files worth preserving Good `AGENTS.md` content is usually hard-earned context that took reading multiple files to infer. ## Questions Only ask the user questions if the repo cannot answer something important. Use the `question` tool for one short batch at most. Good questions: - undocumented team conventions - branch / PR / release expectations - missing setup or test prerequisites that are known but not written down Do not ask about anything the repo already makes clear. ## Writing rules Include only high-signal, repo-specific guidance such as: - exact commands and shortcuts the agent would otherwise guess wrong - architecture notes that are not obvious from filenames - conventions that differ from language or framework defaults - setup requirements, environment quirks, and operational gotchas - references to existing instruction sources that matter Exclude: - generic software advice - long tutorials or exhaustive file trees - obvious language conventions - speculative claims or anything you could not verify - content better stored in another file referenced via `opencode.json` `instructions` When in doubt, omit. Prefer short sections and bullets. If the repo is simple, keep the file simple. If the repo is large, summarize the few structural facts that actually change how an agent should work. If `AGENTS.md` already exists at `D:\Projects\Private\datalive-design`, improve it in place rather than rewriting blindly. Preserve verified useful guidance, delete fluff or stale claims, and reconcile it with the current codebase. --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 8.3s) _Thinking:_ I'm starting by exploring the repository structure to get a sense of what we're working with. **Tool: bash** **Input:** ```json { "command": "ls -la", "description": "List root directory contents", "workdir": "D:\\Projects\\Private\\datalive-design" } ``` **Output:** ``` Get-ChildItem: A parameter cannot be found that matches parameter name 'la'. ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 6.5s) **Tool: bash** **Input:** ```json { "command": "Get-ChildItem -Force | Select-Object Mode, LastWriteTime, Length, Name", "description": "List root directory contents", "workdir": "D:\\Projects\\Private\\datalive-design" } ``` **Output:** ``` Mode  LastWriteTime  Length Name ----  -------------  ------ ---- d--h- 2026/4/30 1:32:12 .git d---- 2026/4/9 21:21:45 docs d---- 2025/12/18 1:45:26 node_modules d---- 2026/4/14 14:19:15 src -a--- 2025/12/18 1:45:26 388 .gitignore -a--- 2026/4/14 14:15:06 5517 AGENTS.md -a--- 2025/12/18 1:45:26 1207 bun.lock -a--- 2026/4/2 0:10:14 206 package.json -a--- 2025/12/18 1:45:26 230 README.md -a--- 2025/12/18 1:45:26 713 tsconfig.json ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 7.1s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\AGENTS.md" } ``` **Output:** ``` D:\Projects\Private\datalive-design\AGENTS.md file 1: # DatAlive 低代码设计器数据结构设计 2: 3: ## 项目介绍 4: 5: 本项目的实现目标是设计一个尽可能通用的低代码设计器平台的核心数据结构,该平台能够支持以拖拽和配置组件、路由、状态、事件、过滤器、页面等实体元素,以可视化的交互方式搭建数字大屏、中后台系统以及产品官网等多类应用。 6: 7: 其中,当前阶段的首要目标场景是**数字大屏**。围绕该场景,平台的核心 `Schema` 结构已经进行了更深入的分析、约束与推演;而对于中后台系统与产品官网场景,现阶段主要完成的是字段层面的前瞻性预留,以保证整体结构具备后续扩展空间,但尚未进行同等深度的专项分析与完备性验证。 8: 9: 所谓“核心数据结构”,主要是在平台中设计应用或大屏系统时所依赖的一套统一配置蓝图。 10: 11: 这套蓝图既需要能够描述设计时配置,也需要能够描述运行时配置,其中: 12: 13: - 设计时配置,指用户在设计器中拖拽、配置组件、路由、状态、事件、过滤器、页面等元素时,需要被持久化保存的配置信息。 14: - 运行时配置,指用户完成设计后,在最终应用运行时需要被加载和消费的配置信息。 15: 16: 在本项目中,`Schema` 的角色应被明确定位为:**整个应用配置的持久化表现形式与统一交换格式**。 17: 18: 用户保存到数据库的是这份 `Schema`,导出到本地的是这份 `Schema`,从外部导入到平台中的也是这份 `Schema`。但平台在运行过程中,**不会直接以 `Schema` 作为工作内存来驱动各项能力**。相反,平台会在导入 `Schema` 后,将其解析、校验、规范化,并拆分到与各引擎职责对应的内部状态 `Store` 中;而在保存、导出或发布时,再将各引擎 `Store` 中的稳定数据重新聚合为 `Schema`,用于持久化或输出。 19: 20: 因此可以认为: 21: 22: - `Schema` 面向持久化、导入导出与跨边界交换; 23: - `Store` 面向平台运行时、引擎协作与高频状态操作。 24: 25: 此外,平台在整体运行语义上需要明确区分 `设计态(Design Mode)`、`预览态(Preview Mode)` 与 `运行态(Runtime Mode)` 三种模式。三态的切换应被视为平台的**运行时上下文(AppMode)** 差异,而不是 `Schema` 本身的结构差异。换言之,`AppMode` 不属于需要持久化存储的 `Schema` 蓝图,而应由外部宿主容器或平台运行时环境显式注入。 26: 27: 其中: 28: 29: - `设计态` 用于可视化编辑、拖拽编排与配置应用结构; 30: - `运行态` 用于面向最终用户提供纯净、完整的应用运行体验; 31: - `预览态` 则用于在不进入正式运行环境的前提下,以尽可能接近真实运行态的方式对应用进行预览、验证与调试。 32: 33: `预览态` 既不同于可任意编辑配置的 `设计态`,也不同于面向最终用户的纯净 `运行态`,而是一种介于两者之间的**受控运行模式**。在该模式下,平台应尽可能复用与 `运行态` 相同的 `Schema` 渲染主链路,放行业务交互、数据请求、事件流转与页面跳转,使用户或实施人员能够提前验证应用在真实运行中的行为表现。 34: 35: 同时,`预览态` 还应具备必要的白盒调试与观测能力,用于辅助定位应用配置中的问题,例如: 36: 37: - 数据请求的发起、成功、失败与错误信息; 38: - 过滤器接收的输入参数是否正确,以及过滤结果是否异常; 39: - 事件流的触发顺序、条件命中情况、动作执行过程与中断原因; 40: - 表达式求值、生命周期触发、关键动作执行等运行日志; 41: - 将错误、警告与日志尽可能关联到具体的组件、事件、过滤器、数据源或动作节点。 42: 43: 因此,`预览态` 需要被纳入平台整体架构设计中,但其影响应主要体现在运行时上下文、引擎挂载策略、错误处理策略以及内部 `Store` 的组织方式上,而不应膨胀为一套独立的 `Schema` 结构维度。 44: 45: `Schema` 仍只负责承载跨模式稳定且需要被持久化的应用配置,而模式切换过程中产生的会话状态、派生状态、调试状态、缓存状态与临时控制状态,应由运行时 `Store` 负责管理。 46: 47: 在完成核心 `Schema` 结构设计的里程碑阶段后,项目下一阶段的重点将转向整个平台的技术路线与实现方案设计。 48: 49: 这意味着,后续工作不再仅仅聚焦于“应用配置如何被描述”,而是要进一步回答:平台应如何基于既定 `Schema` 组织内部状态 `Store`、构建运行时上下文、拆分核心模块,并驱动各个引擎协同工作。 50: 51: 其中,一个关键目标是逐步明确并落地平台的五大核心引擎,包括: 52: 53: - 工作区引擎 54: - 画布引擎 55: - 渲染引擎 56: - 数据引擎 57: - 交互引擎 58: 59: 现阶段的实现目标,是在既定 `Schema` 蓝图的基础上,进一步规划整个平台的技术架构、状态模型与引擎协作机制,为后续设计器与运行时系统的工程化实现提供稳定依据。 60: 61: 在技术栈方面,本项目希望积极拥抱 `React` + `Vite` 的最新生态体系,包括但不限于 `React`、`React Router` 或 `Tanstack Router`、`Tanstack Query`、`Zustand` 等。 62: 63: ## 项目规则 64: 65: ### 协作规则 66: 67: 1. 严禁直接修改项目代码,仅展示你的方案,由我来手动修改代码。 (End of file - total 67 lines) [Project README: D:\Projects\Private\datalive-design\README.md] # datalive-design To install dependencies: ```bash bun install ``` To run: ```bash bun run index.ts ``` This project was created using `bun init` in bun v1.3.4. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. [Category+Skill Reminder] **Built-in**: playwright, frontend-ui-ux, git-master, dev-browser, review-work, ai-slop-remover **⚡ YOUR SKILLS (PRIORITY)**: (none) > User-installed skills OVERRIDE built-in defaults. ALWAYS prefer YOUR SKILLS when domain matches. ```typescript task(category="visual-engineering", load_skills=["playwright"], run_in_background=true) ``` ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.7s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\package.json" } ``` **Output:** ``` D:\Projects\Private\datalive-design\package.json file 1: { 2: "name": "datalive-design", 3: "module": "src/index.ts", 4: "type": "module", 5: "private": true, 6: "devDependencies": { 7: "@types/bun": "latest" 8: }, 9: "peerDependencies": { 10: "typescript": "^5" 11: } 12: } (End of file - total 12 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.3s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\tsconfig.json" } ``` **Output:** ``` D:\Projects\Private\datalive-design\tsconfig.json file 1: { 2: "compilerOptions": { 3: // Environment setup & latest features 4: "lib": ["ESNext"], 5: "target": "ESNext", 6: "module": "Preserve", 7: "moduleDetection": "force", 8: "jsx": "react-jsx", 9: "allowJs": true, 10: 11: // Bundler mode 12: "moduleResolution": "bundler", 13: "allowImportingTsExtensions": true, 14: "verbatimModuleSyntax": true, 15: "noEmit": true, 16: 17: // Best practices 18: "strict": true, 19: "skipLibCheck": true, 20: "noFallthroughCasesInSwitch": true, 21: "noUncheckedIndexedAccess": true, 22: "noImplicitOverride": true, 23: 24: // Some stricter flags (disabled by default) 25: "noUnusedLocals": false, 26: "noUnusedParameters": false, 27: "noPropertyAccessFromIndexSignature": false 28: } 29: } (End of file - total 29 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 6.1s) **Tool: bash** **Input:** ```json { "command": "Get-ChildItem -Recurse src -Force | Select-Object FullName", "description": "List src directory tree", "workdir": "D:\\Projects\\Private\\datalive-design" } ``` **Output:** ``` FullName -------- D:\Projects\Private\datalive-design\src\schema D:\Projects\Private\datalive-design\src\index.ts D:\Projects\Private\datalive-design\src\schema\application D:\Projects\Private\datalive-design\src\schema\component D:\Projects\Private\datalive-design\src\schema\data-source D:\Projects\Private\datalive-design\src\schema\filter D:\Projects\Private\datalive-design\src\schema\interaction D:\Projects\Private\datalive-design\src\schema\mutation D:\Projects\Private\datalive-design\src\schema\page D:\Projects\Private\datalive-design\src\schema\query D:\Projects\Private\datalive-design\src\schema\route D:\Projects\Private\datalive-design\src\schema\shared D:\Projects\Private\datalive-design\src\schema\variable D:\Projects\Private\datalive-design\src\schema\index.ts D:\Projects\Private\datalive-design\src\schema\application\application.ts D:\Projects\Private\datalive-design\src\schema\application\index.ts D:\Projects\Private\datalive-design\src\schema\component\component-data.ts D:\Projects\Private\datalive-design\src\schema\component\component-layout.ts D:\Projects\Private\datalive-design\src\schema\component\component.ts D:\Projects\Private\datalive-design\src\schema\component\index.ts D:\Projects\Private\datalive-design\src\schema\data-source\data-source-by-database.ts D:\Projects\Private\datalive-design\src\schema\data-source\data-source-by-rest.ts D:\Projects\Private\datalive-design\src\schema\data-source\data-source.ts D:\Projects\Private\datalive-design\src\schema\data-source\index.ts D:\Projects\Private\datalive-design\src\schema\filter\filter.ts D:\Projects\Private\datalive-design\src\schema\filter\index.ts D:\Projects\Private\datalive-design\src\schema\interaction\action.ts D:\Projects\Private\datalive-design\src\schema\interaction\index.ts D:\Projects\Private\datalive-design\src\schema\interaction\interaction.ts D:\Projects\Private\datalive-design\src\schema\mutation\index.ts D:\Projects\Private\datalive-design\src\schema\mutation\mutation-config.ts D:\Projects\Private\datalive-design\src\schema\mutation\mutation.ts D:\Projects\Private\datalive-design\src\schema\page\index.ts D:\Projects\Private\datalive-design\src\schema\page\page-layout.ts D:\Projects\Private\datalive-design\src\schema\page\page.ts D:\Projects\Private\datalive-design\src\schema\query\index.ts D:\Projects\Private\datalive-design\src\schema\query\query-config.ts D:\Projects\Private\datalive-design\src\schema\query\query.ts D:\Projects\Private\datalive-design\src\schema\route\index.ts D:\Projects\Private\datalive-design\src\schema\route\route.ts D:\Projects\Private\datalive-design\src\schema\shared\condition.ts D:\Projects\Private\datalive-design\src\schema\shared\css-properties.ts D:\Projects\Private\datalive-design\src\schema\shared\dynamic-expression.ts D:\Projects\Private\datalive-design\src\schema\shared\entity.ts D:\Projects\Private\datalive-design\src\schema\shared\index.ts D:\Projects\Private\datalive-design\src\schema\shared\json-value.ts D:\Projects\Private\datalive-design\src\schema\shared\rest-request.ts D:\Projects\Private\datalive-design\src\schema\variable\index.ts D:\Projects\Private\datalive-design\src\schema\variable\variable.ts ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.1s) **Tool: bash** **Input:** ```json { "command": "Get-ChildItem -Recurse docs -Force | Select-Object FullName", "description": "List docs directory contents", "workdir": "D:\\Projects\\Private\\datalive-design" } ``` **Output:** ``` FullName -------- D:\Projects\Private\datalive-design\docs\�������̬������������.md D:\Projects\Private\datalive-design\docs\�������������ܹ��淶.md D:\Projects\Private\datalive-design\docs\�����ѡ������齻���淶.md D:\Projects\Private\datalive-design\docs\ʵ��������������ʵ�ֹ淶.md D:\Projects\Private\datalive-design\docs\Ӧ������ģʽ�ܹ��淶.md ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 29.9s) _Thinking:_ The filenames in the docs directory contain Chinese characters that got corrupted in the display, so I'll switch to using Glob to handle them properly. **Tool: glob** **Input:** ```json { "pattern": "docs/*.md" } ``` **Output:** ``` Found 5 file(s) D:\Projects\Private\datalive-design\docs\实体生命周期引擎实现规范.md D:\Projects\Private\datalive-design\docs\设计器悬浮组件架构规范.md D:\Projects\Private\datalive-design\docs\设计器静态依赖分析方案.md D:\Projects\Private\datalive-design\docs\应用运行模式架构规范.md D:\Projects\Private\datalive-design\docs\设计器选中与分组交互规范.md [Agent Usage Reminder] You called a search/fetch tool directly without leveraging specialized agents. RECOMMENDED: Use task with explore/librarian agents for better results: ``` // Parallel exploration - fire multiple agents simultaneously task(subagent_type="explore", load_skills=[], prompt="Find all files matching pattern X") task(subagent_type="explore", load_skills=[], prompt="Search for implementation of Y") task(subagent_type="librarian", load_skills=[], prompt="Lookup documentation for Z") // Then continue your work while they run in background // System will notify you when each completes ``` WHY: - Agents can perform deeper, more thorough searches - Background tasks run in parallel, saving time - Specialized agents have domain expertise - Reduces context window usage in main session ALWAYS prefer: Multiple parallel task calls > Direct tool calls ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.5s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\index.ts file (End of file - total 0 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\index.ts file (End of file - total 0 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.8s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\application\\application.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\application\application.ts file 1: import type { DataSource } from '../data-source'; 2: import type { Filter } from '../filter'; 3: import type { Interaction } from '../interaction'; 4: import type { Mutation } from '../mutation'; 5: import type { Page } from '../page'; 6: import type { Query } from '../query'; 7: import type { Route } from '../route'; 8: import type { Variable } from '../variable'; 9: 10: export interface Application { 11: /** 12: * 应用的唯一全局标识符 13: */ 14: id: string; 15: /** 16: * 应用的名称 (如:"智慧能源管理平台") 17: * 仅用于控制台展示或浏览器 title 18: */ 19: title: string; 20: /** 21: * 创建时间 22: */ 23: createdTime: string; 24: /** 25: * 更新时间 26: */ 27: updatedTime: string; 28: /** 29: * 路由体系 30: * 31: * 决定了应用由哪些页面组成,以及页面间的跳转关系(嵌套路由/重定向)。 32: * 33: * 引擎需根据运行环境,动态采用 BrowserRouter 或 MemoryRouter 进行接管。 34: */ 35: routes: Route[]; 36: /** 37: * 页面 38: * 39: * 包含了该应用下所有的画板实例。 40: * 41: * 每个 Page 决定了自身的排版模式(Free/Flex/Flow),并作为根节点挂载了一棵庞大的组件树。 42: */ 43: pages: Page[]; 44: /** 45: * 变量 46: * 47: * 强类型的状态容器。它是组件通信、属性动态绑定、控制流(Condition)的核心依赖。 48: * 49: * 引擎需将其映射为一个支持响应式订阅的 Store(如 Zustand),确保一处修改,全局重绘。 50: */ 51: variables: Variable[]; 52: /** 53: * 数据源 54: * 55: * 定义底层的通信协议(如 RESTful API 的 baseUrl 和公共鉴权 Headers,或数据库的连接配置)。 56: * 57: * 它是为上层的 Query/Mutation 提供网络 IO 能力的基础设施。 58: */ 59: dataSources: DataSource[]; 60: /** 61: * 查询 62: * 63: * 专用于向后端发起无副作用的数据获取请求(如获取列表、详情)。 64: * 65: * 引擎实现指引: 66: * 67: * 1. 它可以享受平台提供的高级状态机特性:如页面加载预热(prefetch)、定时轮询(polling)、自动缓存(cache)。 68: * 2. 它会被映射为类似 Tanstack Query 的 `useQuery` 实例。 69: * 3. 组件通过 `dataBinding` 机制,声明式地订阅它的结果(data, isLoading),实现数据驱动视图。 70: */ 71: queries: Query[]; 72: /** 73: * 变更 74: * 75: * 专用于修改服务端状态(如提交表单、删除数据、上传文件)。 76: * 77: * 引擎实现指引: 78: * 79: * 1. 坚决不能在页面加载时自动执行!它没有 polling 和 prefetch 配置。 80: * 2. 它会被映射为类似 Tanstack Query 的 `useMutation` 实例。 81: * 3. 它只能作为一种【命令式动作 (Imperative Action)】,在组件的交互事件 (Interactions) 中被手动调用。 82: * 4. 调用成功后,通常需要配合触发其他 Action (如显示 Toast、或刷新某个 Query)。 83: */ 84: mutations: Mutation[]; 85: /** 86: * 数据过滤器 87: * 88: * 独立的纯函数字符串集合。 89: * 90: * 专供组件在订阅 `Query` 后,进行局部的数据格式化、过滤或多源聚合操作。 91: * 92: * 确保了一份原始数据(Query)能被洗成多种形态供不同图表复用。 93: */ 94: filters: Filter[]; 95: /** 96: * 实体交互 97: * 98: * 挂载于应用最顶层的交互配置。 99: * 100: * 例如:监听 `onAppLaunch`(应用启动)事件,去触发某个全局鉴权 API,或初始化某个关键 Variable。 101: */ 102: interactions: Interaction[]; 103: } (End of file - total 103 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.3s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\component\\component.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\component\component.ts file 1: import type { 2: DynamicExpression, 3: Condition, 4: CSSProperties, 5: Entity, 6: JsonValue, 7: } from '../shared'; 8: import type { Interaction } from '../interaction'; 9: import type { ComponentData } from './component-data'; 10: import type { ComponentLayout } from './component-layout'; 11: 12: export interface Component extends Entity { 13: /** 14: * 组件类型 15: * 16: * 组件类型用于标识组件的类型,例如 `input`、`button` 等,就是组件名。 17: */ 18: type: string; 19: /** 20: * 组件来源类型 21: * 22: * 组件来源类型用于标识组件的来源,例如 `builtin` 表示内置组件,`remote` 表示远程组件。 23: */ 24: sourceType: 'builtin' | 'remote'; 25: children?: Component[]; 26: /** 27: * 条件渲染 28: */ 29: condition?: Condition; 30: layout: ComponentLayout; 31: /** 32: * 组件通用样式 33: * 34: * 承载跨组件通用的、标准的 CSS 视觉属性,仅作用于组件的最外层 DOM 容器。 35: * 必须为静态键值对,不支持动态表达式(DynamicExpression),以保证渲染性能并斩断“无意义的 React 渲染瀑布”。 36: * 任何基于数据流或业务状态的动态视觉变化,应通过 props 或事件触发的 Action 来实现。 37: * 38: * @example { backgroundColor: '#fff', borderRadius: 4, boxShadow: '0 2px 4px rgba(0,0,0,0.1)' } 39: */ 40: style: CSSProperties; 41: /** 42: * 组件私有属性 43: * 44: * 承载与具体组件类型(type)强绑定的业务语义、内部结构和私有状态。 45: * 支持动态表达式(DynamicExpression),允许属性值随数据流或环境变量动态变化。 46: * 如果组件没有任何自定义属性,该值必须为空对象 `{}`,以消除空值检查成本。 47: * 48: * @example { text: '提交', disabled: false, size: 'large', type: 'primary' } 49: */ 50: props: Record; 51: /** 52: * 图层管理属性 53: * 54: * 仅影响编辑器中的交互行为和图层面板状态,不影响运行时渲染。 55: * e.g. 锁定、隐藏、选中策略 56: */ 57: layer: { 58: locked: boolean; // 锁定后在画布中不可被选中或移动 59: hidden: boolean; // 在设计器中隐藏(辅助线/临时隐藏),但运行时可能可见 60: }; 61: data: ComponentData; 62: interactions: Interaction[]; 63: } 64: 65: export type ComponentPropValue = JsonValue | DynamicExpression | undefined; (End of file - total 65 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.2s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\component\\component-data.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\component\component-data.ts file 1: import type { JsonValue } from '../shared'; 2: 3: export interface ComponentDataByStatic { 4: type: 'static'; 5: value: JsonValue; 6: } 7: 8: export interface ComponentDataByQuery { 9: type: 'query'; 10: queryIds: string[]; 11: filterIds: string[]; 12: } 13: 14: export type ComponentData = ComponentDataByStatic | ComponentDataByQuery; (End of file - total 14 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\component\\component-layout.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\component\component-layout.ts file 1: export type ComponentLayout = 2: | ComponentLayoutByFree 3: | ComponentLayoutByFlex 4: | ComponentLayoutByFlow; 5: 6: export interface ComponentLayoutByFree { 7: mode: 'free'; 8: top: number; 9: left: number; 10: width: number; 11: height: number; 12: visibility: string; // 组件可见性 13: opacity: number; // 组件透明度 14: pointerEvents: string; // 事件穿透 15: // allowDrag: boolean; // 允许拖动 16: // allowDrop: boolean; // 允许放置 17: /** 18: * 空间形变数据 (支持大屏的高级 2D/3D 视觉需求) 19: */ 20: transform?: { 21: rotateX?: number; // 绕X轴翻转 (3D) 22: rotateY?: number; // 绕Y轴翻转 (3D) 23: rotateZ?: number; // 平面旋转 (即原来的 rotation) 24: scaleX?: number; // X轴缩放 25: scaleY?: number; // Y轴缩放 26: }; 27: } 28: 29: // TODO: 弹性布局配置,暂不实现 30: export interface ComponentLayoutByFlex { 31: mode: 'flex'; 32: } 33: 34: // TODO: 流式布局配置,暂不实现 35: export interface ComponentLayoutByFlow { 36: mode: 'flow'; 37: } (End of file - total 37 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.2s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\page\\page.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\page\page.ts file 1: import type { Component } from '../component'; 2: import type { CSSProperties, Entity } from '../shared'; 3: import type { Interaction } from '../interaction'; 4: import type { PageLayout } from './page-layout'; 5: 6: /** 7: * 页面容器 8: * 9: * 【架构定位】: 10: * 11: * 它是低代码视图层(View Layer)的顶级画板。 12: * 13: * 负责统领全局的排版模式(Layout)、提供背景画板(Style)、并挂载整棵组件树(Components)。 14: */ 15: export interface Page extends Entity { 16: /** 17: * 页面排版模式 18: * 19: * 决定了当前页面的渲染法则(大屏绝对定位 vs 中后台自适应)。 20: */ 21: layout: PageLayout; 22: /** 23: * 页面级静态样式 24: * 25: * 核心架构指引: 26: * 27: * 坚决抵制“在画布底层垫一个巨大的图片/色块组件来充当背景”的反模式! 28: * 那会导致极其严重的误触(需要频繁锁定)、层叠上下文污染(Z-index 战争)和流式响应式坍塌。 29: * 30: * 必须由引擎将此处的 `style`(如 backgroundColor, backgroundImage, padding) 31: * 原生地挂载到包裹整个页面的最外层 HTML `
` 容器上,实现真正的、零成本的背景渲染。 32: */ 33: style: CSSProperties; 34: /** 35: * 组件树 36: * 37: * 核心架构指引: 38: * 39: * 1. 多根节点支持:必须是数组,允许用户在白板上自由平铺多个逻辑根节点。 40: * 引擎在底层会自动将 Page 实例映射为一个真实的 DOM 容器(如 `
`)来包裹这棵树。 41: * 这避免了强制要求唯一 `rootComponent` 带来的无谓 DOM 嵌套(如强迫套一个 Group)和反直觉体验。 42: * 2. 嵌套结构:为了保持 Schema 作为“蓝图”的直观可读性,这里存储的是完整的嵌套组件树。 43: * 将组件打平为全局字典 (Normalization) 仅是引擎在运行时 Zustand Store 里的性能优化手段, 44: * 绝不应污染此处持久化的静态 Schema。 45: */ 46: components: Component[]; 47: /** 48: * 交互 49: * 50: * 页面级生命周期与事件 51: * 52: * 挂载于当前页面的高阶控制流枢纽。 53: * 54: * 引擎实现指引: 55: * 56: * 1. 常见的触发事件 (event):`onLoad` (页面加载完成), `onUnload` (离开页面), `onResize` (尺寸变化)。 57: * 2. 典型的业务场景:在 `onLoad` 时,派发 Action 去触发某些没有开启 prefetch 的懒加载 Query, 58: * 或者初始化/重置某些局部的 Variables。 59: */ 60: interactions: Interaction[]; 61: } (End of file - total 61 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.0s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\page\\page-layout.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\page\page-layout.ts file 1: /** 2: * 自由布局,用于数字大屏或看板页面 3: */ 4: export interface FreeLayout { 5: mode: 'free'; 6: width: number; 7: height: number; 8: /** 9: * 缩放模式 10: * 11: * - `fit`: 等比缩放,确保大屏内容完整显示 12: * - `fill`: 放弃长宽比,强行拉伸大屏填满容器 13: * - `flow`: 流式布局,宽度填满,纵向滚动 14: * - `none`: 无视屏幕尺寸,不进行缩放,以真实像素值进行渲染 15: */ 16: scaleMode: 'fit' | 'fill' | 'flow' | 'none'; // 等比缩放/全屏拉伸/纵向滚动/保持比例 17: } 18: 19: /** 20: * 弹性布局,用于中后台页面 21: */ 22: export interface FlexLayout { 23: mode: 'flex'; 24: minWidth: number; 25: } 26: 27: /** 28: * 流式布局,用于门户/官网场景 29: */ 30: export interface FlowLayout { 31: mode: 'flow'; 32: maxWidth: number; 33: } 34: 35: export type PageLayout = FreeLayout | FlexLayout | FlowLayout; (End of file - total 35 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.3s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\route\\route.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\route\route.ts file 1: import type { Entity } from '../shared'; 2: import type { Interaction } from '../interaction'; 3: 4: /** 5: * 路由 6: * 7: * 【架构定位】: 8: * 9: * 1. 它是连接 URL 与 Page(页面实例)的唯一桥梁。 10: * 2. 它是构建复杂应用(如中后台系统、多页官网)的核心导航骨架。 11: * 12: * 【引擎实现指引】 13: * 14: * 1. 隔离策略: 15: * - 设计模式 (design) 下,渲染引擎必须使用 `Memory Router`(或重写 `history.pushState`), 16: * 以防止用户在配置路由跳转时,导致整个设计器外壳发生灾难性的真刷新或沙盒逃逸。 17: * - 运行/预览模式 (runtime/preview) 下,引擎切换为原生的 `Browser Router`。 18: * 2. 嵌套挂载: 19: * 当遇到带有 `children` 的路由时,引擎会将其对应的 `pageId` 视为一个“父级布局骨架(Layout Skeleton)”。 20: * 引擎在该骨架中必须寻找一个特殊的内置组件(如 `type: 'Outlet'` 或 `RouterView`), 21: * 以作为子路由对应 `Page` 的挂载插槽。 22: */ 23: export interface Route extends Entity { 24: /** 25: * 路由路径 26: * 27: * 定义了匹配当前路由的 URL 片段。 28: * 29: * 支持静态路径(如 '/home'、'/dashboard')和参数路径(如 '/user/:id')。 30: * 31: * 在根数组中,通常包含一个 '/' 作为默认首页。 32: */ 33: path: string; 34: /** 35: * 路由重定向 36: * 37: * 如果配置了此字段,当 URL 匹配到当前 path 时,引擎不渲染组件, 38: * 而是立即执行 301/302 级别的重定向,跳转到目标 path。 39: * 40: * 常见于将根路径 '/' 重定向到具体的首页 '/home'。 41: */ 42: redirect?: string; 43: /** 44: * 绑定的页面 ID 45: * 46: * 核心映射:当前路由命中时,引擎将去全局的 `Application.pages` 数组中 47: * 查找对应的 Page 实例,并渲染该 Page 携带的庞大组件树。 48: * 49: * 注:如果这是一个纯粹的重定向路由 (redirect存在) 或父级空壳路由,此项可为空。 50: */ 51: pageId?: string; 52: /** 53: * 子路由 54: * 55: * 构建复杂应用(如带侧边栏、顶部导航的后台框架)的核心。 56: * 57: * 架构规约: 58: * 59: * 如果此数组不为空,则当前路由的 `pageId` 对应的 Page,不再是一个终端页面, 60: * 而是一个带有“插槽”的布局容器。它的内部组件树中必须包含一个 `type: 'Outlet'` 的组件, 61: * 用于动态渲染其子孙 Route 所绑定的 Page。 62: */ 63: children?: Route[]; 64: /** 65: * 交互 66: * 67: * 路由级生命周期与拦截器 68: * 69: * 在进入或离开该路由时触发的高阶控制流。 70: * 71: * 引擎实现指引: 72: * 1. 常用于“路由守卫 (Navigation Guards)”:例如在进入 '/admin' 前, 73: * 执行一个校验 Token 的 Action,若校验失败,则执行一个 Redirect Action 踢回登录页。 74: * 2. 常见事件如:`onEnter` (进入前), `onLeave` (离开前)。 75: * 76: * 如果当前路由无拦截逻辑,则必须为空数组 `[]`(而非 undefined)。 77: */ 78: interactions: Interaction[]; 79: } (End of file - total 79 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.9s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\interaction\\interaction.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\interaction\interaction.ts file 1: import type { Entity } from '../shared'; 2: import type { Action } from './action'; 3: 4: /** 5: * 实体交互 6: * 7: * 泛化事件侦听器 8: * 9: * 【架构定位】: 10: * 11: * 低代码平台中负责响应任何“状态突变”的唯一入口。 12: * 它的名字虽叫 Interaction(人机交互),但在架构底层,它不仅监听物理鼠标键盘, 13: * 更监听系统级的数据流转。 14: * 15: * 【引擎实现指引】: 16: * 17: * 根据它所挂载的宿主实体不同,引擎应将其映射为不同的事件绑定: 18: * 1. 挂载于 Component:映射为 DOM 原生事件或 React 组件暴露的业务事件(如 `onClick`, `onScroll`, `onRowSelect`)。 19: * 2. 挂载于 Route/Page:映射为生命周期钩子(如 `onEnter`, `onLoad`)。 20: * 3. 挂载于 Query/Mutation/Variable:映射为数据流的状态回调(如 `onSuccess`, `onError`, `onChange`)。 21: */ 22: export interface Interaction extends Entity { 23: /** 24: * 触发时机/事件名称 (Event Name) 25: * 26: * 引擎会根据此名称去注册对应的监听器。 27: */ 28: event: string; 29: /** 30: * 触发频率控制 (Debounce & Throttle) 31: * 32: * 处理高频数据流(如 Input 搜索框的 `onChange` 联动触发后端 Query)的核心防御机制。 33: * 34: * 引擎实现指引: 35: * 36: * 如果 enabled 为 true,引擎在派发底层的 `actions` 数组前, 37: * 必须先经过 Lodash 或 es-toolkit 的 `debounce` 或 `throttle` 包装器。 38: */ 39: control: { 40: enabled: boolean; 41: type: 'debounce' | 'throttle'; 42: delay: number; 43: }; 44: /** 45: * 原生事件修饰符 (Event Modifiers) 46: * 47: * 引擎实现指引: 48: * 49: * 仅当该 Interaction 是由原生 DOM 事件(如 onClick 冒泡或 Form 默认提交)触发时生效。 50: * 如果是 `Query.onSuccess` 这种纯逻辑事件,此配置应被忽略。 51: */ 52: modifiers: { 53: preventDefault: boolean; 54: stopPropagation: boolean; 55: }; 56: /** 57: * 动作执行序列 (Action Chain) 58: * 59: * 当事件触发(且通过频率控制与修饰符拦截)后,引擎需要按顺序串行(或并行)执行的命令集合。 60: * 61: * 必须为一个数组,允许一个按钮点击同时触发“保存数据”和“跳转页面”两个动作。 62: */ 63: actions: Action[]; 64: } (End of file - total 64 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.5s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\interaction\\action.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\interaction\action.ts file 1: import type { Entity, Condition, DynamicExpression, JsonValue } from '../shared'; 2: 3: /** 4: * 执行动作的目标实体 5: * 6: * 泛化 RPC 命令动作 (Generalized RPC Command Action) 7: * 8: * 【架构定位】: 9: * 10: * 这是整个交互体系的巅峰设计。 11: * 我们坚决拒绝将 Action 枚举化为 `ShowToast`, `Navigate`, `SetVariable` 等海量具体类型。 12: * 相反,我们采用极其抽象的“一切皆实体(Entity),一切皆方法(Method)”模型。 13: * 14: * 架构优势: 15: * 16: * 这种极致抽象保持了 Schema 结构的极简与统一。未来设计器新增几百种组件或系统能力时, 17: * Schema 结构一行代码都不用改;渲染引擎只需要一个通用的“方法派发器(Method Dispatcher)”即可支撑无限的扩展能力。 18: */ 19: export interface Action extends Entity { 20: /** 21: * 命令目标 (Target Entity) 22: * 23: * 告诉引擎:这个命令是发给谁的? 24: * 25: * 目标类型举例: 26: * - `type: 'component'`: 调用画布上的组件(如让图表刷新,或动态修改其 layout)。 27: * - `type: 'variable'`: 调用全局变量(如修改当前用户的值)。 28: * - `type: 'query'`: 调用全局查询(如手动触发一次 `execute()` 发起网络请求)。 29: * - `type: 'system'`: 极其关键!调用引擎提供的全局系统服务(如 `id: 'router'` 进行跳转,或 `id: 'message'` 弹出 Toast)。 30: */ 31: target: { 32: type: string; 33: id: string; 34: }; 35: /** 36: * 目标方法名 (Method Name) 37: * 38: * 目标实体向外暴露的、可供执行的函数名。 39: * 40: * 例:组件暴露的 `updateLayout`,系统路由服务暴露的 `navigateTo`。 41: */ 42: method: string; 43: /** 44: * 执行动作的条件 45: * 46: * 动作级拦截器 (Action Execution Condition) 47: * 48: * 在执行此单一动作前的高阶逻辑判断。 49: * 50: * 若存在此字段且求值为 false,引擎将静默跳过此动作的执行,继续执行下一个动作。 51: */ 52: condition?: Condition; 53: /** 54: * 方法调用入参 (Method Parameters Payload) 55: * 56: * 传递给 `method` 的额外数据。 57: * 58: * 采用“双模设计 (Dual-Mode)”: 59: * 既支持固定的 JSON 字典(fixed),也支持极其强大的代码逃生舱(code), 60: * 允许在触发动作的一瞬间,通过 JS 代码动态拼装入参(如提取事件源 event 的值)。 61: */ 62: params?: ActionParams; 63: } 64: 65: export type ActionParams = ActionParamsByFixed | ActionParamsByCode; 66: 67: /** 68: * 静态表单参数模式 69: * 70: * 适用于大部分常规场景(如打开弹窗时传个死参数)。 71: * payload 里的值在设计时即已确定。 72: */ 73: export interface ActionParamsByFixed { 74: type: 'fixed'; 75: payload: Record; 76: } 77: 78: /** 79: * 动态代码参数模式 (代码逃生舱) 80: * 81: * 业务场景: 82: * 当你需要“点击表格的某一行,提取这一行的数据 ID,传给下一个页面或 Mutation”时。 83: * 你必须在此时动态执行一段 JS 函数,从上下文中提取事件源的数据,返回一个 params 对象。 84: */ 85: export interface ActionParamsByCode extends DynamicExpression {} (End of file - total 85 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.8s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\entity.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\entity.ts file 1: /** 2: * 实体基类 (Entity Base) 3: * 4: * 【架构定位】: 5: * 6: * 它是低代码平台中所有独立配置节点(如 Component, Variable, Query 等)的万物之源。 7: * 8: * 强制所有核心节点继承此接口,是为了确保整个 Schema 树在进行 9: * 扁平化映射(Normalization)、全局事件总线寻址、以及状态树订阅时, 10: * 拥有一个绝对统一、可依赖的唯一标识符(ID)。 11: */ 12: export interface Entity { 13: /** 14: * 实体的全局唯一标识符 (UUID / Unique ID) 15: * 16: * 引擎防呆指引: 17: * 必须保证该 ID 在整个应用 (Application) 的同类实体池中全局唯一。 18: * 渲染引擎在构建 React 列表或遍历 DOM 树时,将强依赖此字段作为 `key`。 19: * 同时,它也是 Action.target.id 进行 RPC 调用的核心靶点。 20: */ 21: id: string; 22: /** 23: * 实体的显示名称 (Display Label) 24: * 25: * 核心架构边界: 26: * 它仅仅用于设计器左侧的“图层面板”、“变量列表”或右侧“属性面板”向实施人员展示一个友好的中文名称 27: * (如:“提交按钮”、“获取用户列表查询”)。 28: * 29: * 坚决抵制在任何底层的 JS 表达式求值或数据流绑定中引用 `label`! 30: * (代码逻辑的引用必须依赖不可变的 `key` 或是系统分配的 `id`) 31: */ 32: label: string; 33: } (End of file - total 33 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.5s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\dynamic-expression.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\dynamic-expression.ts file 1: /** 2: * 动态代码表达式 (Dynamic Expression) 3: * 4: * 【架构定位】: 5: * 6: * 这是整个低代码平台实现“图灵完备性”和“动态数据流”的终极逃生舱 (Ultimate Escape Hatch)。 7: * 8: * 无论是组件属性 (props) 的动态求值、查询条件 (Condition) 的逻辑判断, 9: * 还是数据清洗管道 (Filter) 的转换逻辑,全部收敛于此接口。 10: * 11: * 【引擎沙箱与执行指引 (Sandbox Execution Guide)】: 12: * 13: * 1. 纯函数体特性: 14: * `code` 字段保存的绝不是一个完整的函数定义(如 `function foo() {}`), 15: * 而是**函数体内部的代码片段 (Function Body)**。 16: * 因此,用户在编写这段代码时,**必须显式地使用 `return` 语句返回最终的计算结果!** 17: * 18: * 2. 动态编译 (JIT Compilation): 19: * 渲染引擎在解析到带有 `type: 'code'` 的对象时,必须在运行时动态编译它。 20: * 标准做法是使用 `new Function(paramNames, codeString)`。 21: * 22: * 3. 全局上下文注入 (Context Injection): 23: * 引擎在调用编译后的函数时,必须将当前应用的全局状态快照,封装为一个 `context` 对象注入其中。 24: * `context` 至少包含: 25: * - `variables`: 当前所有全局变量的最新值。 26: * - `queries`: 当前所有数据查询的最新状态 (data, isLoading, error)。 27: * - (可选) `event`: 当该表达式在交互动作 (Interaction) 中被执行时,触发它的源生事件对象。 28: * 29: * 示例: 30: * 31: * { 32: * type: 'code', 33: * code: "const user = context.variables.currentUser; return user.role === 'admin' ? 'red' : 'blue';" 34: * } 35: */ 36: export interface DynamicExpression { 37: /** 38: * 引擎执行标识 (Type Discriminator) 39: * 40: * 明确告诉解析器:这是一个需要被丢进 JS 沙箱里去算的代码对象, 41: * 绝不是一个普通的拥有 `code` 属性的静态字典。 42: */ 43: type: 'code'; 44: /** 45: * 动态求值的纯函数代码体 (Function Body String) 46: * 47: * 引擎必须通过形如 `const fn = new Function('context', code)` 的方式实例化。 48: * 49: * 用户代码中必须包含合法的 `return` 语句(除非是用于执行纯副作用的 Action,但也建议 return)。 50: */ 51: code: string; 52: } (End of file - total 52 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.0s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\condition.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\condition.ts file 1: import type { DynamicExpression } from './dynamic-expression'; 2: 3: /** 4: * 核心逻辑条件分支 (Logical Condition) 5: * 6: * 【架构定位】: 7: * 8: * 低代码平台中负责“控制流拦截 (Control Flow Gatekeeping)”的最小原子单元。 9: * 10: * 广泛被复用于: 11: * 12: * 1. Component 的 `condition` (物理级挂载/销毁,类似于 v-if 或 Conditional Rendering) 13: * 2. Action 的 `condition` (交互动作是否被允许执行的拦截器) 14: * 3. Query 的 `enabled` (串行请求的依赖挂起开关) 15: * 16: * 【双模演进路线】: 17: * 18: * - Code 模式:MVP 阶段的基石,通过纯函数赋予实施人员图灵完备的逻辑判断能力。 19: * - Rules 模式:远期规划,通过基于 JSON 序列化的“可视化规则树”降低非研发人员的使用门槛。 20: */ 21: export type Condition = ConditionByCode | ConditionByRules; 22: 23: /** 24: * 纯代码条件判断 (Code Mode) 25: * 26: * 赋予实施人员极其灵活且强大的逻辑判断能力。 27: * 28: * 引擎执行指引 (JIT 编译): 29: * 30: * `code` 是一段接收 `context` 为入参的纯函数字符串。 31: * 引擎必须使用 `new Function('context', code)` 动态执行它。 32: * 实施人员可以从 `context` 中解构出当前应用的全局运行时状态(如 `variables`, `queries`), 33: * 并利用这些状态编写复杂的条件组合(如 `return context.variables.role === 'admin' && context.queries.checkAuth.data.isValid`)。 34: * 35: * 引擎防呆校验: 36: * 37: * 该函数执行的返回值**必须被引擎强行转换为 `boolean` 类型**(如使用 `!!result`), 38: * 任何非布尔值的返回都会导致控制流产生不可预期的歧义行为。 39: */ 40: export interface ConditionByCode extends DynamicExpression {} 41: 42: // TODO: 预留规则条件,用于可视化配置,暂不实现 43: /** 44: * 可视化规则树判断 (Rules Mode - 暂不实现) 45: * 46: * 专为“无代码(No-Code)”和业务人员设计的图形化逻辑配置模式。 47: * 48: * 业务场景: 49: * 当用户在设计器界面上,通过点击下拉框拼凑出诸如: 50: * [ “当前用户角色” “等于” “管理员” ] AND [ “当前订单状态” “不等于” “已取消” ] 51: * 这样的逻辑表达式时,设计器将把这些图形化选项序列化为一棵基于 JSON 的 Rule Tree。 52: * 53: * 引擎执行指引: 54: * 引擎需内置一个规则解析器 (Rule Evaluator),递归遍历这棵 JSON 树, 55: * 提取其中的运算符 (operator) 和变量引用 (field),最终运算得出一个 `boolean` 值。 56: */ 57: export type ConditionByRules = { 58: type: 'rules'; 59: // rules: Rule[]; 60: }; (End of file - total 60 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.2s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\json-value.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\json-value.ts file 1: /** 2: * JSON 原生可序列化值 (Strict JSON Serializable Value) 3: * 4: * 【架构定位】: 5: * 6: * 它是低代码 Schema 抵御脏数据污染的“类型铁壁 (Type Barrier)”。 7: * 8: * 核心背景: 9: * 10: * 低代码的 `design-mode` 配置蓝图,最终宿命是调用 `JSON.stringify` 存入数据库。 11: * 如果在 Schema 的属性(如 `props`, `data`)中滥用 `any` 或 `object`, 12: * 实施人员极易在配置中混入 `Function`, `Date`, `RegExp` 或类实例等非法对象, 13: * 这将导致序列化时数据丢失(变成死字符串或 undefined),引发毁灭性的页面崩溃。 14: * 15: * 此递归类型(Recursive Type)在 TypeScript 编译阶段, 16: * 就极其原教旨主义地封杀了所有非标准 JSON 类型的侵入。 17: */ 18: export type JsonValue = 19: | string 20: | number 21: | boolean 22: | null 23: | JsonValue[] 24: | { [key: string]: JsonValue }; (End of file - total 24 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.0s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\rest-request.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\rest-request.ts file 1: import type { DynamicExpression } from './dynamic-expression'; 2: import type { JsonValue } from './json-value'; 3: 4: /** 5: * RESTful 请求配置 6: * 7: * 【架构定位】: 8: * 9: * - 低代码平台底层网络 I/O 的通用描述符。 10: * - 广泛被 QueryConfig 和 MutationConfig 复用。 11: * 12: * 采用“顶层双模设计”, 13: * 在提供常规的可视化表单配置(fixed)的同时,保留了极客级别的代码逃生舱(code)。 14: */ 15: export type RestRequest = RestRequestByFixed | RestRequestByCode; 16: 17: /** 18: * 可视化表单请求配置 19: * 20: * 适用于 90% 的标准 HTTP 请求。 21: * 引擎会将这些配置项与全局的 DataSource 配置进行深度合并(Merge)。 22: */ 23: export interface RestRequestByFixed { 24: type: 'fixed'; 25: /** 26: * 关联的全局数据源 ID 27: * 28: * 引擎实现指引: 29: * 30: * 如果指定了 DataSource,引擎应提取该数据源的 baseUrl、params、headers, 31: * 并与当前请求的配置进行合并(当前请求的优先级更高)。 32: */ 33: dataSourceId?: string; 34: /** 35: * 请求路径 36: * 37: * 可以是完整的绝对路径(若无 dataSourceId 或需要跨域调用第三方 API), 38: * 也可以是相对路径(如 `/users`,引擎会自动拼接 DataSource 的 baseUrl)。 39: */ 40: url: string; 41: /** 42: * URL 查询参数 (Query String) 43: * 44: * 引擎防呆设计 (Poka-yoke): 45: * 46: * `params` 最终会被序列化拼接在 URL 后面(如 `?name=A&age=18`)。 47: * 坚决抵制在此处传入对象或数组!如果传入 `{ a: { b: 1 } }`, 48: * 多数底层客户端(如原生 Fetch 或默认配置的 Axios)会将其序列化为 `?a=[object Object]`, 49: * 这会导致后端网关解析崩溃且极其难以排查。 50: * 因此,类型被严格锁定为基础数据类型(Primitive Types)。 51: * 52: * 【核心架构:null 的显式抹除语义 (Explicit Erasure)】 53: * 54: * 引入 `null` 是为了解决局部请求“抹除”全局 DataSource 继承配置的刚需。 55: * 如果全局配置了 `params: { tenantId: '123' }`,而当前请求不需要带此参数, 56: * 用户必须在当前配置中显式设置 `params: { tenantId: null }`。 57: * 引擎在合并配置时,一旦遇到值为 `null` 的键,必须从最终的请求参数中将其物理删除。 58: */ 59: params?: Record; 60: /** 61: * HTTP 请求头 (Headers) 62: * 63: * 同上理,HTTP Headers 协议本身只接受字符串。 64: * 如果在 Axios 中传了一个对象(如 `headers: { Authorization: { token: '123' } }`), 65: * Axios 就会直接把这个对象序列化成 `[object Object]` 发给后端! 66: * 必须锁定为基础数据类型。 67: * 68: * 同样支持 `null` 值的显式抹除语义(常用于抹除全局继承的 Token 以调用第三方开放 API)。 69: */ 70: headers?: Record; 71: /** 72: * HTTP 请求体 (Payload / Body) 73: * 74: * 引擎实现指引: 75: * 不强制 body 一定是一个对象,用户可以根据需要自定义。 76: * 当 method 为 GET 时,此字段通常被底层 HTTP 客户端忽略。 77: * 78: * 必须使用 JsonValue 以守住存入数据库时的序列化底线,防止混入 Function 等非法对象。 79: */ 80: body?: JsonValue; 81: } 82: 83: /** 84: * 纯代码请求配置 (Code Mode 逃生舱) 85: * 86: * 解决低代码平台“图灵完备性不足”的终极武器。 87: * 88: * 业务场景: 89: * 90: * 当实施人员面临极度变态的鉴权或加密需求时 91: * (例如:需要提取当前时间戳、加上全局变量 token,混合后进行 MD5 加密, 92: * 最后生成动态的 Headers、签名 Params 和变异的 URL)。 93: * 这在可视化的 fixed 模式下是根本无法完成的。 94: * 95: * 引擎实现指引: 96: * 97: * `code` 是一段纯函数字符串。它接收全局上下文 `context` 作为参数 98: * (可解构出 `variables`, `queries` 等运行时状态)。 99: * 它必须 `return` 一个符合 `Omit` 结构的对象。 100: * 引擎在执行该函数(JIT 编译)后,拿着返回的对象去发真实的 HTTP 请求。 101: */ 102: export interface RestRequestByCode extends DynamicExpression { 103: /** 104: * 关联的全局数据源 ID 105: * 106: * 即使在使用代码动态生成请求体时,也依然可以继承底层 DataSource 的公共配置(如 baseUrl)。 107: */ 108: dataSourceId?: string; 109: } (End of file - total 109 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.5s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\css-properties.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\css-properties.ts file 1: export interface CSSProperties { 2: [key: string]: string | number | undefined; 3: } (End of file - total 3 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 3.9s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\shared\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\shared\index.ts file 1: export * from './dynamic-expression'; 2: export * from './condition'; 3: export * from './css-properties'; 4: export * from './entity'; 5: export * from './json-value'; 6: export * from './rest-request'; (End of file - total 6 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\variable\\variable.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\variable\variable.ts file 1: import type { Entity, JsonValue } from '../shared'; 2: import type { Interaction } from '../interaction'; 3: 4: /** 5: * 全局变量 6: * 7: * 【架构定位】: 8: * 9: * 1. 它是低代码平台的“响应式状态中枢(Reactive State Hub)”。 10: * 2. 它是连接组件(Component)的输入/输出、驱动查询(Query)动态刷新的核心媒介。 11: * 12: * 【引擎实现指引】: 13: * 14: * 渲染引擎启动时,必须扫描所有 Variable 节点,提取其 `key` 和初始 `value`, 15: * 并在内存中构建一个支持深度订阅的全局 Store(如 Zustand)。 16: * 17: * 当任何 Action(如 `setVariable`)修改了该 Store 中的值时, 18: * 引擎的响应式机制会自动触发所有绑定了该变量的组件重绘或 Query 重新请求。 19: */ 20: export interface Variable extends Entity { 21: /** 22: * 变量的键名,用于在表达式中作为变量名来引用 23: * 24: * 核心架构边界: 25: * 26: * 与仅用于 UI 展示的 `label` (如:"当前选中用户") 不同,`key` 是供 JIT 编译器在代码块中求值的真实引用名。 27: * (例如:在代码式的配置中通过 `context.variables.currentUser` 来访问它) 28: * 29: * 引擎约束: 30: * 31: * 1. 必须严格符合 JavaScript 变量命名规范(正则:/^[a-zA-Z_$][a-zA-Z0-9_$]*$/)。 32: * 2. 在当前应用 (Application) 的所有 Variables 列表中必须全局唯一。 33: * 3. 它是不可变的“主键”级数据,修改它可能导致海量已绑定的组件或查询报错(引用失效)。 34: */ 35: key: string; 36: /** 37: * 变量的类型,运行时类型守卫 38: * 39: * 决定了该变量在内存中允许存储的合法数据类型。 40: * 41: * 引擎在执行 `setVariable` Action 时,必须先根据此字段进行运行时类型校验 (Runtime Type Checking), 42: * 以防止用户将一个对象强行赋给一个声明为 'number' 的变量,从而引发灾难性的级联崩溃。 43: */ 44: type: 'string' | 'number' | 'boolean' | 'object' | 'array'; 45: /** 46: * 是否为可选变量,默认false 47: */ 48: optional: boolean; 49: /** 50: * 是否允许变量为null,默认false 51: */ 52: nullable: boolean; 53: /** 54: * 变量保存的值(初始值) 55: * 56: * 在 Schema 中,它仅仅代表应用首次加载时(或变量被重置时)的一个“静态快照”。 57: * 58: * 引擎约束: 59: * 60: * 为确保该初始快照可以被安全地序列化存入数据库,它必须是一个合法的纯净 JSON 结构, 61: * 坚决抵制在此处使用 Function, Date 等无法被 `JSON.stringify` 转换的类型。 62: */ 63: value: JsonValue; 64: /** 65: * 交互 66: * 67: * 变量级生命周期与状态监听 68: * 69: * 挂载于状态节点本身的高阶控制流。 70: * 71: * 引擎实现指引: 72: * 73: * 这是低代码中最强大的“连锁反应触发器(Chain Reaction Trigger)”。 74: * 当变量的值发生突变时触发(如 `event: 'onChange'`)。 75: * 76: * 典型场景: 77: * 78: * 1. 表单联动:当 `selectedProvince` 变量改变时,触发 Action 去清空 `selectedCity` 变量。 79: * 2. 异常监控:当 `errorCount` 变量突破阈值时,触发 Action 弹出一个警告对话框 (Modal)。 80: * 81: * 如果该变量无任何监听逻辑,必须为一个显式的空数组 `[]`。 82: */ 83: interactions: Interaction[]; 84: } (End of file - total 84 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.9s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\query\\query.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\query\query.ts file 1: import type { Entity, Condition } from '../shared'; 2: import type { Interaction } from '../interaction'; 3: import type { QueryConfig } from './query-config'; 4: 5: /** 6: * 数据查询配置 7: * 8: * 【架构定位】: 9: * 10: * 1. 它是低代码数据流“三层漏斗”模型的中间层(核心业务层)。 11: * 2. 遵循 CQRS 架构,专职处理幂等的“读操作(Read)”。 12: * 3. 它是连接底层 DataSource(协议层)与顶层 Component(视图层)的桥梁。 13: * 14: * 【引擎实现指引】: 15: * 16: * 渲染引擎应将其映射为一个强大的状态机(如 TanStack Query 的 `useQuery` 实例)。 17: * 18: * 它不应将 `isLoading`, `data`, `error` 等运行时快照存入此 Schema, 19: * 而是由引擎在全局内存(QueryClient)中动态维护这些衍生状态,供组件声明式地订阅。 20: */ 21: export interface Query extends Entity { 22: /** 23: * 执行条件 24: * 25: * 决定了该查询是否允许被发送(无论是因为页面加载、轮询还是组件订阅)。 26: * 27: * 核心场景(串行依赖): 28: * 29: * 当 Query B 需要用到 Query A 的返回结果作为参数时, 30: * 可在此配置 `enabled: { type: 'code', code: 'return !!context.queries.QueryA.data' }`。 31: * 引擎会挂起 Query B,直到 Query A 成功返回并填充了数据,Query B 才会被自动放行。 32: * 33: * 如果不填,默认允许执行。 34: */ 35: enabled?: Condition; 36: /** 37: * 页面加载时自动执行 38: * 39: * 性能优化的杀手锏。 40: * 41: * 如果为 true,引擎在路由命中(或应用启动)的极早期阶段, 42: * 在 UI 组件树还未开始渲染时,就提前向服务器发起请求。 43: * 这样当底层图表组件渲染完毕并尝试订阅此 Query 时,数据可能已经“热乎”地躺在缓存里了, 44: * 从而彻底消灭组件的初始白屏 Loading 时间。 45: */ 46: prefetch: boolean; 47: /** 48: * 定时轮询策略 49: * 50: * 数字大屏(Dashboard)的灵魂特性。赋予数据流实时刷新的能力。 51: */ 52: polling: { 53: /** 54: * 是否开启轮询 55: */ 56: enabled: boolean; 57: /** 58: * 轮询间隔时间(单位:毫秒 ms) 59: * 60: * 引擎实现指引:在页面不可见(浏览器标签页隐藏)时,引擎应智能暂停轮询以节省性能。 61: */ 62: interval: number; 63: }; 64: /** 65: * 过滤器管道 66: * 67: * 极其关键的数据转换层(Transform Layer)。 68: * 包含了一系列被引用的全局 Filter ID。 69: * 70: * 引擎实现指引: 71: * 72: * 当底层 API 返回原始 JSON 后,在存入 Query 内存缓存池(或喂给组件)之前, 73: * 必须将原始数据像接水管一样,串行流过这些 Filter 函数。 74: * data = filter3(filter2(filter1(rawData))) 75: * 76: * 优势:让组件拿到的永远是极其纯净、格式规整的业务数据(如 `[{ x, y }]` 数组), 77: * 实现了“一份原始接口数据,清洗出多种衍生视图”的极致复用。 78: */ 79: filterIds: string[]; 80: /** 81: * 交互 82: * 83: * 请求生命周期与副作用控制流 84: * 85: * 挂载于查询状态突变时的高阶事件侦听器。 86: * 87: * 引擎实现指引: 88: * 89: * 1. `onSuccess` (请求成功):常用于触发数据获取后的连锁反应(如更新某个全局 Variable,或弹出“数据同步成功”的 Toast)。 90: * 2. `onError` (请求失败):常用于统一拦截错误,触发异常上报或显示全局 Error Modal。 91: * 92: * 这将原本散落在组件里的异步回调地狱,完美收拢到了数据请求自身的配置中。 93: * 若无副作用,必须为一个显式的空数组 `[]`。 94: */ 95: interactions: Interaction[]; 96: /** 97: * 具体的请求协议配置 98: * 99: * 采用极其强大的“多态联合类型(Polymorphism Union Type)”。 100: * 101: * 它决定了这究竟是一个静态的 Mock 数据(Static), 102: * 还是一个通过 HTTP 调用的 REST 请求(Rest), 103: * 抑或是一个直连数据库执行的 SQL 语句(Database)。 104: * 105: * 引擎通过读取 `config.type` 决定派发给哪个底层的 DataSource 客户端去执行。 106: */ 107: config: QueryConfig; 108: } (End of file - total 108 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.0s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\query\\query-config.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\query\query-config.ts file 1: import type { DynamicExpression, JsonValue, RestRequest } from '../shared'; 2: 3: /** 4: * 数据查询核心配置 5: * 6: * 【架构定位】: 7: * 8: * 这是一个极其强大的多态联合类型 (Polymorphism Union Type)。 9: * 它决定了当前这个 `Query` 到底是通过什么“物理手段”去获取数据的。 10: * 11: * 引擎实现指引: 12: * 13: * 渲染引擎(或数据请求层)在执行 `Query` 时,必须写一个 `switch (config.type)`。 14: * 15: * - 如果是 'static',O(1) 复杂度直接返回内存里的死数据。 16: * - 如果是 'rest',提取其绑定的 dataSourceId,组装 Axios 请求发给网关。 17: * - 未来如果是 'database',则通过 WebSocket 或专用代理发给后端执行 SQL。 18: */ 19: export type QueryConfig = 20: | QueryConfigByStatic 21: | QueryConfigByRest 22: | QueryConfigByGraphql 23: | QueryConfigByDatabase 24: | QueryConfigByCode; 25: 26: /** 27: * 静态查询配置 28: * 29: * 核心价值: 30: * 31: * 1. 跨组件复用:定义如“全国省份列表”等被多个组件同时绑定的全局字典数据。 32: * 2. 接口 Mock:当后端真实 API 尚未开发完毕时,作为临时数据源占位。 33: * 一旦后端就绪,只需在设计器将此配置一键切换为 `QueryConfigByRest`, 34: * 所有绑定了此 Query 的前端组件无需任何修改即可平滑接入真数据。 35: */ 36: export interface QueryConfigByStatic { 37: type: 'static'; 38: /** 39: * 静态的、硬编码的全局数据。 40: * 必须是合法的纯净 JSON(使用 JsonValue 锁死序列化底线,坚决不用 any)。 41: */ 42: data: JsonValue; 43: } 44: 45: /** 46: * RESTful 查询配置 47: * 48: * 占据了低代码数据获取 90% 以上场景的主力网络通信配置。 49: */ 50: export interface QueryConfigByRest { 51: type: 'rest'; 52: /** 53: * HTTP 请求方法 54: * 55: * 注:在 CQRS 架构中,即使是一个 POST 请求(如 GraphQL 的查询,或带有复杂查询体的高级搜索), 56: * 只要它是幂等的且不修改服务端状态,它在低代码中依然属于 `Query`(查询),而非 `Mutation`(变更)。 57: */ 58: method: 'GET' | 'POST'; 59: /** 60: * 请求体配置 61: * 62: * 极其关键的双模逃生舱设计 (Dual-Mode Design): 63: * 它引入了定义在 `core/rest-request.ts` 中的 `RestRequest` 类型 64: * (`RestRequestByFixed | RestRequestByCode`)。 65: * 66: * 允许用户既能通过可视化表单填死 url/params, 67: * 又能通过手写 JS 代码,根据全局变量动态拼装出极其复杂的请求头和加密签名。 68: */ 69: request: RestRequest; 70: /** 71: * 接口超时时间 (毫秒 ms) 72: * 73: * 如果不启用,引擎应使用全局 DataSource 配置的超时,或默认的浏览器超时(如 30s)。 74: */ 75: timeout: { 76: enabled: boolean; 77: duration: number; 78: }; 79: } 80: 81: // TODO: GraphQL 查询配置,暂不实现 82: export interface QueryConfigByGraphql { 83: type: 'graphql'; 84: } 85: 86: // TODO: 数据库查询配置,暂不实现 87: export interface QueryConfigByDatabase { 88: type: 'database'; 89: } 90: 91: // TODO: 代码查询配置,暂不实现 92: export interface QueryConfigByCode extends DynamicExpression {} (End of file - total 92 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.8s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\mutation\\mutation.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\mutation\mutation.ts file 1: import type { Entity, RestRequest } from '../shared'; 2: import type { Interaction } from '../interaction'; 3: import type { MutationConfig } from './mutation-config'; 4: 5: /** 6: * 数据变更操作 7: * 8: * 【架构定位】: 9: * 10: * 1. 它是低代码数据流“三层漏斗”模型的写操作层(Write/Command)。 11: * 2. 遵循 CQRS 架构,专职处理具有副作用(Side-effects)的操作(如:提交表单、删除数据、点赞)。 12: * 13: * 【引擎实现指引】: 14: * 15: * 渲染引擎应将其映射为一个手动触发的执行器(如 TanStack Query 的 `useMutation` 实例)。 16: * 它绝对没有自动触发的能力(没有 prefetch,没有 polling,没有 enabled 挂起), 17: * 它只能在用户发生了交互动作(Interaction)后,通过派发 `invokeMethod` Action 被动调用执行。 18: */ 19: export interface Mutation extends Entity { 20: /** 21: * 具体的请求协议配置 22: * 23: * 采用极其强大的“多态联合类型(Polymorphism Union Type)”。 24: * 决定了这到底是一个通过 HTTP 调用的 REST 请求(Rest), 25: * 抑或是一个直连数据库执行的 INSERT/UPDATE/DELETE 语句(Database)。 26: * 27: * 引擎通过读取 `config.type` 决定派发给哪个底层的 DataSource 客户端去执行。 28: */ 29: config: MutationConfig; 30: /** 31: * 交互 32: * 33: * 请求生命周期与副作用控制流 34: * 35: * 挂载于数据变更操作成功或失败时的高阶事件侦听器。 36: * 这是整个低代码业务逻辑编排中最核心的“指挥中心”! 37: * 38: * 引擎实现指引: 39: * 40: * 1. 极其典型的业务串联 (Success Chain): 41: * 当表单提交成功 (`onSuccess`) -> 派发 Action 触发“获取用户列表(Query)”重新请求(刷新数据) 42: * -> 派发 Action 显示“提交成功”的全局 Toast -> 派发 Action 清空绑定的输入框变量。 43: * 2. `onError` (请求失败):用于统一拦截接口异常,并在前端触发容错或告警流程。 44: * 45: * 若无副作用,必须为一个显式的空数组 `[]`。 46: */ 47: interactions: Interaction[]; 48: } (End of file - total 48 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\mutation\\mutation-config.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\mutation\mutation-config.ts file 1: import type { DynamicExpression, RestRequest } from '../shared'; 2: 3: /** 4: * 数据变更核心配置引擎 5: * 6: * 【架构定位】: 7: * 8: * 这是一个多态联合类型 (Polymorphism Union Type)。 9: * 它决定了当前这个 `Mutation` 到底是通过什么“物理手段”去修改服务端状态的。 10: * 11: * 核心架构差异(与 QueryConfig 的对比): 12: * 13: * 坚决不允许存在 `MutationConfigByStatic`! 14: * 因为修改一个内存里的死数据(Mock)是没有任何业务意义的,写操作必定伴随着网络 I/O 或数据库操作。 15: */ 16: export type MutationConfig = 17: | MutationConfigByRest 18: | MutationConfigByGraphql 19: | MutationConfigByDatabase 20: | MutationConfigByCode; 21: 22: /** 23: * 1. RESTful 协议变更配置 (REST API) 24: * 25: * 占据了低代码数据变更 90% 以上场景的主力网络通信配置。 26: */ 27: export interface MutationConfigByRest { 28: type: 'rest'; 29: /** 30: * HTTP 请求方法 31: * 32: * 引擎防呆指引: 33: * 既然是写操作(Mutation),绝大部分符合 REST 语义的设计必须是以下四种动词。 34: * 坚决不要在此处允许出现 GET 请求! 35: */ 36: method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; 37: /** 38: * 请求体配置 39: * 40: * 极其关键的双模逃生舱设计 (Dual-Mode Design): 41: * 它引入了定义在 `core/rest-request.ts` 中的 `RestRequest` 类型 42: * (`RestRequestByFixed | RestRequestByCode`)。 43: * 44: * 这是低代码平台处理极度复杂的表单提交数据组装(如从多个 Variables 里提取数据并加密)的终极战场。 45: */ 46: request: RestRequest; 47: /** 48: * 接口超时时间 (毫秒 ms) 49: * 50: * 变更操作(如上传大文件或复杂计算)往往比查询需要更长的超时容忍度。 51: * 如果启用,引擎应使用全局 DataSource 配置的超时,或默认的浏览器超时。 52: */ 53: timeout: { 54: enabled: boolean; 55: duration: number; 56: }; 57: } 58: 59: // TODO: GraphQL 变更配置,暂不实现 60: export interface MutationConfigByGraphql { 61: type: 'graphql'; 62: } 63: 64: // TODO: 数据库变更配置,暂不实现 65: export interface MutationConfigByDatabase { 66: type: 'database'; 67: } 68: 69: // TODO: 代码变更配置,暂不实现 70: export interface MutationConfigByCode extends DynamicExpression {} (End of file - total 70 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.8s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\filter\\filter.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\filter\filter.ts file 1: import type { DynamicExpression, Entity } from '../shared'; 2: 3: /** 4: * 数据过滤器 5: * 6: * 【架构定位】: 7: * 8: * 低代码数据流管线中的“纯函数转换层 (Pure Function Transformer)”。 9: * 10: * 核心价值: 11: * 12: * 1. 解决后端接口返回的数据结构(如嵌套极深的 JSON)与前端图表组件要求的数据结构(如平铺的 [{x, y}] 数组)不匹配的终极痛点。 13: * 2. 它是全局实体,意味着写好一个“通用时间格式化”的 Filter,可以被大屏上 100 个不同的图表同时挂载复用。 14: * 15: * 【引擎实现指引】: 16: * 17: * 1. 它通常被组件的 `ComponentDataQuery` 通过 `filterIds` 数组引用。 18: * 2. 引擎在处理包含多个 Filter 的数组时,必须采用“管道模式 (Pipeline)”: 19: * 前一个 Filter 的返回值,必须作为后一个 Filter 的入参 `data` 传入。 20: * 即:finalData = filter3(filter2(filter1(rawData)))。 21: */ 22: export type Filter = FilterByCode | FilterByRules; 23: 24: /** 25: * 纯代码过滤器 26: * 27: * 赋予实施人员处理复杂数据转换(如 map, reduce, 多数组 join)的图灵完备能力。 28: * 29: * 引擎执行指引 (JIT 编译): 30: * 31: * 引擎在执行该 `code` 时,注入的 `context` 参数必须比普通情况多出一个极其关键的属性:`data`。 32: * 33: * 注入上下文示例: 34: * 35: * - `context.data`: 当前需要被清洗的原始数据(或者是上一个 Filter 吐出来的数据)。 36: * - `context.variables`: 全局变量(允许 Filter 根据当前状态动态调整清洗逻辑,例如:`if (variables.isMetric) return data * 1000`)。 37: * 38: * 引擎防呆校验: 39: * 40: * 该函数执行后,**必须有明确的 `return` 返回值**。 41: * 引擎若检测到返回 `undefined`,应考虑抛出警告,防止开发者漏写 return 导致数据流在管道中断裂。 42: */ 43: export interface FilterByCode extends Entity, DynamicExpression {} 44: 45: // TODO: 预留规则过滤器,用于可视化配置,暂不实现 46: /** 47: * 可视化规则过滤器 48: * 49: * 专为“无代码(No-Code)”和业务人员设计的图形化清洗管道。 50: * 51: * 业务场景: 52: * 53: * 用户不需要写 JS 代码,而是通过点击界面上的算子(Operators)进行串联。 54: * 例如配置一个数组: 55: * [ 56: * { action: 'pick', field: 'records' }, // 第一步:提取 records 字段 57: * { action: 'filter', field: 'age', op: '>', val: 18 }, // 第二步:过滤成年人 58: * { action: 'map', from: 'userName', to: 'label' } // 第三步:字段映射重命名 59: * ] 60: * 61: * 引擎执行指引: 62: * 63: * 引擎需内置一系列标准的清洗算子处理函数,根据上述 JSON 规则树, 64: * 在内存中动态组装并执行数据转换逻辑。 65: */ 66: export interface FilterByRules extends Entity { 67: type: 'rules'; 68: // rules: Rule[]; 69: } (End of file - total 69 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.6s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\data-source\\data-source.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\data-source\data-source.ts file 1: import type { DataSourceByDatabase } from './data-source-by-database'; 2: import type { DataSourceByRest } from './data-source-by-rest'; 3: 4: /** 5: * 数据源池 6: * 7: * 【架构定位】: 8: * 9: * 它是低代码数据流“三层漏斗”模型的最底层(第一层)。 10: * 11: * 核心职责: 12: * 13: * 1. 隔离通信协议:将 RESTful、GraphQL、Database(MySQL/PG) 等底层的网络协议或连接池配置, 14: * 与上层的业务逻辑(Query)彻底解耦。 15: * 2. 跨查询复用:为多个属于同一业务域的 Query 提供统一的 `baseUrl` 和鉴权 `headers` (如 Token), 16: * 实现一处配置,全局生效。 17: * 18: * 【引擎实现指引】: 19: * 20: * 当应用启动时,渲染引擎应扫描此列表,并在内存中为每个 DataSource 实例化一个专门的网络客户端 21: * (如针对 type: 'rest' 实例化一个配置了拦截器的 Axios 实例),以供上层 Query 调用。 22: */ 23: export type DataSource = DataSourceByRest | DataSourceByDatabase; (End of file - total 23 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.0s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\data-source\\data-source-by-rest.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\data-source\data-source-by-rest.ts file 1: import type { DynamicExpression, Entity } from '../shared'; 2: 3: /** 4: * RESTful 协议数据源 5: * 6: * 专用于配置基于 HTTP 的网络通信实体。 7: */ 8: export interface DataSourceByRest extends Entity { 9: /** 10: * 引擎路由标识:告诉引擎必须使用 Axios 或 Fetch 客户端来处理此数据源下的请求。 11: */ 12: type: 'rest'; 13: /** 14: * RESTful 数据源的核心配置 15: * 16: * 采用“顶层双模设计”: 17: * 既支持常规的可视化表单配置,也支持代码模式(应对极其复杂的动态鉴权计算,如时间戳签名)。 18: */ 19: config: DataSourceConfigByRest; 20: } 21: 22: export type DataSourceConfigByRest = 23: | DataSourceConfigByRestWithFixed 24: | DataSourceConfigByRestWithCode; 25: 26: /** 27: * REST 数据源的常规可视化配置 28: * 29: * 适用于 90% 的标准 HTTP 请求场景。 30: */ 31: export interface DataSourceConfigByRestWithFixed { 32: type: 'fixed'; 33: /** 34: * 基础路径 (Base URL) 35: * 36: * 必须是一个完整的绝对 URL(如 `https://api.datalive.com/v1`)。 37: * 38: * 保持 URL 的绝对独立性是防呆设计的关键,避免相对路径引发的拼接灾难。 39: */ 40: baseUrl: string; 41: /** 42: * 全局默认的 URL Query 参数 43: * 44: * 引擎在发送该数据源下的任何 Query 时,都会自动将此对象拼接到 URL 后。 45: * 46: * 为确保 Axios/Fetch 序列化的稳定性,仅允许基础数据类型(Primitive Types),坚决抵制对象或数组嵌套。 47: */ 48: params?: Record; 49: /** 50: * 全局默认的请求头 51: * 52: * 常用于存放如 `Authorization: Bearer ` 或 `x-tenant-id` 等鉴权信息。 53: * 54: * 同样仅限基础数据类型。 55: */ 56: headers?: Record; 57: } 58: 59: /** 60: * REST 数据源的代码配置模式 61: * 62: * 引擎执行指引: 63: * 64: * 传入的 code 函数必须 return 一个符合 `Omit` 结构的对象。 65: * 这赋予了实施人员在发请求前执行极度复杂的加密运算的终极权力。 66: */ 67: export interface DataSourceConfigByRestWithCode extends DynamicExpression {} (End of file - total 67 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\data-source\\data-source-by-database.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\data-source\data-source-by-database.ts file 1: import type { Entity } from '../shared'; 2: 3: // TODO: 数据库数据源, 暂不实现 4: export interface DataSourceByDatabase extends Entity { 5: type: 'database'; 6: } (End of file - total 6 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.7s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\application\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\application\index.ts file 1: export * from './application'; (End of file - total 1 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.6s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\component\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\component\index.ts file 1: export * from './component'; 2: export * from './component-data'; 3: export * from './component-layout'; (End of file - total 3 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.6s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\interaction\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\interaction\index.ts file 1: export * from './action'; 2: export * from './interaction'; (End of file - total 2 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\page\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\page\index.ts file 1: export * from './page'; 2: export * from './page-layout'; (End of file - total 2 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.7s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\query\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\query\index.ts file 1: export * from './query'; (End of file - total 1 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.9s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\mutation\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\mutation\index.ts file 1: export * from './mutation'; 2: export * from './mutation-config'; (End of file - total 2 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\filter\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\filter\index.ts file 1: export * from './filter'; (End of file - total 1 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.3s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\route\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\route\index.ts file 1: export * from './route'; (End of file - total 1 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.6s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\variable\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\variable\index.ts file 1: export * from './variable'; (End of file - total 1 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.6s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\src\\schema\\data-source\\index.ts" } ``` **Output:** ``` D:\Projects\Private\datalive-design\src\schema\data-source\index.ts file 1: export * from './data-source'; 2: export * from './data-source-by-database'; 3: export * from './data-source-by-rest'; (End of file - total 3 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.3s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\.gitignore" } ``` **Output:** ``` D:\Projects\Private\datalive-design\.gitignore file 1: # dependencies (bun install) 2: node_modules 3: 4: # output 5: out 6: dist 7: *.tgz 8: 9: # code coverage 10: coverage 11: *.lcov 12: 13: # logs 14: logs 15: _.log 16: report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 17: 18: # dotenv environment variable files 19: .env 20: .env.development.local 21: .env.test.local 22: .env.production.local 23: .env.local 24: 25: # caches 26: .eslintcache 27: .cache 28: *.tsbuildinfo 29: 30: # IntelliJ based IDEs 31: .idea 32: 33: # Finder (MacOS) folder config 34: .DS_Store (End of file - total 34 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.4s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\bun.lock" } ``` **Output:** ``` D:\Projects\Private\datalive-design\bun.lock file 1: { 2: "lockfileVersion": 1, 3: "configVersion": 1, 4: "workspaces": { 5: "": { 6: "name": "datalive-design", 7: "devDependencies": { 8: "@types/bun": "latest", 9: }, 10: "peerDependencies": { 11: "typescript": "^5", 12: }, 13: }, 14: }, 15: "packages": { 16: "@types/bun": ["@types/bun@1.3.4", "", { "dependencies": { "bun-types": "1.3.4" } }, "sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA=="], 17: 18: "@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="], 19: 20: "bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="], 21: 22: "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 23: 24: "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], 25: } 26: } (End of file - total 26 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.8s) **Tool: glob** **Input:** ```json { "pattern": ".cursor/**/*" } ``` **Output:** ``` No files found [Agent Usage Reminder] You called a search/fetch tool directly without leveraging specialized agents. RECOMMENDED: Use task with explore/librarian agents for better results: ``` // Parallel exploration - fire multiple agents simultaneously task(subagent_type="explore", load_skills=[], prompt="Find all files matching pattern X") task(subagent_type="explore", load_skills=[], prompt="Search for implementation of Y") task(subagent_type="librarian", load_skills=[], prompt="Lookup documentation for Z") // Then continue your work while they run in background // System will notify you when each completes ``` WHY: - Agents can perform deeper, more thorough searches - Background tasks run in parallel, saving time - Specialized agents have domain expertise - Reduces context window usage in main session ALWAYS prefer: Multiple parallel task calls > Direct tool calls ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.1s) **Tool: glob** **Input:** ```json { "pattern": "**/opencode.json" } ``` **Output:** ``` No files found [Agent Usage Reminder] You called a search/fetch tool directly without leveraging specialized agents. RECOMMENDED: Use task with explore/librarian agents for better results: ``` // Parallel exploration - fire multiple agents simultaneously task(subagent_type="explore", load_skills=[], prompt="Find all files matching pattern X") task(subagent_type="explore", load_skills=[], prompt="Search for implementation of Y") task(subagent_type="librarian", load_skills=[], prompt="Lookup documentation for Z") // Then continue your work while they run in background // System will notify you when each completes ``` WHY: - Agents can perform deeper, more thorough searches - Background tasks run in parallel, saving time - Specialized agents have domain expertise - Reduces context window usage in main session ALWAYS prefer: Multiple parallel task calls > Direct tool calls ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 4.1s) **Tool: glob** **Input:** ```json { "pattern": "CLAUDE.md" } ``` **Output:** ``` No files found [Agent Usage Reminder] You called a search/fetch tool directly without leveraging specialized agents. RECOMMENDED: Use task with explore/librarian agents for better results: ``` // Parallel exploration - fire multiple agents simultaneously task(subagent_type="explore", load_skills=[], prompt="Find all files matching pattern X") task(subagent_type="explore", load_skills=[], prompt="Search for implementation of Y") task(subagent_type="librarian", load_skills=[], prompt="Lookup documentation for Z") // Then continue your work while they run in background // System will notify you when each completes ``` WHY: - Agents can perform deeper, more thorough searches - Background tasks run in parallel, saving time - Specialized agents have domain expertise - Reduces context window usage in main session ALWAYS prefer: Multiple parallel task calls > Direct tool calls ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.1s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\docs\\应用运行模式架构规范.md" } ``` **Output:** ``` D:\Projects\Private\datalive-design\docs\应用运行模式架构规范.md file 1: # DatAlive 应用运行模式 (AppMode) 架构设计规范 2: 3: 在低代码/无代码平台的设计中,渲染引擎需要根据不同的上下文环境展现出不同的行为特征。为了保证底层架构的清晰与解耦,DatAlive 明确确立了 **AppMode(应用运行模式)** 的三态规范,并对“预览模式”与“运行模式”的功能边界进行了严格的界定。 4: 5: ## 1. 架构定位:AppMode 是运行时上下文,绝非 Schema 6: 7: 在架构设计的初期,极易将运行模式与应用的数据结构混为一谈。必须极其严厉地明确以下铁律: 8: 9: > **`AppMode` 绝对不属于需要存入数据库持久化的 `design-mode` Schema 蓝图!** 10: > Schema 描述的是“应用长什么样,有什么逻辑”,而 `AppMode` 决定的是“渲染引擎现在该用什么姿势来解析这份 Schema”。 11: 12: 在渲染引擎的前端代码实现中,`AppMode` 应当作为顶级组件的 Props(或全局环境变量)由外部宿主容器(Host Shell)显式注入: 13: 14: ```tsx 15: // AppMode 的三态枚举(定义于引擎层,而非 Schema 层) 16: export type AppMode = 17: | 'design' // 设计态:引擎进入“沙盒模式”,劫持交互与路由,渲染视觉辅助线。 18: | 'preview' // 预览态:放行业务事件,提供沉浸式体验,但挂载强大的白盒调试工具。 19: | 'runtime'; // 运行态:绝对纯净的运行环境,无任何设计器代码注入。 20: ``` 21: 22: ### 1.1 为什么拒绝使用 `publish` 作为模式? 23: 在架构设计中,必须将 **“底层渲染状态(Render State / AppMode)”** 与 **“应用版本生命周期(Lifecycle Status)”** 彻底解耦。 24: * `runtime`(运行时)是一个渲染引擎的“物理运行环境”。 25: * `publish`(发布)是一个应用的“版本流转动作”(如 `draft`, `testing`, `published`)。 26: 即便是本地测试的一个未发布的草稿版本,当它脱离设计器独立在手机上扫码预览时,其底层的渲染模式依然是 `runtime`。 27: 28: --- 29: 30: ## 2. 预览模式 (Preview) vs 运行模式 (Runtime):同源异构的双生子 31: 32: 如果抛开后端服务和数据存储介质不谈,纯粹从前端功能视角来看,**预览模式**和**运行模式**在底层逻辑上是 100% 同源的(共享同一套 Schema 渲染管线),但在外在表现上却截然不同。 33: 34: **一个形象的比喻:** 35: * **预览模式(Preview)**:是导演(开发者)在看**监视器**。画面里可能有收音麦克风穿帮、有场记板、有剧本标注。发现演员台词念错了,导演会喊“咔(报错)”,然后立刻重来。 36: * **运行模式(Runtime)**:是观众在电影院看**最终上映的电影**。画面绝对干净,剧情连贯,即便有个别穿帮镜头(Bug),电影也会继续放下去,绝不会突然黑屏跳出一段剧本代码。 37: 38: ### 2.1 核心功能差异对比 39: 40: | 维度 | 预览模式 (Preview Mode) | 运行模式 (Runtime Mode) | 设计模式 (Design Mode) | 41: | :--- | :--- | :--- | :--- | 42: | **目标用户** | 应用搭建者、实施人员 | 最终业务人员(如客服、仓管) | 平台实施人员 | 43: | **路由引擎 (Routing)** | 原生 `BrowserRouter` 或 Hash,独立窗口展示。 | 干净的业务地址(如 `/apps/my-dashboard`)。 | **强制隔离**:必须使用 `MemoryRouter`,防止点击 a 标签导致设计器真刷新或逃逸。 | 44: | **异常处理 (Error)** | **严厉的教练**:大张旗鼓地报错(Error Boundary 标红),将 JS 堆栈暴露在控制台。 | **温柔的服务员**:静默容错,降级 UI 或弹出温和的 Toast,绝不暴露底层堆栈。 | 忽略破坏性错误,保护画布不崩溃。 | 45: | **破坏性操作 (Mutation)**| 允许执行,但通常通过拦截器指向 Mock 或沙箱环境。 | 毫无保留地真实执行业务逻辑。 | **强力封杀**:引擎必须静默拦截所有的 `Mutation` 动作,防止在画布点击按钮删除了真实数据。 | 46: | **环境纯净度** | 包裹在调试器上下文中,注入各种 DevTools。 | 轻量级纯净容器。剔除所有设计器相关的 JS 胖包和无用 DOM。 | 挂载 `react-moveable` 等庞大的拖拽与辅助渲染引擎。 | 47: 48: --- 49: 50: ## 3. 预览模式专属辅助工具 (Preview Utilities) 深度展开 51: 52: 为了让“导演”能更好地排查“演员”的问题,预览模式必须配备一系列强大的领域特定(Domain-Specific)辅助工具。传统的浏览器 F12 DevTools 对低代码编译后的虚拟 DOM 是“瞎”的,因此必须集成以下工具: 53: 54: ### 3.1 低代码控制台 (Low-Code Console / Debugger) 55: 这是预览模式的核心灵魂,负责将低代码引擎内部的“黑盒状态”白盒化。 56: 1. **全局状态漫游器 (State Explorer)**: 57: * 实时展示当前应用中所有的全局变量(`Variables`)、查询快照(`Queries`)和组件暴露的运行时属性。 58: * 允许开发者手动 Override(覆盖)某个变量的值,实时观察页面的响应式变化。 59: 2. **数据流监控 (Network / Query Monitor)**: 60: * 拦截并展示所有的 `Query` 和 `Mutation` 执行情况(完美契合 TanStack Query DevTools)。 61: 3. **动作轨迹时间轴 (Action Tracer / Timeline)**(最难也是最核心): 62: * 解决低代码中最难排查的“连锁反应”Bug。 63: * 以瀑布流日志打印执行顺序:`[事件触发] -> [变量修改] -> [Query执行] -> [成功回调代码执行]`,让数据流转路径一目了然。 64: 4. **代码沙箱异常日志 (Code Sandbox Logger)**: 65: * 专门捕获用户手写的 `DynamicExpression` (如 `type: 'code'`) 中抛出的 JS 异常,将其劫持并优雅地打印在低代码控制台中。 66: 67: ### 3.2 组件审查器 (Component Inspector) 68: 在预览模式下,开发者有时需要快速定位 UI 问题,但又不想切回设计模式: 69: * **悬浮高亮 (Hover Outline)**:按住特定快捷键(如 `Alt` / `Option`)在页面上移动鼠标,被掠过的组件会显示高亮边框和其 `Entity.id`。 70: * **快捷跳转 (Quick Jump)**:点击被高亮的组件,利用 `postMessage` 与父级设计器通信,设计器立即在画布中选中该组件,右侧面板自动展开其配置项。 71: 72: --- 73: 74: ## 4. MVP 阶段的务实落地策略 75: 76: 在 DatAlive 的 MVP(最小可行性产品)阶段,我们采取 **“架构上严格区分,实现上极简降级”** 的策略: 77: 78: 1. **引擎入口的强约束**:在渲染引擎的顶层组件定义中,严格要求传入 `mode: AppMode`,并根据此字段进行核心模块(如 Router 和 拖拽层)的条件分支渲染。 79: 2. **借力生态实现控制台**:暂不自研复杂的 Action Tracer,而是直接在预览模式接入 ``(监控请求状态机)和开启 Redux/Zustand DevTools Middleware(监控变量变化),以极低成本获得企业级调试能力。 80: 3. **前端纯净路由闭环**:即使没有后端,运行模式(Runtime)也必须在一个独立的 HTML 页面下读取 `localStorage` 进行渲染,以此强制验证渲染引擎是否真正脱离了设计器的胖包上下文。 (End of file - total 80 lines) ``` --- ## Assistant (​Sisyphus - Ultraworker · Claude Opus 4.7 · 5.0s) **Tool: read** **Input:** ```json { "filePath": "D:\\Projects\\Private\\datalive-design\\docs\\实体生命周期引擎实现规范.md" } ``` **Output:** ``` D:\Projects\Private\datalive-design\docs\实体生命周期引擎实现规范.md file 1: # DatAlive 实体生命周期引擎实现规范 (Entity Lifecycle Implementation) 2: 3: ## 1. 设计理念:引擎驱动生命周期 (Engine-Driven Lifecycle) 4: 5: 在基于 React 19+ 生态的低代码架构中,由于 Strict Mode、Concurrent Rendering 和 Suspense 的存在,React 组件的真实挂载/卸载行为往往不可预测(例如组件可能被多次挂载/卸载以检查副作用)。 6: 7: 因此,DatAlive 平台中的“业务生命周期”**严禁直接等价于 React 的生命周期(如 `useEffect`)**。我们必须采用**引擎驱动**模式:由底层的 `RuntimeEngine` 根据路由状态、全局数据流或用户行为,**显式地派发(Emit)**各个实体的生命周期事件。React 仅仅作为“被动接收状态并渲染”的视图层。 8: 9: 在底层 Schema 的定义中,无论是路由跳转、数据请求回调还是用户点击,这一切所谓的“生命周期钩子”,均被统一收口并泛化为 **`Interaction`(泛化事件侦听器)**。 10: 11: --- 12: 13: ## 2. 实体生命周期映射与 Interaction 触发策略 14: 15: 目前设计器中允许配置 `interactions: Interaction[]` 字段的实体,及其引擎侧的触发策略定义如下: 16: 17: ### 2.1 Application (应用根节点) 18: 负责整个低代码应用启动和全局级别的状态拦截。 19: 20: | Interaction.event (触发器) | 触发时机 | 引擎实现策略 | 21: | :--- | :--- | :--- | 22: | `onLaunch` | 应用配置加载完成,准备渲染根节点前 | 在 React `createRoot().render()` 执行前,由引擎主动解析执行。可用于初始化全局变量、鉴权校验等。 | 23: | `onError` | 全局未捕获的运行时异常(含数据流异常) | 绑定在 React ErrorBoundary 顶层,以及 Zustand / TanStack Query 的全局 Error Handler 中。 | 24: 25: ### 2.2 Route & Page (路由与页面容器) 26: 视图层的状态闭环单元,处理路由切换带来的副作用(Route Guards)。 27: 28: | Interaction.event (触发器) | 触发时机 | 引擎实现策略 | 29: | :--- | :--- | :--- | 30: | `onEnter` (Route级) | 路由准备进入该页面前 (Route Guards) | 挂载在路由监听层。可在此处派发 Action 发起鉴权,若鉴权失败可触发 Redirect Action 踢回登录页。 | 31: | `onLoad` (Page级) | 页面组件挂载,且前置预热数据已就绪 | 在页面容器初始化时触发。常用于重置当前页面的局部 Variables,或发起非预热的懒加载 Query。 | 32: | `onLeave` (Route级) | 路由准备离开该页面之前 | 路由切换前触发。用于清理定时器、WebSocket 或清空重型数据变量。 | 33: | `onResize` (Page级) | (大屏特有) 画布或窗口尺寸发生变化 | 引擎统一在 `window.addEventListener('resize')` 中做防抖处理,然后派发给当前激活的 Page。 | 34: 35: ### 2.3 Component (视图原子组件) 36: 最核心的用户交互载体,其事件主要由 DOM 交互驱动,少部分由挂载周期驱动。 37: 38: | Interaction.event (触发器) | 触发时机 | 引擎实现策略 | 39: | :--- | :--- | :--- | 40: | **交互类**: `onClick`, `onMouseEnter`, `onChange` 等 | 用户与组件进行真实物理交互时 | 通过标准 React Props 传递给具体的组件实现,例如 `