diff --git a/.gitignore b/.gitignore index 8ff63ce66342fea52c1b56d249448252f222a72a..94d259b30cd2faeb0580214ecedad178aac424dc 100644 --- a/.gitignore +++ b/.gitignore @@ -59,7 +59,8 @@ node_modules/ # 其他文件过滤 -meta/apps/* -!meta/apps/caseapp/ -!meta/apps/testapp/ -!meta/apps/attendance/ +#meta/apps/* +#!meta/apps/caseapp/ +#!meta/apps/testapp/ +#!meta/apps/attendance/ +#!meta/apps/voteapp/ diff --git a/.qoder/quests/survey-system-development.md b/.qoder/quests/survey-system-development.md new file mode 100644 index 0000000000000000000000000000000000000000..c177ab93a6f5e9321150bee6f716b9b533359fdb --- /dev/null +++ b/.qoder/quests/survey-system-development.md @@ -0,0 +1,407 @@ +# 问卷系统开发设计文档 + +## 一、需求概述 + +在低代码平台中新增独立的问卷系统应用,实现问卷的创建、管理、分发和数据收集功能。系统支持从模板创建问卷,允许外部用户通过链接匿名填写,并提供基础的数据统计分析能力。 + +### 核心功能 +1. 问卷管理:新建空白问卷、从模板创建、将问卷设为模板、查看填写情况、复制填写地址 +2. 问卷填写:外部用户通过链接匿名填写问卷 +3. 模板管理:创建、编辑、分类管理模板库 +4. 题型支持:单选题、多选题、填空题、简答题 +5. 填写记录:查看问卷填写记录 + +## 二、应用元数据结构 + +### 2.1 应用定义 + +创建独立应用 survey + +### 2.2 菜单结构设计 + +采用树形菜单结构,包含以下主要菜单项: + +#### 根菜单 +- 问卷管理(目录) + - 我的问卷(菜单,显示已创建的问卷列表) + - 问卷模板(菜单,管理问卷模板) +- 填写记录(菜单,查看所有问卷的填写记录) + +## 三、数据源设计 + +### 3.1 数据表设计 + +#### 问卷表(tb_survey) + +存储问卷基本信息 + +| 字段名 | 字段类型 | 说明 | 约束 | +|--------|----------|------|------| +| f_id | varchar | 主键 | PK | +| f_title | varchar | 问卷标题 | NOT NULL | +| f_description | varchar | 问卷描述 | NULL | +| f_status | int | 问卷状态:0-草稿,1-发布中,2-已结束 | NOT NULL | +| f_is_template | bool | 是否为模板 | NOT NULL, 默认false | +| f_template_category | varchar | 模板分类 | NULL | +| f_source_template_id | varchar | 来源模板ID | NULL | +| f_allow_anonymous | bool | 允许匿名填写 | NOT NULL, 默认true | +| f_start_time | datetime | 开始时间 | NULL | +| f_end_time | datetime | 结束时间 | NULL | +| f_max_submissions | int | 最大提交次数限制,0表示不限制 | NULL | +| f_creator_id | varchar | 创建人ID | NULL | +| f_create_time | datetime | 创建时间 | NOT NULL | +| f_update_time | datetime | 更新时间 | NULL | + +#### 题目表(tb_question) + +存储问卷题目信息 + +| 字段名 | 字段类型 | 说明 | 约束 | +|--------|----------|------|------| +| f_id | varchar | 主键 | PK | +| f_survey_id | varchar | 所属问卷ID | NOT NULL, FK | +| f_question_type | int | 题目类型:1-单选,2-多选,3-填空,4-简答 | NOT NULL | +| f_title | varchar | 题目标题 | NOT NULL | +| f_description | varchar | 题目说明 | NULL | +| f_is_required | bool | 是否必填 | NOT NULL, 默认false | +| f_order | int | 题目排序号 | NOT NULL | +| f_create_time | datetime | 创建时间 | NOT NULL | + +#### 选项表(tb_question_option) + +存储单选题和多选题的选项 + +| 字段名 | 字段类型 | 说明 | 约束 | +|--------|----------|------|------| +| f_id | varchar | 主键 | PK | +| f_question_id | varchar | 所属题目ID | NOT NULL, FK | +| f_option_text | varchar | 选项文本 | NOT NULL | +| f_order | int | 选项排序号 | NOT NULL | +| f_create_time | datetime | 创建时间 | NOT NULL | + +#### 填写记录表(tb_submission) + +存储问卷填写记录 + +| 字段名 | 字段类型 | 说明 | 约束 | +|--------|----------|------|------| +| f_id | varchar | 主键 | PK | +| f_survey_id | varchar | 问卷ID | NOT NULL, FK | +| f_submitter_id | varchar | 填写人ID,匿名时为空 | NULL | +| f_submitter_name | varchar | 填写人姓名 | NULL | +| f_submit_time | datetime | 提交时间 | NOT NULL | +| f_ip_address | varchar | 提交IP地址 | NULL | +| f_is_complete | bool | 是否完整提交 | NOT NULL, 默认true | + +#### 填写答案表(tb_answer) + +存储具体答案内容 + +| 字段名 | 字段类型 | 说明 | 约束 | +|--------|----------|------|------| +| f_id | varchar | 主键 | PK | +| f_submission_id | varchar | 填写记录ID | NOT NULL, FK | +| f_question_id | varchar | 题目ID | NOT NULL, FK | +| f_answer_text | varchar | 文本答案(填空题、简答题) | NULL | +| f_selected_options | varchar[] | 选中的选项ID数组(单选题、多选题) | NULL | +| f_create_time | datetime | 创建时间 | NOT NULL | + +## 四、页面设计 + +### 4.1 我的问卷页面(page_my_surveys) + +#### 页面布局 +采用列表布局(playout: 0),顶部操作区+表格列表 + +#### 数据源绑定 +- 数据源类型:DB +- 绑定数据表:tb_survey +- 查询条件:f_is_template = false + +#### 页面组件结构 + +**顶部操作区** +- 搜索框组件:搜索问卷标题 +- 状态筛选下拉框:筛选草稿、发布中、已结束 +- 新建空白问卷按钮 +- 从模板创建按钮 + +**问卷列表表格** + +表格列配置: + +| 列名 | 字段 | 说明 | 宽度 | +|------|------|------|------| +| 问卷标题 | f_title | 可点击进入编辑 | 自适应 | +| 状态 | f_status | 显示文本映射 | 100px | +| 创建时间 | f_create_time | 格式化显示 | 150px | +| 提交数量 | - | 关联统计 | 100px | +| 操作 | - | 操作按钮组 | 300px | + +操作列包含按钮: +- 编辑:进入问卷编辑页面 +- 预览:查看问卷填写效果 +- 复制链接:复制问卷填写地址 +- 设为模板:将问卷转为模板 +- 查看统计:进入数据统计页面 +- 删除:删除问卷(需确认) + +#### 页面交互逻辑 + +**新建空白问卷流程** +1. 点击"新建空白问卷"按钮 +2. 弹出模态框,输入问卷标题和描述 +3. 创建问卷记录(状态为草稿) +4. 跳转到问卷编辑页面 + +**从模板创建流程** +1. 点击"从模板创建"按钮 +2. 弹出模板选择对话框,显示可用模板列表 +3. 选择模板后确认 +4. 复制模板内容创建新问卷 +5. 跳转到问卷编辑页面 + +### 4.2 问卷编辑页面(page_survey_editor) + +#### 页面布局 +采用自定义布局(playout: 3) + +#### 数据源绑定 +- 主数据源:tb_survey(单条记录) +- 关联数据源:tb_question、tb_question_option + +#### 页面结构 + +**左侧:题目类型面板** +- 单选题 +- 多选题 +- 填空题 +- 简答题 + +支持拖拽题型到中间画布区域 + +**中间:问卷编辑画布** +- 问卷标题输入框 +- 问卷描述文本域 +- 题目列表区域(可排序、可删除) + +**每个题目编辑卡片包含:** +- 题目类型标识 +- 题目标题输入框 +- 题目说明输入框 +- 是否必填开关 +- 选项编辑区(单选/多选题) + - 选项文本输入框列表 + - 添加选项按钮 + - 删除选项按钮 +- 题目上移/下移按钮 +- 删除题目按钮 + +**右侧:问卷设置面板** +- 问卷状态选择(草稿/发布中/已结束) +- 允许匿名填写开关 +- 开始时间选择 +- 结束时间选择 +- 最大提交次数输入框 +- 保存按钮 +- 发布按钮 +- 预览按钮 + +#### 数据保存逻辑 + +**保存草稿** +- 验证问卷标题不为空 +- 保存问卷基本信息到 tb_survey +- 保存所有题目到 tb_question +- 保存单选/多选题选项到 tb_question_option +- 清理已删除的题目和选项 + +**发布问卷** +- 验证至少包含一个题目 +- 验证单选/多选题至少包含两个选项 +- 更新问卷状态为"发布中" +- 生成问卷填写链接 + +### 4.3 问卷填写页面(page_survey_fill) + +#### 页面布局 +采用表单布局(playout: 1),适配移动端 + +#### 数据源绑定 +- 只读数据源:tb_survey、tb_question、tb_question_option +- 写入数据源:tb_submission、tb_answer + +#### 页面结构 + +**顶部区域** +- 问卷标题显示 +- 问卷描述显示 +- 必填项说明提示 + +**题目区域** +依次渲染每个题目,根据题目类型展示不同组件: + +- 单选题:Radio 组件 +- 多选题:Checkbox 组件 +- 填空题:Input 组件 +- 简答题:TextArea 组件 + +必填题目显示红色星号标识 + +**底部区域** +- 提交按钮 + +#### 填写提交逻辑 + +**页面加载** +1. 通过URL参数获取问卷ID +2. 查询问卷基本信息,验证问卷状态 +3. 查询所有题目和选项 +4. 渲染问卷内容 + +**提交验证** +1. 验证所有必填题目是否已填写 +2. 验证问卷是否在有效期内 +3. 验证是否超过最大提交次数限制 + +**数据保存** +1. 创建填写记录到 tb_submission +2. 保存每个题目的答案到 tb_answer +3. 提交成功后显示感谢页面 + +### 4.4 问卷模板页面(page_survey_templates) + +#### 页面布局 +采用卡片网格布局 + +#### 数据源绑定 +- 数据源类型:DB +- 绑定数据表:tb_survey +- 查询条件:f_is_template = true + +#### 页面结构 + +**顶部操作区** +- 模板分类筛选下拉框 +- 搜索模板输入框 +- 新建模板按钮 + +**模板卡片网格** + +每个模板卡片显示: +- 模板标题 +- 模板描述 +- 模板分类标签 +- 题目数量 +- 创建时间 +- 操作按钮:编辑、预览、使用模板、删除 + +#### 模板分类 + +预定义分类: +- 满意度调查 +- 信息收集 +- 活动报名 +- 意见反馈 +- 市场调研 +- 其他 + +### 4.5 填写记录页面(page_submission_records) + +#### 页面布局 +采用列表布局 + +#### 数据源绑定 +- 数据源类型:DB +- 绑定数据表:tb_submission + +#### 页面结构 + +**筛选区** +- 问卷选择下拉框 +- 时间范围选择器 +- 完成状态筛选 + +**记录列表表格** + +表格列配置: + +| 列名 | 字段 | 说明 | +|------|------|------| +| 问卷标题 | f_survey_id | 关联显示 | +| 填写人 | f_submitter_name | 匿名显示"匿名用户" | +| 提交时间 | f_submit_time | 格式化显示 | +| IP地址 | f_ip_address | - | +| 完成状态 | f_is_complete | 是/否 | +| 操作 | - | 查看详情、删除 | + +**详情查看** +- 点击"查看详情"弹出模态框 +- 显示该次提交的所有题目和答案 + +## 五、业务流程设计 + +### 5.1 问卷创建流程 + +```mermaid +graph TD + A[开始] --> B{选择创建方式} + B -->|新建空白问卷| C[输入问卷标题和描述] + B -->|从模板创建| D[选择问卷模板] + C --> E[创建问卷记录] + D --> F[复制模板内容] + F --> E + E --> G[进入问卷编辑页面] + G --> H[添加题目] + H --> I[配置题目属性] + I --> J{继续添加?} + J -->|是| H + J -->|否| K[设置问卷属性] + K --> L{选择操作} + L -->|保存草稿| M[保存到数据库] + L -->|发布问卷| N[验证问卷完整性] + N --> O[更新状态为发布中] + O --> P[生成填写链接] + M --> Q[结束] + P --> Q +``` + +### 5.2 问卷填写流程 + +```mermaid +graph TD + A[访问填写链接] --> B[加载问卷信息] + B --> C{问卷是否有效?} + C -->|否| D[显示问卷已结束] + C -->|是| E[渲染问卷题目] + E --> F[用户填写答案] + F --> G[点击提交] + G --> H{验证必填项} + H -->|未填完整| I[提示补充必填项] + I --> F + H -->|已填完整| J{验证提交限制} + J -->|超过限制| K[提示已达提交上限] + J -->|未超过| L[创建提交记录] + L --> M[保存答案数据] + M --> N[显示感谢页面] + D --> O[结束] + K --> O + N --> O +``` + +### 5.3 模板管理流程 + +```mermaid +graph TD + A[开始] --> B{操作类型} + B -->|创建新模板| C[新建空白问卷] + B -->|问卷转模板| D[选择已有问卷] + C --> E[设计问卷内容] + D --> F[设置模板属性] + E --> F + F --> G[选择模板分类] + G --> H[标记为模板] + H --> I[保存到模板库] + I --> J[模板可被使用] + J --> K[结束] +``` diff --git "a/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204.md" "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..a8c3ca53f793ccb5ccec0733a857248f484dd7e7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204.md" @@ -0,0 +1,467 @@ +# 元数据架构 + + +**本文档引用的文件** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs) +- [ComponentStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs) +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [SupportPlatformEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/SupportPlatformEnum.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) + + +## 目录 +1. [元数据架构概述](#元数据架构概述) +2. [应用元数据结构](#应用元数据结构) +3. [页面元数据结构](#页面元数据结构) +4. [组件元数据结构](#组件元数据结构) +5. [设计时与运行时元数据对比](#设计时与运行时元数据对比) +6. [核心元模型UML类图](#核心元模型uml类图) + +## 元数据架构概述 + +本系统采用分层元数据架构,将元数据划分为基础模型、设计时模型和运行时模型三个层次。基础模型定义了应用、页面和组件的通用结构,设计时模型扩展了拖拽、状态管理等可视化编辑所需的信息,运行时模型则专注于渲染性能和数据绑定。元数据通过JSON序列化存储于`meta`目录下,支持文件存储和远程服务两种持久化方式。 + +**元数据架构分层** +- **基础元模型**:定义通用字段和继承关系 +- **设计时元模型**:包含拖拽状态、组件物料信息 +- **运行时元模型**:优化渲染性能,合并属性定义 + +```mermaid +graph TB +subgraph "元数据分层" +Base[基础元模型] --> Design[设计时元模型] +Base --> Render[运行时元模型] +end +subgraph "存储" +Design --> JsonFile[JSON文件] +Render --> RemoteService[远程服务] +end +``` + +**图示来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) + +## 应用元数据结构 + +应用元数据(AppSchema)定义了低代码应用的基本信息、发布状态和支持平台。所有应用元数据均继承自`AppSchemaBase`抽象类,该类定义了应用的核心属性。 + +### 基础字段 +- **Id**:应用唯一标识符 +- **Name**:应用名称(JSON属性名:n) +- **Icon**:应用图标 +- **Picture**:应用封面图(JSON属性名:pic) +- **Description**:应用描述(JSON属性名:desc) +- **Version**:版本号(JSON属性名:v) +- **PublishStatus**:发布状态(JSON属性名:pub) +- **SupportPlatforms**:支持平台数组(JSON属性名:platform) + +### 发布状态枚举 +```csharp +public enum PublishStatusEnum +{ + Development, // 开发中 + Approving, // 审核中 + Published // 已发布 +} +``` + +### 支持平台枚举 +```csharp +public enum SupportPlatformEnum +{ + [Display(Name = "Web")] + Web, + [Display(Name = "App")] + Mobile, + [Display(Name = "小程序")] + WXMiniApp +} +``` + +**示例JSON** +```json +{ + "id": "caseapp", + "n": "案例应用", + "pic": "/images/caseapp.jpg", + "desc": "低代码开发示例应用", + "v": "1.0.0", + "pub": 2, + "platform": [0, 1] +} +``` + +**中文说明** +- `pub`值为2表示"已发布" +- `platform`中0代表Web,1代表App + +**本节来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs#L4-L27) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [SupportPlatformEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/SupportPlatformEnum.cs) + +## 页面元数据结构 + +页面元数据(PageSchema)定义了页面的布局、组件列表、数据源引用和事件处理逻辑。页面元数据继承自`PageSchemaBase`类,并在设计时和运行时有不同的扩展。 + +### 基础字段 +- **AppId**:所属应用ID(JSON属性名:aid) +- **Id**:页面唯一ID(JSON属性名:id) +- **Name**:页面名称(JSON属性名:n) +- **Order**:排序序号(JSON属性名:order) +- **PageType**:页面类型(JSON属性名:pt) +- **PublishStatus**:发布状态(JSON属性名:pub) +- **PageProperty**:页面属性(JSON属性名:pageprop) +- **DataSource**:数据源配置(JSON属性名:ds) +- **Events**:事件列表(JSON属性名:evs) + +### 页面类型枚举 +```csharp +public enum PageTypeEnum +{ + [Display(Name = "普通")] + Normal = 0, + [Display(Name = "表单")] + Form = 1, + [Display(Name = "列表")] + Table = 2, + [Display(Name = "报表")] + Report = 5 +} +``` + +### 设计时扩展字段 +- **Components**:组件列表(JSON属性名:comps) +- **SupportEvents**:支持的事件数组(JSON属性名:sptevs) + +### 运行时扩展字段 +- **Components**:运行时组件列表(JSON属性名:comps) + +**示例JSON** +```json +{ + "aid": "caseapp", + "id": "0lgu6xpop", + "n": "用户管理", + "order": 1, + "pt": 2, + "pub": 2, + "pageprop": { + "layout": "default" + }, + "ds": { + "type": "sql", + "query": "SELECT * FROM users" + }, + "evs": [ + { + "en": "OnLoad", + "eht": 1, + "etid": "grid1", + "eta": "Refresh" + } + ], + "comps": [] +} +``` + +**本节来源** +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs#L5-L39) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) + +## 组件元数据结构 + +组件元数据(ComponentSchema)是元数据架构中最复杂的部分,包含属性定义、样式配置、事件绑定和验证规则。 + +### 基础字段 +- **Id**:组件实例ID(JSON属性名:id) +- **ParentId**:父组件ID(JSON属性名:pid) +- **Name**:组件名称(JSON属性名:n) +- **Label**:标签文本(JSON属性名:lb) +- **IsHiddenLabel**:是否隐藏标题(JSON属性名:hlb) +- **IsContainer**:是否为容器组件(JSON属性名:container) +- **IsSupportDataSource**:是否支持数据源(JSON属性名:sptds) +- **Style**:样式配置(JSON属性名:stl) +- **Events**:事件列表(JSON属性名:evs) +- **EventConsumes**:事件消费列表(JSON属性名:evcs) +- **Description**:描述(JSON属性名:desc) + +### 属性定义 +组件属性定义继承自`ComponentAttributeDefineSchemaBase`,包含: +- **AttributeName**:属性名称(JSON属性名:attrn) +- **AttributeClrType**:CLR类型(JSON属性名:attrt) +- **AttributeValue**:属性值(JSON属性名:attrv) + +### 样式配置 +`ComponentStyleSchema`定义了组件的布局样式: +- **ItemWidth**:组件宽度(4-24栅格,JSON属性名:itemw) +- **ItemHeight**:组件高度(单位:px,JSON属性名:itemh) +- **LabelWidth**:标签宽度(默认180px,JSON属性名:labelw) +- **DefaultStyle**:默认样式(JSON属性名:dfstl) +- **CustomStyle**:自定义样式(JSON属性名:ctstl) + +### 事件绑定 +`EventSchema`定义了事件处理逻辑: +- **EventName**:事件名称(JSON属性名:en) +- **EventHandlerType**:事件处理器类型(JSON属性名:eht) +- **EventTargetId**:事件目标ID(JSON属性名:etid) +- **EventTargetAction**:事件目标动作(JSON属性名:eta) +- **EventCustomLanguage**:自定义脚本语言(JSON属性名:ecl) +- **EventCustomScript**:自定义脚本内容(JSON属性名:ecs) +- **EventArgs**:事件参数字典 + +### 验证规则 +`ValidationRuleSchema`定义了表单验证规则: +- **Id**:规则ID +- **ComponentId**:关联组件ID +- **Expression**:验证表达式 + +**示例JSON** +```json +{ + "id": "comp1", + "pid": "root", + "n": "用户名输入框", + "lb": "用户名", + "hlb": false, + "container": false, + "sptds": true, + "stl": { + "itemw": 12, + "itemh": 40, + "labelw": 100 + }, + "evs": [ + { + "en": "OnChange", + "eht": 2, + "ecl": 0, + "ecs": "console.log('value changed')" + } + ], + "desc": "用户登录名输入" +} +``` + +**本节来源** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs#L5-L77) +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs#L9-L29) +- [ComponentStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs#L5-L38) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs#L5-L45) +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs#L8-L15) + +## 设计时与运行时元数据对比 + +系统采用分离的设计时和运行时元数据架构,以满足可视化编辑和高效渲染的不同需求。 + +### 设计时元数据(MetaSchema.DesignEngine) + +设计时元数据位于`H.LowCode.MetaSchema.DesignEngine`命名空间,主要用于可视化设计器。 + +#### AppPartsSchema +继承自`AppSchemaBase`,无额外字段,主要用于类型区分。 + +#### PagePartsSchema +在`PageSchemaBase`基础上扩展: +- **Components**:`IList`类型组件列表 +- **SupportEvents**:支持的事件数组(JSON属性名:sptevs) + +#### ComponentPartsSchema +在`ComponentSchemaBase`基础上扩展了丰富的设计时信息: +- **ComponentId**:组件物料ID(JSON属性名:compid) +- **LibraryId**:组件库ID(JSON属性名:libid) +- **ComponentName**:组件物料名称(JSON属性名:cn) +- **ComponentType**:组件类型(1-原子组件,2-组合组件,JSON属性名:ct) +- **Fragment**:组件渲染片段(JSON属性名:frag) +- **DataSource**:组件数据源(JSON属性名:ds) +- **AttributeDefineGroups**:属性定义分组(JSON属性名:attrdefgroups) +- **Childrens**:子组件列表(JSON属性名:childs) +- **SupportEvents**:支持的事件(JSON属性名:sptevs) +- **Order**:排序序号(JSON属性名:order) +- **PublishStatus**:发布状态(JSON属性名:pub) +- **ModifiedTime**:修改时间(JSON属性名:mt) +- **DesignState**:设计状态(非持久化,JsonIgnore) +- **Refresh**:刷新委托(非持久化,JsonIgnore) + +### 运行时元数据(MetaSchema.RenderEngine) + +运行时元数据位于`H.LowCode.MetaSchema.RenderEngine`命名空间,专为高效渲染优化。 + +#### AppSchema +继承自`AppSchemaBase`,无额外字段。 + +#### PageSchema +在`PageSchemaBase`基础上扩展: +- **Components**:`IList`类型组件列表 + +#### ComponentSchema +在`ComponentSchemaBase`基础上扩展: +- **Fragment**:组件渲染片段(JSON属性名:frag) +- **DataSource**:组件数据源(JSON属性名:ds) +- **AttributeDefineGroups**:属性定义分组(JSON属性名:attrdefgroups) +- **Childrens**:子组件数组(JSON属性名:childs) +- **MergeAttributeDefineToFragment**:将属性定义合并到渲染片段的方法 + +### 关键差异对比 + +| 特性 | 设计时元数据 | 运行时元数据 | +|------|-------------|-------------| +| **组件列表类型** | `IList` | `IList` | +| **属性定义分组** | `IEnumerable` | `ComponentAttributeDefineGroupSchema[]` | +| **子组件类型** | `IList` | `ComponentSchema[]` | +| **非持久化字段** | DesignState, Refresh | 无 | +| **主要用途** | 可视化编辑、拖拽操作 | 高效渲染、数据绑定 | + +**本节来源** +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) + +## 核心元模型UML类图 + +```mermaid +classDiagram +class MetaSchemaBase { +<> +} +class AppSchemaBase { +<> ++string Id ++string Name ++string Icon ++string Picture ++string Description ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class PageSchemaBase { +<> ++string AppId ++string Id ++string Name ++int Order ++PageTypeEnum PageType ++int PublishStatus ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList~EventSchema~ Events +} +class ComponentSchemaBase { +<> ++string Id ++string ParentId ++string Name ++string Label ++bool IsHiddenLabel ++bool IsContainer ++bool IsSupportDataSource ++ComponentStyleSchema Style ++IList~EventSchema~ Events ++IList~EventConsumeSchema~ EventConsumes ++string Description +} +class AppPartsSchema { ++IList~ComponentPartsSchema~ Components +} +class PagePartsSchema { ++IList~ComponentPartsSchema~ Components ++string[] SupportEvents +} +class ComponentPartsSchema { ++string ComponentId ++string LibraryId ++string ComponentName ++int ComponentType ++ComponentPartsFragmentSchema Fragment ++ComponentPartsDataSourceSchema DataSource ++IEnumerable~ComponentPartsAttributeDefineGroupSchema~ AttributeDefineGroups ++IList~ComponentPartsSchema~ Childrens ++string[] SupportEvents ++int Order ++int PublishStatus ++DateTime ModifiedTime ++ComponentDesignStateSchema DesignState ++Action Refresh ++ComponentPartsSchema DeepClone() ++void MergeComponentPartsDefine(ComponentPartsSchema) +} +class AppSchema { ++IList~ComponentSchema~ Components +} +class PageSchema { ++IList~ComponentSchema~ Components +} +class ComponentSchema { ++ComponentFragmentSchema Fragment ++ComponentDataSourceSchema DataSource ++ComponentAttributeDefineGroupSchema[] AttributeDefineGroups ++ComponentSchema[] Childrens ++void MergeAttributeDefineToFragment() +} +class EventSchema { ++string EventName ++EventTargetTypeEnum EventHandlerType ++string EventTargetId ++string EventTargetAction ++EventCustomLanguageEnum EventCustomLanguage ++string EventCustomScript ++IDictionary~string, string~ EventArgs +} +class ComponentStyleSchema { ++double ItemWidth ++double ItemHeight ++double LabelWidth ++string DefaultStyle ++string CustomStyle +} +class ValidationRuleSchema { ++string Id ++string ComponentId ++string Expression +} +MetaSchemaBase <|-- AppSchemaBase +MetaSchemaBase <|-- PageSchemaBase +StateHasChangeSchema <|-- ComponentSchemaBase +AppSchemaBase <|-- AppPartsSchema +AppSchemaBase <|-- AppSchema +PageSchemaBase <|-- PagePartsSchema +PageSchemaBase <|-- PageSchema +ComponentSchemaBase <|-- ComponentPartsSchema +ComponentSchemaBase <|-- ComponentSchema +PagePartsSchema "1" *-- "0..*" ComponentPartsSchema +ComponentPartsSchema "1" *-- "0..*" ComponentPartsSchema +PageSchema "1" *-- "0..*" ComponentSchema +ComponentSchema "1" *-- "0..*" ComponentSchema +ComponentSchemaBase "1" -- "0..*" EventSchema +ComponentSchemaBase "1" -- "0..*" ValidationRuleSchema +ComponentSchemaBase "1" -- "1" ComponentStyleSchema +``` + +**图示来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [ComponentStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs) +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\345\272\224\347\224\250\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\345\272\224\347\224\250\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..e3c4fc32f4b06893fdf3c305ae5d7fc922051fbf --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\345\272\224\347\224\250\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" @@ -0,0 +1,233 @@ +# 应用元数据结构 + + +**本文档引用的文件** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) +- [MetaSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\MetaSchemaBase.cs#L5-L18) +- [PublishStatusEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PublishStatusEnum.cs#L5-L10) +- [SupportPlatformEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\SupportPlatformEnum.cs#L5-L14) +- [caseapp.json](file://meta\apps\caseapp\caseapp.json) +- [testapp.json](file://meta\apps\testapp\testapp.json) + + +## 目录 + +1. [引言](#引言) +2. [应用元数据结构设计](#应用元数据结构设计) +3. [核心字段详解](#核心字段详解) +4. [枚举类型定义](#枚举类型定义) +5. [元数据序列化实例](#元数据序列化实例) +6. [元数据关联与使用机制](#元数据关联与使用机制) +7. [JSON Schema 定义](#json-schema-定义) +8. [扩展机制与自定义字段](#扩展机制与自定义字段) + +## 引言 + +应用元数据(AppSchema)是低代码平台中用于描述一个应用基本属性和配置的核心数据结构。它不仅定义了应用的标识、名称、描述等基本信息,还包含了发布状态、支持平台等关键控制属性。本文档将深入分析 `AppSchemaBase` 类的设计与实现,结合实际 JSON 实例,说明其在设计引擎与渲染引擎中的流转机制,并提供完整的 JSON Schema 以支持扩展。 + +## 应用元数据结构设计 + +应用元数据结构基于面向对象的继承模型构建,核心类为 `AppSchemaBase`,继承自 `MetaSchemaBase`,后者进一步继承自 `StateHasChangeSchema`。该设计实现了元数据的通用属性(如创建/修改时间)与业务属性的分离,增强了可维护性与可扩展性。 + +```mermaid +classDiagram +class MetaSchemaBase { ++string CreatedUser ++DateTime CreatedTime ++string ModifiedUser ++DateTime ModifiedTime +} +class AppSchemaBase { ++string Id ++string Name ++string Icon ++string Picture ++string Description ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +MetaSchemaBase <|-- AppSchemaBase : 继承 +``` + +**图示来源** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) +- [MetaSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\MetaSchemaBase.cs#L5-L18) + +**本节来源** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) +- [MetaSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\MetaSchemaBase.cs#L5-L18) + +## 核心字段详解 + +`AppSchemaBase` 类定义了应用元数据的核心字段,各字段用途及约束如下: + +- **Id**: 应用唯一标识符,用于系统内引用,不可为空。 +- **Name (n)**: 应用名称,JSON 序列化时使用简写 `"n"`,提升传输效率。 +- **Icon**: 应用图标路径或标识。 +- **Picture (pic)**: 应用封面图,序列化为 `"pic"`。 +- **Description (desc)**: 应用描述信息,序列化为 `"desc"`。 +- **Version (v)**: 应用版本号,序列化为 `"v"`。 +- **PublishStatus (pub)**: 发布状态,枚举类型 `PublishStatusEnum`,序列化为 `"pub"`。 +- **SupportPlatforms (platform)**: 支持平台数组,枚举类型 `SupportPlatformEnum[]`,默认值为 `[0]`(即 Web 平台),序列化为 `"platform"`。 + +所有字段均通过 `[JsonPropertyName]` 特性进行序列化别名映射,确保 JSON 输出紧凑且语义清晰。 + +**本节来源** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) + +## 枚举类型定义 + +### 发布状态(PublishStatusEnum) + +定义应用的生命周期状态: + +```csharp +public enum PublishStatusEnum +{ + Development, // 开发中 + Approving, // 审核中 + Published // 已发布 +} +``` + +该枚举用于控制应用的可见性与访问权限,是发布流程的核心状态机。 + +### 支持平台(SupportPlatformEnum) + +定义应用支持的运行平台: + +```csharp +public enum SupportPlatformEnum +{ + [Display(Name = "Web")] + Web, + [Display(Name = "App")] + Mobile, + [Display(Name = "小程序")] + WXMiniApp +} +``` + +通过 `[Display]` 特性提供中文友好名称,支持多端适配。数组形式允许一个应用同时发布到多个平台。 + +**本节来源** +- [PublishStatusEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PublishStatusEnum.cs#L5-L10) +- [SupportPlatformEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\SupportPlatformEnum.cs#L5-L14) + +## 元数据序列化实例 + +在 `meta/apps` 目录下,每个应用对应一个 JSON 文件,存储其元数据。以下是两个实例: + +### 用例系统(caseapp.json) + +```json +{ + "id": "caseapp", + "n": "用例系统", + "desc": "展示典型页面案例 (参考 amis 示例)", + "platform": [0, 2], + "mt": "2025-05-29T16:49:31.1628431Z" +} +``` + +- `platform: [0, 2]` 表示支持 Web 和 小程序。 +- `mt` 字段来自 `MetaSchemaBase`,表示最后修改时间。 + +### 测试系统(testapp.json) + +```json +{ + "id": "testapp", + "n": "测试系统", + "desc": "测试组件、页面不同设计场景", + "platform": [0], + "mt": "2025-05-29T16:43:23.7831823Z" +} +``` + +- `platform: [0]` 表示仅支持 Web 平台。 + +这些 JSON 文件由设计引擎在用户操作时写入,渲染引擎在加载应用时读取,实现元数据的持久化与共享。 + +**本节来源** +- [caseapp.json](file://meta\apps\caseapp\caseapp.json) +- [testapp.json](file://meta\apps\testapp\testapp.json) + +## 元数据关联与使用机制 + +应用元数据作为整个应用的根节点,与其他元数据对象建立关联: + +```mermaid +graph TD +A[AppSchema] --> B[MenuSchema] +A --> C[PageSchema] +A --> D[DataSourceSchema] +B --> E[菜单项] +C --> F[页面组件] +D --> G[数据源配置] +``` + +- **设计引擎**:通过 `AppFileRepository` 等组件将 `AppSchemaBase` 实例序列化为 JSON 并写入文件系统。 +- **渲染引擎**:通过 `AppSchema` 类(位于 `H.LowCode.MetaSchema.RenderEngine`)反序列化 JSON,构建运行时应用模型。 +- **关联关系**:应用元数据通过 `Id` 作为外键,与 `menu/*.json` 和 `page/*.json` 文件关联,形成完整的应用结构树。 + +该机制实现了元数据的解耦与模块化管理,支持独立开发与部署。 + +**图示来源** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) + +**本节来源** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) + +## JSON Schema 定义 + +以下是应用元数据的 JSON Schema 定义,可用于校验与生成: + +```json +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "应用元数据", + "type": "object", + "properties": { + "id": { "type": "string" }, + "n": { "type": "string" }, + "desc": { "type": "string" }, + "v": { "type": "string" }, + "pub": { "type": "integer", "enum": [0, 1, 2] }, + "platform": { + "type": "array", + "items": { "type": "integer", "enum": [0, 1, 2] }, + "default": [0] + }, + "mt": { "type": "string", "format": "date-time" } + }, + "required": ["id", "n"] +} +``` + +## 扩展机制与自定义字段 + +平台支持通过以下方式扩展应用元数据: + +1. **继承扩展**:创建 `AppSchemaBase` 的子类,添加自定义属性。 +2. **配置文件扩展**:在 JSON 文件中直接添加新字段(如 `"customField": "value"`),反序列化时保留。 +3. **API 扩展**:通过 `MetaOption` 配置元数据结构,动态注入字段。 + +例如,添加“开发者团队”字段: + +```json +{ + "id": "testapp", + "n": "测试系统", + "team": "前端团队" +} +``` + +系统在反序列化时将保留 `team` 字段,可在渲染引擎中通过动态属性访问。 + +**本节来源** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) +- [MetaOption.cs](file://src\Common\H.LowCode.Configuration\Options\MetaOption.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\346\225\260\346\215\256\346\272\220\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\346\225\260\346\215\256\346\272\220\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..cf1fdfcd342c0986bfd2377ef1ee3f575f50f72a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\346\225\260\346\215\256\346\272\220\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" @@ -0,0 +1,394 @@ +# 数据源元数据结构 + + +**本文档引用的文件** +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [ComponentDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceTypeEnum.cs) +- [PageDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageDataSourceTypeEnum.cs) +- [iumn5yg5t.json](file://meta/apps/caseapp/datasource/iumn5yg5t.json) +- [qgzhc7w3z.json](file://meta/apps/caseapp/datasource/qgzhc7w3z.json) +- [rsdjkqjz.json](file://meta/apps/caseapp/datasource/rsdjkqjz.json) +- [s4sd6rvm.json](file://meta/apps/caseapp/datasource/s4sd6rvm.json) + + +## 目录 +1. [引言](#引言) +2. [数据源基类结构](#数据源基类结构) +3. [API接口数据源](#api接口数据源) +4. [数据库查询数据源](#数据库查询数据源) +5. [静态选项数据源](#静态选项数据源) +6. [页面间传参数据源](#页面间传参数据源) +7. [数据源类型枚举](#数据源类型枚举) +8. [实际数据源配置示例](#实际数据源配置示例) +9. [数据源在组件属性绑定中的作用](#数据源在组件属性绑定中的作用) + +## 引言 +本文档系统性地描述了低代码平台中各类数据源元数据的结构与使用场景。通过分析代码定义和实际配置文件,详细解析了API接口数据源、数据库查询数据源、静态选项数据源和页面间传参数据源的字段定义与配置方式。同时说明了数据源基类提供的通用属性,以及数据源在组件属性绑定中的作用机制和运行时解析流程。 + +## 数据源基类结构 + +`DataSourceSchema` 类是所有数据源类型的基类,继承自 `MetaSchemaBase`,定义了数据源的通用属性。这些属性为所有类型的数据源提供了统一的结构框架。 + +```mermaid +classDiagram +class DataSourceSchema { ++string AppId ++string Id ++string Name ++string DisplayName ++string Description ++int Order ++ComponentDataSourceTypeEnum DataSourceType ++bool PublishStatus ++IList TableFields ++bool EnableSoftDelete ++APIDataSourceSchema API ++OptionDataSourceSchema[] Options ++string Value ++IDictionary Values +} +class MetaSchemaBase { ++string CreatedTime ++string ModifiedTime +} +DataSourceSchema --|> MetaSchemaBase : 继承 +``` + +**图示来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs#L10-L69) + +**本节来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs#L10-L69) + +### 通用属性说明 +- **AppId**: 应用ID,标识数据源所属的应用 +- **Id**: 数据源唯一标识符,由系统生成 +- **Name**: 数据源名称,用于内部引用 +- **DisplayName**: 数据源显示名称,用于界面展示 +- **Description**: 描述信息 +- **Order**: 排序序号 +- **DataSourceType**: 数据源类型,通过 `ComponentDataSourceTypeEnum` 枚举定义 +- **PublishStatus**: 发布状态,标识数据源是否已发布 + +### 特定类型字段 +基类通过条件编译区域(#region)组织不同类型数据源的特定字段: +- **Table类型**: 包含 `TableFields` 字段列表和 `EnableSoftDelete` 软删除标志 +- **API类型**: 包含 `API` 属性,指向 `APIDataSourceSchema` 对象 +- **Option类型**: 包含 `Options` 选项数组、`Value` 默认值和 `Values` 字典值 + +## API接口数据源 + +`APIDataSourceSchema` 类定义了API接口数据源的结构,用于配置对外部API的调用。 + +```mermaid +classDiagram +class APIDataSourceSchema { ++string Domain ++string Path ++string Method ++IList Queries ++APIBodySchema Body ++IList Headers +} +class APIParamSchema { ++string Id ++string Name ++string Type ++string Description +} +class APIBodySchema { ++APIBodyTypeEnum DataType ++string Value ++IList MultipartParams +} +class APIBodyTypeEnum { ++None ++Json ++Text ++Multipart ++Raw ++Baniry +} +APIDataSourceSchema --> APIParamSchema : 包含 +APIDataSourceSchema --> APIBodySchema : 包含 +APIBodySchema --> APIBodyTypeEnum : 使用 +``` + +**图示来源** +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs#L10-L64) + +**本节来源** +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs#L10-L64) + +### 字段定义 +- **Domain**: API域名 +- **Path**: 请求路径 +- **Method**: HTTP方法(GET、POST等) +- **Queries**: 查询参数列表,每个参数包含ID、名称、类型和描述 +- **Body**: 请求体配置,包含数据类型、值和多部分参数 +- **Headers**: 请求头列表 + +### 请求体类型 +`APIBodyTypeEnum` 枚举定义了请求体的数据类型: +- **None**: 无请求体 +- **Json**: JSON格式 +- **Text**: 纯文本 +- **Multipart**: 多部分表单 +- **Raw**: 原始数据 +- **Baniry**: 二进制数据 + +## 数据库查询数据源 + +`SQLDataSourceSchema` 类定义了数据库查询数据源的结构,用于配置直接的SQL查询。 + +```mermaid +classDiagram +class SQLDataSourceSchema { ++string DbType ++string Sql +} +``` + +**图示来源** +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs#L10-L28) + +**本节来源** +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs#L10-L28) + +### 字段定义 +- **DbType**: 数据库类型,标识目标数据库的种类 +- **Sql**: SQL查询语句,包含完整的查询逻辑 + +该数据源类型允许用户直接编写SQL语句来获取数据,适用于复杂的查询场景或需要直接操作数据库的情况。 + +## 静态选项数据源 + +`OptionDataSourceSchema` 类定义了静态选项数据源的结构,用于配置下拉框、单选按钮等组件的选项列表。 + +```mermaid +classDiagram +class OptionDataSourceSchema { ++string Id ++string Label ++string Value +} +``` + +**图示来源** +- [OptionDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs#L10-L31) + +**本节来源** +- [OptionDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs#L10-L31) + +### 字段定义 +- **Id**: 选项唯一标识符,由系统自动生成 +- **Label**: 显示标签,用户界面中可见的文本 +- **Value**: 实际值,组件绑定和数据处理时使用的值 + +静态选项数据源通常用于配置具有固定选项的组件,如状态选择、类型选择等,提供了一种简单的方式来定义预设值列表。 + +## 页面间传参数据源 + +`PageDataSourceSchema` 类定义了页面间传参数据源的结构,用于处理页面导航时的参数传递。 + +```mermaid +classDiagram +class PageDataSourceSchema { ++PageDataSourceTypeEnum DataSourceType ++string DataSourceId ++string DataSourceName ++string DataSourceValue +} +class PageDataSourceTypeEnum { ++None ++DB ++API +} +``` + +**图示来源** +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs#L10-L32) +- [PageDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageDataSourceTypeEnum.cs#L10-L27) + +**本节来源** +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs#L10-L32) +- [PageDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageDataSourceTypeEnum.cs#L10-L27) + +### 字段定义 +- **DataSourceType**: 传参数据源类型,通过 `PageDataSourceTypeEnum` 枚举定义 +- **DataSourceId**: 数据源ID,标识参数来源 +- **DataSourceName**: 数据源名称 +- **DataSourceValue**: 参数值表达式或直接值 + +页面间传参数据源在页面跳转时起着关键作用,允许将当前页面的数据作为参数传递给目标页面,实现页面间的数据流动和状态传递。 + +## 数据源类型枚举 + +系统定义了两个主要的枚举类型来管理数据源的分类:`ComponentDataSourceTypeEnum` 和 `PageDataSourceTypeEnum`。 + +```mermaid +classDiagram +class ComponentDataSourceTypeEnum { ++None = 0 ++DB = 1 ++API = 2 ++Option = 3 ++SQL = 6 ++Expression = 7 ++Fiexd = 8 +} +class PageDataSourceTypeEnum { ++None = 0 ++DB = 1 ++API = 2 +} +DataSourceSchema --> ComponentDataSourceTypeEnum : 使用 +PageDataSourceSchema --> PageDataSourceTypeEnum : 使用 +``` + +**图示来源** +- [ComponentDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceTypeEnum.cs#L10-L20) +- [PageDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageDataSourceTypeEnum.cs#L10-L17) + +**本节来源** +- [ComponentDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceTypeEnum.cs#L10-L20) +- [PageDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageDataSourceTypeEnum.cs#L10-L17) + +### 组件数据源类型 +`ComponentDataSourceTypeEnum` 定义了组件可以使用的数据源类型: +- **None**: 无数据源 +- **DB**: 数据库表数据源 +- **API**: API接口数据源 +- **Option**: 静态选项数据源 +- **SQL**: SQL查询数据源 +- **Expression**: 表达式数据源 +- **Fiexd**: 固定值数据源 + +### 页面数据源类型 +`PageDataSourceTypeEnum` 定义了页面间传参可用的数据源类型: +- **None**: 无传参 +- **DB**: 数据库数据 +- **API**: API接口数据 + +这两个枚举类型为系统提供了类型安全的机制,确保数据源的正确使用和配置。 + +## 实际数据源配置示例 + +通过分析 `meta/apps/caseapp/datasource/` 目录下的实际JSON配置文件,我们可以看到数据源元数据在运行时的具体表现形式。 + +### API数据源配置示例 +```json +{ + "aid": "caseapp", + "id": "iumn5yg5t", + "n": "测试 API", + "disn": "测试 API", + "order": 0, + "type": 2, + "pub": false, + "fields": [], + "api": { + "p": "/test/save", + "mth": "POST", + "prs": [], + "hds": [] + }, + "ops": [], + "createdTime": "0001-01-01T00:00:00", + "modifiedTime": "2024-10-04T03:53:44.4086661Z" +} +``` + +**本节来源** +- [iumn5yg5t.json](file://meta/apps/caseapp/datasource/iumn5yg5t.json) + +### 数据库表数据源配置示例 +```json +{ + "aid": "caseapp", + "id": "qgzhc7w3z", + "n": "tb_test1", + "disn": "测试表1", + "desc": "xxx", + "type": 1, + "fields": [ + { + "id": "9080f5b9-b155-4aa2-82d9-dc7a20192c06", + "n": "f_id", + "disn": "主键", + "type": "varchar", + "pk": true + }, + { + "id": "b4c09312-7267-45fc-94c1-15f893d0f5ea", + "n": "f_field1", + "disn": "字段1", + "type": "varchar", + "nul": true + } + ], + "ops": [], + "modifiedTime": "2025-03-23T10:17:51.3553924Z" +} +``` + +**本节来源** +- [qgzhc7w3z.json](file://meta/apps/caseapp/datasource/qgzhc7w3z.json) + +### 配置分析 +从实际配置文件可以看出: +1. JSON中的字段名与C#类中的 `JsonPropertyName` 属性对应 +2. `type` 字段的值对应枚举的整数值(1表示DB,2表示API) +3. 不同类型的数据源只包含其相关的配置字段 +4. 系统自动生成的字段如 `createdTime` 和 `modifiedTime` 用于跟踪数据源的生命周期 + +这些配置文件在运行时被反序列化为相应的C#对象,供渲染引擎使用。 + +## 数据源在组件属性绑定中的作用 + +数据源在低代码平台中扮演着连接数据与界面的关键角色,其运行时解析流程如下: + +```mermaid +sequenceDiagram +participant 组件 as 组件实例 +participant 渲染引擎 as 渲染引擎 +participant 数据源服务 as 数据源服务 +participant 数据提供者 as 数据提供者API/DB等 +组件->>渲染引擎 : 请求数据绑定 +渲染引擎->>数据源服务 : 根据数据源ID获取配置 +数据源服务-->>渲染引擎 : 返回数据源配置 +渲染引擎->>数据提供者 : 执行数据获取操作 +数据提供者-->>渲染引擎 : 返回原始数据 +渲染引擎->>渲染引擎 : 数据转换与映射 +渲染引擎-->>组件 : 提供处理后的数据 +组件->>组件 : 更新界面显示 +``` + +**图示来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs#L10-L69) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs#L10-L64) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs#L10-L28) + +**本节来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs#L10-L69) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs#L10-L64) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs#L10-L28) + +### 作用机制 +1. **配置阶段**: 设计器中配置组件的数据源引用,选择特定的数据源实例 +2. **解析阶段**: 运行时根据数据源类型和配置,确定数据获取方式 +3. **执行阶段**: 调用相应的数据提供者(API客户端、数据库连接等)获取数据 +4. **转换阶段**: 将原始数据转换为组件所需的格式,可能包括字段映射、数据类型转换等 +5. **绑定阶段**: 将处理后的数据绑定到组件属性,触发界面更新 + +### 缓存策略 +虽然在当前代码分析中未明确看到缓存配置字段,但系统可能在服务层实现缓存机制: +- 对于API数据源,可能根据请求参数缓存响应结果 +- 对于数据库查询,可能缓存查询结果以提高性能 +- 静态选项数据源通常会被长期缓存,因为其数据不经常变化 + +数据源机制为低代码平台提供了灵活的数据集成能力,使得非技术人员也能轻松配置复杂的数据交互逻辑。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\347\273\204\344\273\266\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\347\273\204\344\273\266\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..7546c8ec1ac50e0fcca7c9bd05c934150d4e3cb3 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\347\273\204\344\273\266\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" @@ -0,0 +1,338 @@ +# 组件元数据结构 + + +**本文档引用文件** +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs) +- [ComponentStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs) +- [ComponentFragmentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs) +- [ComponentValueTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentValueTypeEnum.cs) +- [52391a70.json](file://meta/parts/componentParts/antdesign/52391a70.json) +- [5icgyefr.json](file://meta/parts/componentParts/antdesign/5icgyefr.json) +- [6d997568.json](file://meta/parts/componentParts/antdesign/6d997568.json) +- [7bab5a19.json](file://meta/parts/componentParts/antdesign/7bab5a19.json) +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) + + +## 目录 +1. [引言](#引言) +2. [组件元数据整体结构](#组件元数据整体结构) +3. [组件属性定义](#组件属性定义) +4. [组件样式配置](#组件样式配置) +5. [事件绑定机制](#事件绑定机制) +6. [验证规则配置](#验证规则配置) +7. [组件片段结构](#组件片段结构) +8. [实际应用示例](#实际应用示例) +9. [高级功能实现](#高级功能实现) +10. [总结](#总结) + +## 引言 + +本文档旨在全面解析低代码平台中组件元数据(ComponentSchema)的组成结构与配置机制。通过分析核心代码与实际JSON定义文件,深入探讨组件ID、类型、属性、样式、事件和验证规则的设计原理,并展示如何通过元数据实现动态表单、条件渲染等高级功能。 + +## 组件元数据整体结构 + +组件元数据以 `ComponentSchemaBase` 为核心基类,定义了组件的基本结构,包括组件ID、类型、标签、样式、属性定义、事件绑定等。该结构支持通过元数据驱动的方式动态生成UI组件,实现可视化配置。 + +```mermaid +classDiagram +class ComponentSchemaBase { ++string Id ++string ComponentId ++string Label ++ComponentStyleSchema Style ++ComponentAttributeDefineSchemaBase[] Attributes ++EventSchema[] Events ++ValidationRuleSchema[] ValidationRules +} +ComponentSchemaBase --> ComponentStyleSchema : "包含" +ComponentSchemaBase --> ComponentAttributeDefineSchemaBase : "包含" +ComponentSchemaBase --> EventSchema : "包含" +ComponentSchemaBase --> ValidationRuleSchema : "包含" +``` + +**图示来源** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) + +**中文来源** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) + +## 组件属性定义 + +组件属性通过 `ComponentAttributeDefineSchemaBase` 类进行定义,包含属性名称、CLR类型和属性值三个核心字段。 + +### 属性结构说明 + +- **AttributeName (attrn)**:组件属性名称,必须与实际组件中的属性名一致。 +- **AttributeClrType (attrt)**:属性值的CLR类型,如 `System.String`、`System.Boolean`。 +- **AttributeValue (attrv)**:属性的实际值,支持多种数据类型。 + +```csharp +public abstract class ComponentAttributeDefineSchemaBase +{ + [JsonPropertyName("attrn")] + public string AttributeName { get; set; } + + [JsonPropertyName("attrt")] + public string AttributeClrType { get; set; } + + [JsonPropertyName("attrv")] + public object AttributeValue { get; set; } +} +``` + +### 属性分组与默认值 + +在antdesign组件库中,属性可按功能分组(`attrdefgroups`),并设置默认值(`dftval`)。例如,Input组件的“基础属性”组包含禁用、最大长度、提示文本等。 + +```json +"attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean" + }, + { + "disn": "最大长度", + "dftval": 0, + "attrn": "MaxLength", + "attrt": "System.Int32" + } + ] + } +] +``` + +**中文来源** +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs) +- [52391a70.json](file://meta/parts/componentParts/antdesign/52391a70.json) + +## 组件样式配置 + +组件样式由 `ComponentStyleSchema` 类定义,控制组件在页面中的布局与外观。 + +### 样式字段说明 + +- **ItemWidth (itemw)**:组件宽度,取值4-24,对应24列栅格系统。 +- **ItemHeight (itemh)**:组件高度,单位为像素。 +- **LabelWidth (labelw)**:标签宽度,默认180px。 +- **DefaultStyle (dfstl)**:默认CSS样式。 +- **CustomStyle (ctstl)**:自定义CSS样式。 + +```csharp +public class ComponentStyleSchema +{ + [JsonPropertyName("itemw")] + public double ItemWidth { get; set; } = 4; + + [JsonPropertyName("itemh")] + public double ItemHeight { get; set; } = 85; + + [JsonPropertyName("labelw")] + public double LabelWidth { get; set; } = 180; + + [JsonPropertyName("dfstl")] + public string DefaultStyle { get; set; } + + [JsonPropertyName("ctstl")] + public string CustomStyle { get; set; } +} +``` + +例如,Layout组件设置 `itemw: 24` 表示占满整行宽度。 + +**中文来源** +- [ComponentStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs) +- [6d997568.json](file://meta/parts/componentParts/antdesign/6d997568.json) + +## 事件绑定机制 + +事件通过 `EventSchema` 类进行配置,支持标准事件和自定义脚本两种模式。 + +### 事件结构说明 + +- **EventName (en)**:触发的事件名称,如 `OnClick`。 +- **EventHandlerType (eht)**:事件处理器类型,枚举 `EventTargetTypeEnum`。 +- **EventTargetId (etid)**:目标组件或页面ID。 +- **EventTargetAction (eta)**:目标动作,如跳转、刷新。 +- **EventCustomScript (ecs)**:自定义脚本内容。 + +```csharp +public class EventSchema +{ + [JsonPropertyName("en")] + public string EventName { get; set; } + + [JsonPropertyName("eht")] + public EventTargetTypeEnum EventHandlerType { get; set; } + + [JsonPropertyName("etid")] + public string EventTargetId { get; set; } + + [JsonPropertyName("eta")] + public string EventTargetAction { get; set; } + + [JsonPropertyName("ecs")] + public string EventCustomScript { get; set; } + + public IDictionary EventArgs { get; set; } +} +``` + +DatePicker组件支持 `OnClick` 和 `OnExpand` 事件。 + +**中文来源** +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [7bab5a19.json](file://meta/parts/componentParts/antdesign/7bab5a19.json) + +## 验证规则配置 + +验证规则通过 `ValidationRuleSchema` 类定义,用于表单组件的数据校验。 + +### 验证规则字段 + +- **Id**:规则唯一标识。 +- **ComponentId**:关联的组件ID。 +- **Expression**:验证表达式,如正则或逻辑条件。 + +```csharp +public class ValidationRuleSchema +{ + public string Id { get; set; } + public string ComponentId { get; set; } + public string Expression { get; set; } +} +``` + +该结构支持动态构建验证逻辑,适用于复杂表单场景。 + +**中文来源** +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs) + +## 组件片段结构 + +复杂组件通过 `ComponentFragmentSchemaBase` 定义其内部结构片段,支持嵌套子组件。 + +### 片段字段说明 + +- **TypeName (t)**:组件类型名。 +- **ValueType (valt)**:值类型,如 `System.String`。 +- **Attributes (attrs)**:片段属性数组。 +- **Content (content)**:内容模板,如 `$(DropItemContainer)` 表示可拖拽区域。 + +```csharp +public abstract class ComponentFragmentSchemaBase +{ + [JsonPropertyName("t")] + public virtual string TypeName { get; set; } + + [JsonPropertyName("valt")] + public string ValueType { get; set; } + + [JsonPropertyName("attrs")] + public ComponentAttributeFragmentSchema[] Attributes { get; set; } + + [JsonPropertyName("content")] + public string Content { get; set; } +} +``` + +Layout组件包含 `Sider` 和 `Content` 两个子片段,构成左右布局。 + +```json +"frag": { + "childs": [ + { + "dt": "AntDesign.Sider, AntDesign", + "attrs": [ ... ], + "content": "$(DropItemContainer)" + }, + { + "dt": "AntDesign.Content, AntDesign", + "attrs": [ ... ], + "content": "$(DropItemContainer)" + } + ] +} +``` + +**中文来源** +- [ComponentFragmentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs) +- [6d997568.json](file://meta/parts/componentParts/antdesign/6d997568.json) + +## 实际应用示例 + +### Input组件配置解析 + +```json +{ + "cn": "Input", + "lb": "输入框-A", + "stl": { "itemh": 85, "labelw": 180 }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { "disn": "是否禁用", "dftval": false, "attrn": "Disabled" }, + { "disn": "最大长度", "dftval": 0, "attrn": "MaxLength" } + ] + } + ] +} +``` + +此配置定义了一个输入框组件,包含基础属性分组,支持禁用状态和长度限制。 + +### TextArea组件简化配置 + +```json +{ + "cn": "TextArea", + "lb": "文本框-A", + "stl": { "itemh": 85, "labelw": 180 } +} +``` + +该组件无额外属性定义,使用默认行为。 + +**中文来源** +- [52391a70.json](file://meta/parts/componentParts/antdesign/52391a70.json) +- [5icgyefr.json](file://meta/parts/componentParts/antdesign/5icgyefr.json) + +## 高级功能实现 + +### 动态表单生成 + +通过读取组件元数据中的 `Attributes` 和 `ValidationRules`,可动态生成表单字段及其校验逻辑。例如,遍历所有属性定义,根据 `ComponentValueTypeEnum` 渲染对应输入控件。 + +### 条件渲染 + +结合事件绑定与状态管理,可实现条件渲染。例如,当某组件的 `Visible` 属性绑定到另一组件的值变化事件时,可动态显示/隐藏该组件。 + +### 数据类型支持 + +`ComponentValueTypeEnum` 枚举定义了丰富的数据类型,支持字符串、数字、布尔、日期、数组、树形结构等,满足多样化数据处理需求。 + +```csharp +public enum ComponentValueTypeEnum +{ + String = 1, + Integer = 6, + Boolean = 13, + Date = 18, + Array = 25, + Tree = 42 +} +``` + +**中文来源** +- [ComponentValueTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentValueTypeEnum.cs) + +## 总结 + +组件元数据结构是低代码平台的核心,通过标准化的JSON Schema定义组件的行为与外观。`ComponentSchemaBase` 及其相关类提供了灵活的扩展机制,支持属性、样式、事件、验证等多维度配置。结合antdesign组件库的实际定义,展示了如何通过元数据驱动UI生成,实现高效、可维护的可视化开发体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\350\256\276\350\256\241\346\227\266\344\270\216\350\277\220\350\241\214\346\227\266\345\205\203\346\225\260\346\215\256\345\257\271\346\257\224.md" "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\350\256\276\350\256\241\346\227\266\344\270\216\350\277\220\350\241\214\346\227\266\345\205\203\346\225\260\346\215\256\345\257\271\346\257\224.md" new file mode 100644 index 0000000000000000000000000000000000000000..192679c50ab4ac35f8b729a2c4dae8efdf9ffe34 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\350\256\276\350\256\241\346\227\266\344\270\216\350\277\220\350\241\214\346\227\266\345\205\203\346\225\260\346\215\256\345\257\271\346\257\224.md" @@ -0,0 +1,431 @@ +# 设计时与运行时元数据对比 + + +**本文档引用文件** +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs) +- [ComponentAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineSchema.cs) +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs) +- [ComponentDesignStateSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentDesignStateSchema.cs) +- [ComponentPartsAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineGroupSchema.cs) +- [ComponentAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineGroupSchema.cs) +- [ComponentAttributeItemTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/Enums/ComponentAttributeItemTypeEnum.cs) +- [52391a70.json](file://meta/parts/componentParts/antdesign/52391a70.json) +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) +- [MetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) + + +## 目录 +1. [引言](#引言) +2. [设计时与运行时元数据架构概览](#设计时与运行时元数据架构概览) +3. [组件属性定义模式对比分析](#组件属性定义模式对比分析) +4. [属性分组信息的转换机制](#属性分组信息的转换机制) +5. [组件设计状态模式的作用分析](#组件设计状态模式的作用分析) +6. [antdesign组件元数据转换实例](#antdesign组件元数据转换实例) +7. [元数据转换流程与性能优势](#元数据转换流程与性能优势) +8. [结论](#结论) + +## 引言 +本文档深入分析低代码平台中设计时元数据(DesignEngine.MetaSchema)与运行时元数据(RenderEngine.MetaSchema)的差异与转换机制。重点探讨从可视化设计环境到生产运行环境的元数据精简过程,特别是组件属性定义、属性分组和设计状态等关键元数据的处理方式。通过对比分析相关类结构和实际元数据文件,揭示这种分离架构在性能优化和维护性方面的优势。 + +## 设计时与运行时元数据架构概览 + +```mermaid +graph TB +subgraph "设计时元数据 (DesignEngine)" +A[ComponentPartsAttributeDefineSchema] +B[ComponentPartsAttributeDefineGroupSchema] +C[ComponentDesignStateSchema] +D[ComponentAttributeItemTypeEnum] +end +subgraph "运行时元数据 (RenderEngine)" +E[ComponentAttributeDefineSchema] +F[ComponentAttributeDefineGroupSchema] +end +subgraph "共享基础结构" +G[ComponentAttributeDefineSchemaBase] +end +A --> |继承| G +E --> |继承| G +B --> A +F --> E +A --> D +A --> C +style A fill:#f9f,stroke:#333 +style B fill:#f9f,stroke:#333 +style C fill:#f9f,stroke:#333 +style D fill:#f9f,stroke:#333 +style E fill:#bbf,stroke:#333 +style F fill:#bbf,stroke:#333 +style G fill:#9f9,stroke:#333 +classDef design fill:#f9f,stroke:#333; +classDef runtime fill:#bbf,stroke:#333; +classDef base fill:#9f9,stroke:#333; +class A,B,C,D design +class E,F runtime +class G base +``` + +**图示来源** +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs) +- [ComponentAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineSchema.cs) +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs) +- [ComponentPartsAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineGroupSchema.cs) +- [ComponentAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineGroupSchema.cs) + +## 组件属性定义模式对比分析 + +设计时组件属性定义(ComponentPartsAttributeDefineSchema)与运行时组件属性定义(ComponentAttributeDefineSchema)均继承自同一个基类 ComponentAttributeDefineSchemaBase,但具有显著差异。 + +### 基础结构分析 + +```mermaid +classDiagram +class ComponentAttributeDefineSchemaBase { ++string AttributeName ++string AttributeClrType ++object AttributeValue +} +class ComponentPartsAttributeDefineSchema { ++string DisplayName ++ComponentAttributeItemTypeEnum AttributeItemType ++bool IsRequired ++string Description ++object DefaultValue ++Dictionary Options ++string StringValue ++int IntValue ++bool BoolValue +} +class ComponentAttributeDefineSchema { +} +ComponentPartsAttributeDefineSchema --|> ComponentAttributeDefineSchemaBase : 继承 +ComponentAttributeDefineSchema --|> ComponentAttributeDefineSchemaBase : 继承 +note right of ComponentPartsAttributeDefineSchema +设计时专属字段: +- DisplayName : 属性显示名称 +- AttributeItemType : 属性控件类型 +- IsRequired : 是否必填 +- Description : 描述信息 +- DefaultValue : 默认值 +- Options : 选项配置 +- StringValue/IntValue/BoolValue : 类型安全的值访问器 +end +note right of ComponentAttributeDefineSchema +运行时仅保留基础属性: +- AttributeName : 属性名称 +- AttributeClrType : CLR类型 +- AttributeValue : 属性值 +end +``` + +**图示来源** +- [ComponentAttributeDefineSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs#L9-L29) +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs#L11-L75) +- [ComponentAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineSchema.cs#L9-L12) + +### 设计时专属字段说明 + +设计时元数据包含多个专为可视化编辑器设计的字段: + +- **DisplayName**: 属性的显示名称,用于在属性面板中展示 +- **AttributeItemType**: 属性控件类型,决定属性编辑器的渲染方式 +- **IsRequired**: 标识属性是否为必填项 +- **Description**: 属性描述信息,提供使用指导 +- **DefaultValue**: 属性默认值,用于新组件实例化 +- **Options**: 属性选项配置,用于下拉框、单选框等控件 +- **StringValue/IntValue/BoolValue**: 类型安全的值访问器,简化属性值操作 + +这些字段在运行时环境中均被过滤,仅保留最基础的属性定义信息。 + +**中文标签结构** +- :DisplayName: 显示名称 +- :AttributeItemType: 属性项目类型 +- :IsRequired: 是否必填 +- :Description: 描述 +- :DefaultValue: 默认值 +- :Options: 选项 +- :StringValue: 字符串值 +- :IntValue: 整数值 +- :BoolValue: 布尔值 + +## 属性分组信息的转换机制 + +设计时和运行时对属性分组的处理方式也存在明显差异。 + +### 设计时属性分组 + +```mermaid +classDiagram +class ComponentPartsAttributeDefineGroupSchema { ++string GroupName ++ComponentPartsAttributeDefineSchema[] AttributeDefines +} +class ComponentPartsAttributeDefineSchema { ++string DisplayName ++ComponentAttributeItemTypeEnum AttributeItemType ++bool IsRequired ++string Description ++object DefaultValue ++Dictionary Options +} +ComponentPartsAttributeDefineGroupSchema --> ComponentPartsAttributeDefineSchema : 包含 +``` + +**图示来源** +- [ComponentPartsAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineGroupSchema.cs#L9-L18) + +设计时属性分组(ComponentPartsAttributeDefineGroupSchema)包含: +- **GroupName**: 分组名称,如"基础属性"、"样式设置"等 +- **AttributeDefines**: 设计时属性定义数组,包含完整的属性元数据 + +### 运行时属性分组 + +```mermaid +classDiagram +class ComponentAttributeDefineGroupSchema { ++ComponentAttributeDefineSchema[] AttributeDefines +} +class ComponentAttributeDefineSchema { ++string AttributeName ++string AttributeClrType ++object AttributeValue +} +ComponentAttributeDefineGroupSchema --> ComponentAttributeDefineSchema : 包含 +``` + +**图示来源** +- [ComponentAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineGroupSchema.cs#L9-L15) + +运行时属性分组(ComponentAttributeDefineGroupSchema)仅包含: +- **AttributeDefines**: 运行时属性定义数组,仅保留基础属性信息 + +转换过程中,分组名称(GroupName)被完全移除,因为运行时组件不需要知道属性的分组信息。 + +## 组件设计状态模式的作用分析 + +```mermaid +classDiagram +class ComponentDesignStateSchema { ++bool IsSelected ++string DragEffectStyle ++bool IsDroppedFromComponentPanel ++string AnimationTransform ++bool IsAnimating +} +note right of ComponentDesignStateSchema +设计状态模式用于记录 +可视化编辑器中的临时状态, +不需要持久化存储。 +end +``` + +**图示来源** +- [ComponentDesignStateSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentDesignStateSchema.cs#L9-L34) + +### 设计状态模式字段说明 + +组件设计状态模式(ComponentDesignStateSchema)包含以下字段: + +- **IsSelected**: 标识组件是否被选中,用于高亮显示 +- **DragEffectStyle**: 拖拽效果样式,用于视觉反馈 +- **IsDroppedFromComponentPanel**: 标识是否从组件面板拖拽而来 +- **AnimationTransform**: 动画变换样式,用于平滑让位动画 +- **IsAnimating**: 标识是否正在进行让位动画 + +这些状态信息仅在设计时有效,用于支持拖拽、选择、动画等交互功能。运行时组件不需要这些信息,因此在发布过程中被完全移除。 + +**中文标签结构** +- :IsSelected: 是否选中 +- :DragEffectStyle: 拖拽效果样式 +- :IsDroppedFromComponentPanel: 是否从组件面板拖拽而来 +- :AnimationTransform: 动画变换样式 +- :IsAnimating: 是否正在动画 + +## antdesign组件元数据转换实例 + +以 antdesign 组件库中的 Input 组件为例,分析从设计时到运行时的元数据转换过程。 + +### 设计时元数据结构 + +```json +{ + "cn": "Input", + "ct": 1, + "frag": { + "dt": "AntDesign.Input`1[System.String], AntDesign", + "valt": "System.String", + "attrs": [ + { + "attrn": "TValue", + "attrt": "System.String" + } + ] + }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "pt": 2, + "disn": "最大长度", + "desc": "字段输入的最大长度,为0时表示不限制长度", + "dftval": 0, + "attrn": "MaxLength", + "attrt": "System.Int32", + "attrv": 0 + }, + { + "pt": 1, + "disn": "输入提示", + "desc": "组件输入时的 Placeholder 提示", + "dftval": "", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "" + } + ] + } + ], + "childs": [], + "sptds": false, + "order": 10, + "pub": 1, + "mt": "2025-02-24T15:36:15.8037414Z", + "id": "cj8ac3m42", + "libid": "antdesign", + "partsId": "52391a70", + "lb": "输入框-A", + "container": false, + "stl": { + "itemh": 85, + "labelw": 180, + "display": "inline", + "pos": "static" + } +} +``` + +**文件来源** +- [52391a70.json](file://meta/parts/componentParts/antdesign/52391a70.json) + +### 转换过程分析 + +在发布过程中,设计时元数据被转换为运行时元数据: + +1. **属性定义转换**: + - 移除 `disn` (显示名称) + - 移除 `pt` (属性项目类型) + - 移除 `desc` (描述) + - 移除 `dftval` (默认值) + - 保留 `attrn` (属性名称)、`attrt` (属性类型)、`attrv` (属性值) + +2. **属性分组转换**: + - 移除 `gn` (分组名称) + - 将 `attrdefs` 中的设计时属性转换为运行时属性 + +3. **其他设计时信息移除**: + - 移除组件设计状态相关信息 + - 移除拖拽、动画等交互状态 + +### 转换后运行时元数据结构 + +```json +{ + "frag": { + "dt": "AntDesign.Input`1[System.String], AntDesign", + "valt": "System.String", + "attrs": [ + { + "attrn": "TValue", + "attrt": "System.String" + } + ] + }, + "attrdefgroups": [ + { + "attrdefs": [ + { + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "attrn": "MaxLength", + "attrt": "System.Int32", + "attrv": 0 + }, + { + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "" + } + ] + } + ], + "pub": true, + "id": "cj8ac3m42", + "libid": "antdesign", + "partsId": "52391a70" +} +``` + +## 元数据转换流程与性能优势 + +```mermaid +flowchart TD +A[设计时元数据] --> B{发布流程} +B --> C[过滤设计时专属字段] +C --> D[移除组件设计状态] +D --> E[精简属性分组信息] +E --> F[转换属性定义] +F --> G[生成运行时元数据] +G --> H[部署到生产环境] +style A fill:#f9f,stroke:#333 +style G fill:#bbf,stroke:#333 +style H fill:#9f9,stroke:#333 +classDef design fill:#f9f,stroke:#333; +classDef runtime fill:#bbf,stroke:#333; +classDef deploy fill:#9f9,stroke:#333; +class A design +class G runtime +class H deploy +``` + +**图示来源** +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs) +- [ComponentAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineSchema.cs) + +### 转换机制实现 + +元数据转换通过以下机制实现: + +1. **继承关系**: 设计时和运行时属性定义共享同一个基类,确保基础结构一致性 +2. **字段过滤**: 发布过程中仅序列化运行时需要的字段 +3. **类型映射**: 设计时属性数组转换为运行时属性数组 +4. **JSON序列化控制**: 使用 `JsonIgnore` 属性标记设计时专属字段 + +### 性能与维护性优势 + +这种分离架构带来以下优势: + +- **性能优化**: 运行时元数据体积显著减小,减少网络传输和内存占用 +- **安全性**: 移除设计时敏感信息,降低安全风险 +- **维护性**: 设计时和运行时关注点分离,便于独立演进 +- **加载速度**: 精简的元数据结构提升页面加载速度 +- **可扩展性**: 设计时可以添加丰富的元数据而不影响运行时性能 + +## 结论 + +本文档深入分析了低代码平台中设计时与运行时元数据的差异与转换机制。通过对比 ComponentPartsAttributeDefineSchema 和 ComponentAttributeDefineSchema,揭示了从设计态到运行态的元数据精简过程。设计时元数据包含丰富的可视化编辑所需信息,如属性显示名称、控件类型、分组信息和设计状态等。这些信息在发布过程中被过滤,仅保留运行时必需的基础属性定义。 + +这种分离架构实现了关注点分离,既保证了可视化编辑器的丰富功能,又确保了运行时环境的高性能和轻量化。antdesign 组件的元数据转换实例进一步验证了这一机制的有效性。未来可以进一步优化转换流程,支持更复杂的元数据映射规则,同时保持运行时元数据的简洁性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\351\241\265\351\235\242\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\351\241\265\351\235\242\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..0ec42c59db4e47b2a2e9b37be45fb282e4a08563 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\205\203\346\225\260\346\215\256\346\236\266\346\236\204/\351\241\265\351\235\242\345\205\203\346\225\260\346\215\256\347\273\223\346\236\204.md" @@ -0,0 +1,266 @@ +# 页面元数据结构 + + +**本文档中引用的文件** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs) +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs) +- [fhumgxyk.json](file://meta\apps\caseapp\page\fhumgxyk.json) +- [g0qcqxzd.json](file://meta\apps\caseapp\page\g0qcqxzd.json) +- [2qceiqni.json](file://meta\apps\caseapp\page\2qceiqni.json) +- [4tnfvebp1.json](file://meta\apps\caseapp\page\4tnfvebp1.json) + + +## 目录 +1. [引言](#引言) +2. [页面元数据核心结构](#页面元数据核心结构) +3. [页面类型与布局配置](#页面类型与布局配置) +4. [页面属性定义](#页面属性定义) +5. [组件列表与数据源引用](#组件列表与数据源引用) +6. [事件处理逻辑](#事件处理逻辑) +7. [实例分析:页面元数据结构嵌套](#实例分析:页面元数据结构嵌套) +8. [生命周期管理与动态渲染](#生命周期管理与动态渲染) + +## 引言 + +页面元数据(PageSchema)是低代码平台中用于描述页面结构、行为和外观的核心数据模型。通过元数据驱动的方式,系统能够在设计时和运行时动态构建用户界面,实现高度灵活的页面配置。本文将深入解析 `PageSchemaBase` 类的设计与实现,结合 `PagePropertySchema` 分析页面级属性的定义方式,并以 `meta/apps/caseapp/page` 目录下的 JSON 文件为例,展示页面元数据的实际结构与嵌套关系。 + +## 页面元数据核心结构 + +`PageSchemaBase` 是所有页面元数据的基类,定义了页面的基本属性和结构。该类继承自 `MetaSchemaBase`,并包含多个关键字段,用于描述页面的身份、类型、布局、组件、数据源和事件等信息。 + +```mermaid +classDiagram +class PageSchemaBase { ++string AppId ++string Id ++string Name ++int Order ++PageTypeEnum PageType ++int PublishStatus ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList Events ++IList Comps +} +class PagePropertySchema { ++int PageLayout ++string TitleWidth ++string DefaultStyle ++string CustomStyle ++PageDataSourceSchema DataSource +} +class PageTypeEnum { +<> +Normal = 0 +Form = 1 +Table = 2 +Report = 5 +} +PageSchemaBase --> PagePropertySchema : "包含" +PageSchemaBase --> PageTypeEnum : "引用" +PageSchemaBase --> PageDataSourceSchema : "引用" +PageSchemaBase --> EventSchema : "包含多个" +PageSchemaBase --> ComponentSchema : "包含多个" +``` + +**图示来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L5-L39) +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs#L5-L36) + +**本节来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L5-L39) + +## 页面类型与布局配置 + +### 页面类型(PageTypeEnum) + +页面类型通过 `PageTypeEnum` 枚举定义,支持以下几种类型: + +- **普通页面(Normal)**: 值为 0,适用于通用内容展示。 +- **表单页面(Form)**: 值为 1,用于数据录入和编辑。 +- **列表页面(Table)**: 值为 2,用于数据展示和操作。 +- **报表页面(Report)**: 值为 5,用于数据分析和可视化。 + +该枚举通过 `[Display(Name = "...")]` 特性提供中文名称,便于在用户界面中显示。 + +### 布局配置 + +页面布局由 `PagePropertySchema` 中的 `PageLayout` 字段控制,表示页面的列数布局: + +- **1列布局**: 单列,适合简洁内容。 +- **2列布局**: 双列,常见于表单和列表。 +- **3列布局**: 三列,适用于复杂表单或分栏布局。 +- **4列布局**: 四列,用于高度复杂的布局需求。 + +例如,在 `fhumgxyk.json` 中,`"pageprop":{"playout":3}` 表示该页面采用三列布局。 + +**本节来源** +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs#L9-L19) +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs#L5-L36) + +## 页面属性定义 + +`PagePropertySchema` 类定义了页面级别的属性,包括布局、样式、标题宽度和数据源等。这些属性决定了页面的整体外观和行为。 + +### 核心字段说明 + +- **PageLayout**: 页面布局列数,影响组件的排列方式。 +- **TitleWidth**: 标题区域的宽度,控制标签与输入框的比例。 +- **DefaultStyle**: 默认样式,应用于整个页面的基础样式。 +- **CustomStyle**: 自定义样式,允许用户添加额外的 CSS 规则。 +- **DataSource**: 页面级数据源,可被多个组件共享。 + +例如,在 `2qceiqni.json`(主从表单)中,`"pageprop":{"playout":2,"ds":{}}` 表示该页面为双列布局,并配置了数据源。 + +**本节来源** +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs#L5-L36) + +## 组件列表与数据源引用 + +### 组件列表(comps) + +`comps` 字段是一个组件对象数组,描述了页面上所有可视组件的配置。每个组件包含以下信息: + +- **compid**: 组件唯一标识。 +- **libid**: 所属组件库(如 antdesign)。 +- **cn**: 组件名称(如 Input、Table)。 +- **attrdefgroups**: 属性定义组,包含组件的可配置属性。 +- **stl**: 样式信息,如高度、标签宽度等。 +- **ds**: 数据源配置,用于绑定数据。 + +例如,在 `g0qcqxzd.json`(基础列表)中,`comps` 包含一个表格组件,其数据源配置了列定义和按钮事件。 + +### 数据源引用 + +数据源通过 `ds` 字段配置,支持多种类型: + +- **API 数据源**: 调用后端接口获取数据。 +- **SQL 数据源**: 直接执行 SQL 查询。 +- **静态数据源**: 固定选项列表(如下拉框选项)。 + +在 `fhumgxyk.json` 中,`"ds":{"dst":1,"dsv":"tb_test1"}` 表示该页面的数据源类型为数据库表,表名为 `tb_test1`。 + +**本节来源** +- [fhumgxyk.json](file://meta\apps\caseapp\page\fhumgxyk.json) +- [g0qcqxzd.json](file://meta\apps\caseapp\page\g0qcqxzd.json) + +## 事件处理逻辑 + +事件处理通过 `Events` 字段定义,是一个 `EventSchema` 对象的列表。每个事件包含以下信息: + +- **en**: 事件名称(如 OnClick、OnLoad)。 +- **eht**: 事件处理类型(如跳转、提交)。 +- **etid**: 目标页面或组件 ID。 +- **eta**: 附加参数。 + +例如,在 `g0qcqxzd.json` 中,表格的“新增”按钮配置了 `OnClick` 事件,指向另一个表单页面,实现页面跳转。 + +```mermaid +sequenceDiagram +participant 用户 as "用户" +participant 页面 as "基础列表页面" +participant 事件系统 as "事件处理器" +participant 目标页面 as "基础表单页面" +用户->>页面 : 点击“新增”按钮 +页面->>事件系统 : 触发 OnClick 事件 +事件系统->>目标页面 : 跳转至 fhumgxyk 页面 +目标页面-->>用户 : 显示表单界面 +Note over 用户,目标页面 : 实现页面间导航 +``` + +**图示来源** +- [g0qcqxzd.json](file://meta\apps\caseapp\page\g0qcqxzd.json) +- [fhumgxyk.json](file://meta\apps\caseapp\page\fhumgxyk.json) + +**本节来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L26-L29) + +## 实例分析:页面元数据结构嵌套 + +以 `fhumgxyk.json`(基础表单)为例,其元数据结构如下: + +```json +{ + "aid": "caseapp", + "id": "fhumgxyk", + "n": "基础表单", + "pt": 1, + "pageprop": { + "playout": 3 + }, + "ds": { + "dst": 1, + "dsv": "tb_test1" + }, + "comps": [ + { + "partsId": "52391a70", + "cn": "Input", + "n": "f_field1", + "lb": "输入框1", + "stl": { "itemh": 85, "labelw": 180 } + }, + { + "partsId": "evuqdwzl", + "cn": "Radio", + "n": "f_field6", + "lb": "单选框3", + "ds": { "fxopds": [ { "l": "选项1", "v": "op1" } ] } + } + ] +} +``` + +该结构展示了: + +- 页面属于 `caseapp` 应用。 +- 页面类型为表单(`pt:1`)。 +- 采用三列布局(`playout:3`)。 +- 数据源绑定到 `tb_test1` 表。 +- 包含多个组件,如输入框、单选框等,每个组件都有独立的属性和数据源配置。 + +**本节来源** +- [fhumgxyk.json](file://meta\apps\caseapp\page\fhumgxyk.json) + +## 生命周期管理与动态渲染 + +页面元数据在设计时和运行时具有不同的生命周期管理方式: + +### 设计时 + +- 元数据通过可视化设计器编辑,保存为 JSON 文件。 +- 支持版本控制和发布状态管理(`PublishStatus`)。 +- 可通过 `PageAppService` 等服务进行增删改查。 + +### 运行时 + +- 系统加载 JSON 元数据,解析为 `PageSchema` 对象。 +- 根据 `PageType` 和 `PageProperty` 动态渲染页面布局。 +- 组件根据 `comps` 数组实例化,并绑定数据源和事件。 +- 通过 `MetaAppService` 提供运行时元数据查询接口。 + +这种元数据驱动的架构实现了“配置即代码”的理念,使非技术人员也能快速构建复杂页面。 + +```mermaid +flowchart TD +A[设计时] --> B[用户通过设计器配置页面] +B --> C[生成 JSON 元数据] +C --> D[保存至 meta/apps/caseapp/page/] +D --> E[发布为运行时资源] +F[运行时] --> G[加载 JSON 元数据] +G --> H[解析为 PageSchema 对象] +H --> I[动态渲染组件树] +I --> J[绑定数据源与事件] +J --> K[用户交互] +E --> G +``` + +**图示来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [fhumgxyk.json](file://meta\apps\caseapp\page\fhumgxyk.json) + +**本节来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [MetaAppService.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Application\RenderAppServices\MetaAppService.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\345\270\270\350\247\201\351\227\256\351\242\230\346\216\222\346\237\245.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\345\270\270\350\247\201\351\227\256\351\242\230\346\216\222\346\237\245.md" new file mode 100644 index 0000000000000000000000000000000000000000..7e5ea2a06931d6ff3b32012c94cf367f54c2d6ed --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\345\270\270\350\247\201\351\227\256\351\242\230\346\216\222\346\237\245.md" @@ -0,0 +1,297 @@ +# 常见问题排查 + + +**本文档引用的文件** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [EventTargetTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/EventTargetTypeEnum.cs) +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) +- [0lgu6xpop.json](file://meta/apps/caseapp/page/0lgu6xpop.json) +- [2qceiqni.json](file://meta/apps/caseapp/page/2qceiqni.json) +- [2qme5ln5e.json](file://meta/apps/caseapp/page/2qme5ln5e.json) +- [4tnfvebp1.json](file://meta/apps/caseapp/page/4tnfvebp1.json) +- [5kicsevr.json](file://meta/apps/caseapp/page/5kicsevr.json) +- [7qa2yetz.json](file://meta/apps/caseapp/page/7qa2yetz.json) + + +## 目录 + +1. [元数据加载失败](#元数据加载失败) +2. [页面或组件不显示](#页面或组件不显示) +3. [事件绑定无效](#事件绑定无效) +4. [元数据文件完整性检查](#元数据文件完整性检查) +5. [数据源配置验证](#数据源配置验证) +6. [前端渲染错误分析](#前端渲染错误分析) +7. [错误日志解读指南](#错误日志解读指南) +8. [快速恢复建议](#快速恢复建议) + +## 元数据加载失败 + +元数据加载失败通常表现为系统无法识别应用、页面或菜单,导致页面空白或提示“找不到资源”。常见原因包括 JSON 文件读取异常、文件路径错误、编码问题或文件损坏。 + +### 诊断步骤 + +1. **确认文件路径正确性** + 检查 `meta` 目录下对应应用的路径是否符合规范: + - 应用元数据:`meta/apps/{app-id}/{app-id}.json` + - 页面元数据:`meta/apps/{app-id}/page/{page-id}.json` + - 菜单元数据:`meta/apps/{app-id}/menu/{menu-id}.json` + - 数据源元数据:`meta/apps/{app-id}/datasource/{ds-id}.json` + +2. **验证文件编码格式** + 所有 JSON 文件应保存为 UTF-8 编码,避免使用 BOM 头。若文件开头出现 `` 字符,可能导致解析失败。 + +3. **检查 JSON 语法完整性** + 使用在线 JSON 验证工具或编辑器内置功能检查语法是否正确,确保无遗漏逗号、引号或括号。 + +4. **确认文件权限** + 确保运行环境对 `meta` 目录及其子文件具有读取权限。 + +### 修复方案 + +- 若文件路径错误,按规范重命名或移动文件。 +- 使用文本编辑器(如 VS Code)将文件另存为“UTF-8 无 BOM”格式。 +- 修复 JSON 语法错误,例如补全缺失的 `}` 或 `]`。 +- 在开发环境中重启服务以重新加载元数据。 + +**Section sources** +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) +- [0lgu6xpop.json](file://meta/apps/caseapp/page/0lgu6xpop.json) + +## 页面或组件不显示 + +页面或组件未正常渲染,可能由元数据结构错误、组件注册缺失或依赖关系断裂引起。 + +### 诊断步骤 + +1. **检查页面元数据结构** + 根据 `PageSchemaBase.cs` 定义,页面元数据必须包含以下关键字段: + ```json + { + "aid": "应用ID", + "id": "页面ID", + "n": "页面名称", + "pt": "页面类型", + "pageprop": { "playout": 2 }, + "ds": { "dst": 0 } + } + ``` + 若缺少 `aid` 或 `id`,系统无法定位页面。 + +2. **验证页面类型(PageType)** + 参考 `PageTypeEnum.cs`,`pt` 字段应为有效值: + - `0`: 普通页面 + - `1`: 表单 + - `2`: 列表 + - `5`: 报表 + 若值非法,可能导致渲染引擎跳过该页面。 + +3. **检查组件注册状态** + 组件定义存储于 `meta/parts/componentParts/antdesign/` 目录下,需确认: + - 组件 JSON 文件存在且命名正确(如 `52391a70.json`) + - 对应组件类已在 `H.LowCode.Components.Defaults` 模块中注册 + +4. **查看组件引用是否存在** + 页面元数据中的 `"comps"` 数组应包含合法组件 ID。若引用了不存在的组件 ID,该组件将不会显示。 + +### 修复方案 + +- 补全缺失的必填字段,如 `aid`、`id`、`n`。 +- 将非法 `pt` 值修正为枚举允许的整数。 +- 确保所有引用的组件文件存在于 `componentParts` 目录。 +- 在设计引擎中重新保存页面以刷新组件注册信息。 + +**Section sources** +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [2qceiqni.json](file://meta/apps/caseapp/page/2qceiqni.json) + +## 事件绑定无效 + +事件无法触发或行为异常,通常源于事件定义不匹配或处理函数未注册。 + +### 诊断步骤 + +1. **检查事件结构定义** + 根据 `EventSchema.cs`,事件对象应包含: + ```json + { + "en": "click", + "eht": 30, + "etid": "target-component-id", + "eta": "refresh" + } + ``` + - `en`: 事件名称(如 click、change) + - `eht`: 事件处理类型(`Component=30` 表示组件间通信) + - `etid`: 目标组件或页面 ID + - `eta`: 目标动作(如 refresh、open) + +2. **验证事件目标类型** + `EventTargetTypeEnum.cs` 定义了处理类型: + - `30`: 组件事件(Component) + - `10`: 页面跳转(Page) + - `99`: 自定义脚本(Custom) + 若 `eht` 设置为 `0`(None),事件将被忽略。 + +3. **检查目标组件是否存在** + `etid` 所指向的组件必须在当前页面的 `comps` 数组中定义,否则无法绑定。 + +4. **确认事件处理函数已注册** + 前端组件类(继承 `LowCodeComponentBase`)需实现对应事件的处理方法,如 `OnButtonClick()`。 + +### 修复方案 + +- 确保 `eht` 设置为有效值(如 `30` 表示组件事件)。 +- 核对 `etid` 是否与目标组件 ID 完全一致。 +- 在组件代码中添加缺失的事件处理函数。 +- 使用浏览器开发者工具检查控制台是否有“事件处理器未找到”类错误。 + +**Section sources** +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [EventTargetTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/EventTargetTypeEnum.cs) +- [2qme5ln5e.json](file://meta/apps/caseapp/page/2qme5ln5e.json) + +## 元数据文件完整性检查 + +定期检查元数据文件完整性可预防运行时错误。 + +### 检查清单 + +| 检查项 | 说明 | 工具建议 | +|-------|------|---------| +| 文件存在性 | 确认应用、页面、菜单、数据源文件均存在 | `dir meta\apps\caseapp\page\*.json` | +| JSON 语法 | 验证所有 JSON 文件语法正确 | JSONLint、VS Code | +| 必填字段 | 检查 `id`, `n`, `aid` 等字段是否存在 | 手动检查或脚本校验 | +| 编码格式 | 确保为 UTF-8 无 BOM | Notepad++、VS Code | +| 时间戳格式 | `modifiedTime` 应为 ISO 8601 格式 | 正则表达式 `/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/` | + +### 自动化脚本建议 + +可编写 PowerShell 脚本批量验证: + +```powershell +Get-ChildItem "meta\apps\caseapp\page" -Filter "*.json" | ForEach-Object { + $content = Get-Content $_.FullName -Raw + try { + $json = $content | ConvertFrom-Json + Write-Host "$($_.Name): OK" + } catch { + Write-Host "$($_.Name): JSON Error" -ForegroundColor Red + } +} +``` + +**Section sources** +- [0lgu6xpop.json](file://meta/apps/caseapp/page/0lgu6xpop.json) +- [4tnfvebp1.json](file://meta/apps/caseapp/page/4tnfvebp1.json) + +## 数据源配置验证 + +数据源配置错误会导致页面无法加载数据。 + +### 验证步骤 + +1. **检查 `ds` 字段结构** + 根据 `PageDataSourceSchema.cs`,`ds` 应包含: + - `dst`: 数据源类型(0=无,1=表单,2=API 等) + - `dsv`: 数据源值(如表名 `tb_test1`) + +2. **核对数据源类型** + 如页面为表单(`pt=1`),则 `dst` 应为 `1`,`dsv` 为数据库表名。 + +3. **确认数据源文件存在** + 若使用独立数据源文件,需在 `datasource/{id}.json` 中定义。 + +### 示例配置 + +```json +"ds": { + "dst": 1, + "dsv": "tb_test1" +} +``` + +若 `dst=1` 但 `dsv` 为空,系统将无法查询数据。 + +**Section sources** +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [7qa2yetz.json](file://meta/apps/caseapp/page/7qa2yetz.json) + +## 前端渲染错误分析 + +使用浏览器开发者工具可快速定位前端问题。 + +### 分析步骤 + +1. **打开开发者工具(F12)** +2. **查看“Console”面板** + - 寻找红色错误信息,如: + - `Failed to load meta: caseapp/page/invalid.json` + - `Component not found: abc123` + - `Event handler not registered for: click` +3. **检查“Network”面板** + - 过滤 `meta` 请求,查看是否有 404 或 500 错误 + - 点击失败请求,查看响应内容 +4. **审查元素(Inspect)** + - 查看页面 DOM 结构,确认组件占位符是否存在 + - 检查组件属性是否正确绑定 + +### 常见错误模式 + +| 错误信息 | 可能原因 | 解决方法 | +|--------|--------|--------| +| `Cannot read property 'id' of undefined` | 页面元数据缺失或解析失败 | 检查 JSON 文件路径和语法 | +| `Component with id 'xxx' not registered` | 组件未注册或文件缺失 | 检查 `componentParts` 目录 | +| `Event target not found: yyy` | 事件目标 ID 不存在 | 核对 `etid` 是否正确 | + +**Section sources** +- [5kicsevr.json](file://meta/apps/caseapp/page/5kicsevr.json) + +## 错误日志解读指南 + +后端日志通常记录在 `appsettings.json` 配置的输出位置。 + +### 常见日志条目 + +| 日志内容 | 含义 | 处理建议 | +|--------|------|--------| +| `File not found: meta/apps/app1/page/p1.json` | 元数据文件缺失 | 检查文件路径 | +| `JSON deserialization failed for file: ...` | JSON 格式错误 | 使用验证工具修复 | +| `Component registration failed: ComponentX` | 组件注册异常 | 检查模块注入 | +| `DataSource not found: ds1` | 数据源未定义 | 创建对应数据源文件 | + +### 日志级别说明 + +- **Error**: 致命错误,需立即处理 +- **Warning**: 潜在问题,建议修复 +- **Info**: 正常操作记录 +- **Debug**: 详细调试信息 + +## 快速恢复建议 + +### 应急措施 + +1. **备份与回滚** + - 定期备份 `meta` 目录 + - 出现大面积故障时,恢复至上一个稳定版本 + +2. **最小化测试** + - 创建最简页面(仅含标题)验证基础渲染能力 + - 逐步添加组件定位问题模块 + +3. **重启服务** + - 重启 `DesignEngine` 和 `RenderEngine` 主机服务以清除缓存 + +4. **启用调试模式** + - 在 `appsettings.Development.json` 中设置 `"Logging:LogLevel:Default": "Debug"` + +### 预防措施 + +- 使用版本控制系统(Git)管理元数据变更 +- 在设计引擎中进行变更,避免直接编辑 JSON 文件 +- 定期执行元数据完整性扫描脚本 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..7001924d89feddeb16ead5b1914d09fc918944dc --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227.md" @@ -0,0 +1,241 @@ +# 开发者指南 + + +**本文档引用的文件** +- [README.md](file://README.md) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs) +- [LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs) +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs) +- [RenderEngineDynamicComponentBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/RenderEngineDynamicComponentBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [环境搭建](#环境搭建) +4. [模块开发规范](#模块开发规范) +5. [动态组件加载机制](#动态组件加载机制) +6. [调试与全局状态跟踪](#调试与全局状态跟踪) +7. [常见问题排查](#常见问题排查) +8. [编码规范与性能优化](#编码规范与性能优化) + +## 简介 +本指南旨在为开发者提供一份详尽的实践性文档,帮助其快速上手 H.LowCode 项目并进行二次开发。H.LowCode 是一个基于 .NET 8.0 和 Blazor 的低代码实验性项目,采用模块化架构,包含设计引擎(DesignEngine)和渲染引擎(RenderEngine)两大核心。本指南将详细介绍环境配置、模块开发、动态组件、调试技巧及问题解决方案。 + +## 项目结构 +项目采用分层和模块化设计,主要分为 `meta`(元数据)、`src`(源代码)和 `Tools`(工具)三大目录。 + +```mermaid +graph TB +subgraph "元数据 meta" +apps["apps/ (应用元数据)"] +parts["parts/componentParts/ (组件库元数据)"] +end +subgraph "源代码 src" +Common["Common/ (公共库)"] +DesignEngine["DesignEngine/ (设计引擎)"] +RenderEngine["RenderEngine/ (渲染引擎)"] +end +subgraph "工具 Tools" +DbMigrator["DbMigrator (数据库迁移)"] +MetaMigrator["MetaMigrator (元数据迁移)"] +end +Common --> DesignEngine +Common --> RenderEngine +apps --> DesignEngine +parts --> DesignEngine +DesignEngine --> RenderEngine +``` + +**图示来源** +- [README.md](file://README.md) +- 项目结构信息 + +## 环境搭建 +### 安装 .NET 8.0 SDK +确保已安装 .NET 8.0 SDK。可通过命令行验证: +```bash +dotnet --version +``` + +### 配置 IDE +推荐使用 Visual Studio 2022 或 Visual Studio Code 配合 C# 扩展进行开发。 + +### 还原 NuGet 包 +在项目根目录执行: +```bash +dotnet restore +``` + +### 运行 DesignEngine +1. 启动设计引擎后端: + ```bash + dotnet run --project src/DesignEngine/H.LowCode.DesignEngine.Host + ``` +2. 启动设计引擎前端(WebAssembly): + ```bash + dotnet run --project src/DesignEngine/H.LowCode.DesignEngine.Host.Client + ``` + 后端 `Program.cs` 文件配置了服务端和 WebAssembly 两种渲染模式,前端 `Program.cs` 文件负责初始化客户端应用。 + +**代码示例:DesignEngine 后端启动配置** +```csharp +// src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + +await builder.AddApplicationAsync(); // 注册 ABP 模块 + +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(LowCodeGlobalVariables.AdditionalAssemblies); // 动态加载程序集 +``` + +### 运行 RenderEngine +运行渲染引擎的步骤与设计引擎类似: +```bash +dotnet run --project src/RenderEngine/H.LowCode.RenderEngine.Host +dotnet run --project src/RenderEngine/H.LowCode.RenderEngine.Host.Client +``` +其 `Program.cs` 文件结构与 DesignEngine 高度一致,体现了代码复用。 + +**图示来源** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs#L1-L77) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs#L1-L78) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs#L1-L20) + +## 模块开发规范 +### 创建新的 ABP 模块 +1. 在 `src` 目录下创建新项目,例如 `H.LowCode.MyModule`。 +2. 创建一个继承自 `AbpModule` 的类,例如 `MyModule.cs`。 +3. 在 `ConfigureServices` 方法中注册服务和依赖。 + +**代码示例:模块定义** +```csharp +// MyAppModule.cs +public class MyAppModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + // 注册服务 + context.Services.AddTransient(); + // 处理依赖注入 + Configure(options => + { + options.Resources.Add("zh-Hans"); + }); + } +} +``` + +### 服务注册与依赖注入 +遵循 ABP 框架的依赖注入规范,使用 `context.Services` 进行服务注册,并通过构造函数注入使用。 + +**节来源** +- [MyAppModule.cs](file://src/DesignEngine/H.LowCode.MyApp/MyAppModule.cs) + +## 动态组件加载机制 +### 实现原理 +动态组件是低代码平台的核心。`LowCodeDynamicComponentBase` 是所有动态组件的基类,它通过元数据(JSON)来驱动 UI 的渲染。 + +1. **元数据驱动**:组件的属性、样式、事件等信息存储在 `meta` 目录的 JSON 文件中。 +2. **基类继承**:所有组件继承自 `LowCodeComponentBase`,而动态组件则继承自 `LowCodeDynamicComponentBase`。 +3. **运行时解析**:在运行时,系统读取 JSON 元数据,创建组件实例,并根据元数据设置其属性。 + +**类图:动态组件继承关系** +```mermaid +classDiagram +class LowCodeComponentBase { ++string Id ++CascadingValue AppModel ++OnInitializedAsync() ++InvokeAsync(Action) +} +class LowCodeDynamicComponentBase { ++ComponentSchema Schema ++Dictionary~string, object~ Attributes ++OnParametersSetAsync() ++SetParametersFromSchema() +} +class DesignEngineDynamicComponentBase { ++ComponentPartsSchema PartsSchema ++OnParametersSetAsync() override +} +class RenderEngineDynamicComponentBase { ++ComponentSchema ComponentSchema ++OnParametersSetAsync() override +} +LowCodeComponentBase <|-- LowCodeDynamicComponentBase +LowCodeDynamicComponentBase <|-- DesignEngineDynamicComponentBase +LowCodeDynamicComponentBase <|-- RenderEngineDynamicComponentBase +``` + +**图示来源** +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs#L1-L50) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs#L1-L40) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L1-L20) +- [RenderEngineDynamicComponentBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/RenderEngineDynamicComponentBase.cs#L1-L20) + +### 调试技巧 +- 在 `LowCodeDynamicComponentBase.OnParametersSetAsync()` 方法中设置断点,观察 `Schema` 对象的加载过程。 +- 检查 `meta` 目录下的 JSON 文件是否正确,确保 `id` 字段与代码中的组件匹配。 + +## 调试与全局状态跟踪 +### 调试组件渲染流程 +1. 在 `RenderEngine` 的 `MetaAppService` 中获取页面元数据。 +2. 在 `App.razor` 组件的 `OnInitializedAsync` 方法中,观察元数据的传递。 +3. 在具体的组件(如 `FormComponentRender.razor`)中,通过 `ComponentSchema` 属性查看其配置。 + +### 利用 LowCodeGlobalVariables 进行全局状态跟踪 +`LowCodeGlobalVariables` 类用于在客户端存储全局变量,如动态加载的程序集。 + +**代码示例:全局变量使用** +```csharp +// src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs +public static class LowCodeGlobalVariables +{ + public static Assembly[] AdditionalAssemblies { get; set; } = Array.Empty(); +} + +// 在 Program.cs 中使用 +app.MapRazorComponents() + .AddAdditionalAssemblies(LowCodeGlobalVariables.AdditionalAssemblies); +``` +通过修改 `AdditionalAssemblies`,可以动态地向应用注入新的功能模块,便于调试和扩展。 + +**节来源** +- [LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs#L1-L10) +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs#L1-L10) + +## 常见问题排查 +### 元数据加载失败 +- **检查点**:确认 `meta` 目录下的 JSON 文件路径和文件名是否正确。 +- **检查点**:检查 `appsettings.json` 中的元数据路径配置。 + +### 组件不显示 +- **检查点**:检查组件的 `id` 是否在元数据中正确定义。 +- **检查点**:在 `LowCodeDynamicComponentBase` 的 `SetParametersFromSchema` 方法中调试,确认属性是否成功绑定。 + +### 事件绑定无效 +- **检查点**:检查元数据中 `events` 字段的配置,确保 `target` 和 `action` 正确。 +- **检查点**:在组件的 `OnInitializedAsync` 方法中,确认事件处理程序是否被正确注册。 + +## 编码规范与性能优化 +### 编码规范 +- 遵循 ABP 框架的命名和分层规范。 +- 组件的元数据变更需同步更新 JSON Schema。 + +### 性能优化建议 +- **元数据缓存**:对频繁读取的元数据进行内存缓存,减少文件 I/O。 +- **按需加载**:对于大型应用,实现组件的懒加载,提升首屏渲染速度。 +- **减少重渲染**:在 `OnParametersSetAsync` 中进行必要的变更检查,避免不必要的 UI 更新。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\346\250\241\345\235\227\345\274\200\345\217\221\350\247\204\350\214\203.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\346\250\241\345\235\227\345\274\200\345\217\221\350\247\204\350\214\203.md" new file mode 100644 index 0000000000000000000000000000000000000000..34c4b6aca068b6071bee924b64f44a39aff52d54 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\346\250\241\345\235\227\345\274\200\345\217\221\350\247\204\350\214\203.md" @@ -0,0 +1,384 @@ +# 模块开发规范 + + +**本文档引用的文件** +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [DesignEngineApplicationModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/DesignEngineApplicationModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [DesignEngineModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine/DesignEngineModule.cs) +- [RenderEngineModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine/RenderEngineModule.cs) +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) +- [MyAppModule.cs](file://src/DesignEngine/H.LowCode.MyApp/MyAppModule.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心模块实现模式](#核心模块实现模式) +4. [模块依赖关系与解耦设计](#模块依赖关系与解耦设计) +5. [模块生命周期管理](#模块生命周期管理) +6. [服务注册与依赖注入](#服务注册与依赖注入) +7. [配置选项注入实践](#配置选项注入实践) +8. [应用状态管理](#应用状态管理) +9. [最佳实践建议](#最佳实践建议) +10. [结论](#结论) + +## 引言 +本文档详细说明基于ABP框架的模块化开发规范,涵盖模块定义、服务注册、依赖管理、生命周期控制等关键方面。通过分析实际代码实现,提供可操作的最佳实践指导,帮助开发者构建高内聚、低耦合的模块化系统。 + +## 项目结构 +本项目采用分层模块化架构,主要分为Common、DesignEngine、RenderEngine和Tools四大模块群。每个模块群包含多个功能模块,遵循ABP框架的模块化设计原则。 + +```mermaid +graph TB +subgraph "Common" +ComponentBase["H.LowCode.ComponentBase"] +ComponentsDefaults["H.LowCode.Components.Defaults"] +Configuration["H.LowCode.Configuration"] +end +subgraph "DesignEngine" +DE_Host["H.LowCode.DesignEngine.Host"] +DE_Application["H.LowCode.DesignEngine.Application"] +DE_Domain["H.LowCode.DesignEngine.Domain"] +DE_Repository["H.LowCode.DesignEngine.Repository.JsonFile"] +end +subgraph "RenderEngine" +RE_Host["H.LowCode.RenderEngine.Host"] +RE_Application["H.LowCode.RenderEngine.Application"] +RE_Domain["H.LowCode.RenderEngine.Domain"] +RE_Repository["H.LowCode.RenderEngine.Repository.JsonFile"] +end +subgraph "Tools" +DbMigrator["H.LowCode.DbMigrator"] +end +ComponentBase --> DE_Host +ComponentBase --> RE_Host +ComponentsDefaults --> DE_Host +ComponentsDefaults --> RE_Host +Configuration --> DE_Application +Configuration --> RE_Application +DE_Application --> DE_Domain +RE_Application --> RE_Domain +DE_Repository --> DE_Domain +RE_Repository --> RE_Domain +DE_Host --> DbMigrator +RE_Host --> DbMigrator +``` + +**图示来源** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) + +## 核心模块实现模式 +ABP模块通过继承`AbpModule`基类实现,每个模块类负责定义其自身的服务注册和配置逻辑。 + +### 基础模块实现 +`LowCodeComponentBaseModule`作为基础组件模块,展示了最简化的模块实现模式: + +```csharp +public class LowCodeComponentBaseModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + //状态管理 + context.Services.AddScoped(typeof(ComponentState<>)); + context.Services.AddScoped(typeof(ComponentState<,>)); + } +} +``` + +该模块仅在`ConfigureServices`方法中注册了泛型组件状态服务,生命周期为Scoped。 + +**模块来源** +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) + +### 高级模块实现 +`DesignEngineHostModule`展示了复杂的模块实现,包含多个依赖模块和丰富的配置逻辑: + +```csharp +[DependsOn( + typeof(AbpAutofacModule), + typeof(AbpAspNetCoreMvcModule), + typeof(DesignEngineApplicationModule), + typeof(DesignEngineEntityFrameworkCoreModule), + typeof(DesignEngineJsonFileRepositoryModule), + typeof(LowCodeWorkbenchModule), + typeof(DesignEngineModule), + typeof(MyAppModule), + typeof(PartsDesignEngineModule), + typeof(LowCodeDefaultComponentModule), + typeof(LowCodeComponentBaseModule) +)] +public class DesignEngineHostModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + ConfigureAutoApiControllers(); + context.Services.AddSingleton(new LowCodeAppState(true)); + } + + private void ConfigureAutoApiControllers() + { + Configure(options => + { + options.ConventionalControllers.Create(typeof(DesignEngineApplicationModule).Assembly); + }); + } +} +``` + +此模块通过`[DependsOn]`特性声明了对多个其他模块的依赖,并在`ConfigureServices`中配置了自动API控制器和应用状态服务。 + +**模块来源** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) + +## 模块依赖关系与解耦设计 +ABP框架通过`[DependsOn]`特性管理模块间的依赖关系,确保模块按正确顺序初始化。 + +### 依赖关系图 +```mermaid +graph TD +AbpAutofacModule --> DesignEngineHostModule +AbpAspNetCoreMvcModule --> DesignEngineHostModule +DesignEngineApplicationModule --> DesignEngineHostModule +DesignEngineEntityFrameworkCoreModule --> DesignEngineHostModule +DesignEngineJsonFileRepositoryModule --> DesignEngineHostModule +LowCodeWorkbenchModule --> DesignEngineHostModule +DesignEngineModule --> DesignEngineHostModule +MyAppModule --> DesignEngineHostModule +PartsDesignEngineModule --> DesignEngineHostModule +LowCodeDefaultComponentModule --> DesignEngineHostModule +LowCodeComponentBaseModule --> DesignEngineHostModule +DesignEngineDomainModule --> DesignEngineApplicationModule +DesignEngineDomainModule --> DesignEngineJsonFileRepositoryModule +DesignEngineDomainModule --> DesignEngineRemoteServiceRepositoryModule +RenderEngineDomainModule --> RenderEngineApplicationModule +RenderEngineDomainModule --> RenderEngineJsonFileRepositoryModule +RenderEngineDomainModule --> RenderEngineRemoteServiceRepositoryModule +``` + +**图示来源** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [DesignEngineApplicationModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/DesignEngineApplicationModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + +### 解耦设计原则 +1. **单向依赖**:模块间依赖应为单向,避免循环依赖 +2. **分层依赖**:高层模块可以依赖低层模块,但反之则不行 +3. **接口隔离**:通过接口而非具体实现进行依赖 +4. **最小依赖**:只依赖必需的模块,避免过度依赖 + +## 模块生命周期管理 +ABP模块提供了完整的生命周期管理方法,包括初始化和关闭阶段。 + +### 生命周期方法 +```csharp +public class RenderEngineHostModule : AbpModule +{ + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + // 应用初始化逻辑 + } + + public override void OnApplicationShutdown(ApplicationShutdownContext context) + { + // 应用关闭逻辑 + } +} +``` + +### 生命周期执行顺序 +```mermaid +flowchart TD +A["依赖模块 OnPreApplicationInitialization"] --> B["当前模块 OnPreApplicationInitialization"] +B --> C["依赖模块 OnApplicationInitialization"] +C --> D["当前模块 OnApplicationInitialization"] +D --> E["依赖模块 OnPostApplicationInitialization"] +E --> F["当前模块 OnPostApplicationInitialization"] +F --> G["应用运行"] +G --> H["当前模块 OnApplicationShutdown"] +H --> I["依赖模块 OnApplicationShutdown"] +``` + +**图示来源** +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) + +## 服务注册与依赖注入 +ABP框架基于Microsoft.Extensions.DependencyInjection实现依赖注入,支持三种生命周期。 + +### 服务生命周期 +| 生命周期 | 说明 | 使用场景 | +|--------|------|--------| +| Singleton | 单例模式,整个应用生命周期内仅创建一次 | 全局状态、配置服务 | +| Scoped | 作用域模式,每个请求创建一次 | 数据库上下文、用户会话 | +| Transient | 瞬态模式,每次请求都创建新实例 | 工具类、无状态服务 | + +### 服务注册示例 +```csharp +// 单例服务注册 +context.Services.AddSingleton(new LowCodeAppState(true)); + +// 作用域服务注册 +context.Services.AddScoped(typeof(ComponentState<>)); + +// 瞬态服务注册 +context.Services.AddTransient(); + +// 框架服务注册 +context.Services.AddAntDesign(); +``` + +**代码来源** +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) +- [DesignEngineModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine/DesignEngineModule.cs) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) + +## 配置选项注入实践 +ABP框架支持通过`IOptions`模式注入配置选项,实现配置与代码的解耦。 + +### 配置类定义 +```csharp +public class MetaOption +{ + public const string SectionName = "Meta"; + public string AppsFilePath { get; set; } + public string PartsFilePath { get; set; } +} +``` + +### 配置注入实现 +```csharp +public class RenderEngineApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + context.Services.Configure(configuration.GetSection(MetaOption.SectionName)); + + Configure(options => + { + options.AddMaps(); + }); + } +} +``` + +### 配置使用方式 +在服务中通过依赖注入获取配置: + +```csharp +public class SomeService +{ + private readonly MetaOption _metaOption; + + public SomeService(IOptions metaOption) + { + _metaOption = metaOption.Value; + } +} +``` + +**代码来源** +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + +## 应用状态管理 +应用状态通过`LowCodeAppState`类实现,用于区分设计时和运行时环境。 + +### 状态类实现 +```csharp +public class LowCodeAppState +{ + public LowCodeAppState(bool isDesign) + { + IsDesign = isDesign; + } + + /// + /// 是否设计时 + /// + public bool IsDesign { get; } +} +``` + +### 状态注入与使用 +```csharp +public abstract class LowCodeComponentBase : AbpComponentBase +{ + [Inject] + private LowCodeAppState LowCodeAppState { get; set; } + + protected bool IsDesign + { + get + { + return LowCodeAppState.IsDesign; + } + } +} +``` + +在宿主模块中注册为单例服务: + +```csharp +// 设计时环境 +context.Services.AddSingleton(new LowCodeAppState(true)); + +// 运行时环境 +context.Services.AddSingleton(new LowCodeAppState(false)); +``` + +**代码来源** +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) + +## 最佳实践建议 +### 模块设计原则 +1. **单一职责**:每个模块应专注于单一功能领域 +2. **高内聚**:模块内部组件应紧密相关 +3. **低耦合**:模块间依赖应尽量减少 +4. **可复用**:设计通用模块供多个项目使用 + +### 服务注册最佳实践 +1. **选择合适的生命周期**: + - 无状态服务使用Transient + - 请求级服务使用Scoped + - 全局服务使用Singleton + +2. **避免服务膨胀**: + - 不要将所有服务注册在同一个模块 + - 按功能领域分组注册 + +3. **使用条件注册**: +```csharp +if (!context.Services.Any(s => s.ServiceType == typeof(SomeService))) +{ + context.Services.AddScoped(); +} +``` + +### 依赖管理建议 +1. **显式声明依赖**:使用`[DependsOn]`特性明确声明依赖 +2. **避免循环依赖**:通过接口抽象或事件机制解耦 +3. **分层依赖管理**:建立清晰的依赖层次结构 + +### 配置管理建议 +1. **配置分离**:不同环境使用不同配置文件 +2. **配置验证**:在启动时验证关键配置项 +3. **配置默认值**:为可选配置提供合理默认值 + +## 结论 +基于ABP框架的模块化开发提供了强大的基础设施支持。通过遵循本文档的规范和最佳实践,开发者可以构建出结构清晰、易于维护的模块化系统。关键要点包括: +- 正确使用`AbpModule`基类和生命周期方法 +- 合理管理模块间的依赖关系 +- 恰当选择服务生命周期 +- 规范使用配置选项注入 +- 遵循解耦设计原则 + +这些实践将帮助团队构建高质量、可扩展的低代码平台。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\216\257\345\242\203\346\220\255\345\273\272.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\216\257\345\242\203\346\220\255\345\273\272.md" new file mode 100644 index 0000000000000000000000000000000000000000..75fa4e8499dfd52d8d61e67c1a87247dacff8504 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\216\257\345\242\203\346\220\255\345\273\272.md" @@ -0,0 +1,295 @@ +# 环境搭建 + + +**本文档引用的文件** +- [global.json](file://global.json) +- [README.md](file://README.md) +- [src\DesignEngine\H.LowCode.DesignEngine.Host\Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [src\DesignEngine\H.LowCode.DesignEngine.Host\appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [src\DesignEngine\H.LowCode.DesignEngine.Host\Properties\launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\Properties\launchSettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Properties/launchSettings.json) +- [src\Common\H.LowCode.Configuration\Options\MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [src\Common\H.LowCode.Configuration\Options\SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) +- [src\DesignEngine\H.LowCode.DesignEngine.Host.Client\LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs) +- [src\RenderEngine\H.LowCode.RenderEngine.Host.Client\LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) + + +## 目录 +1. [开发环境搭建](#开发环境搭建) +2. [IDE配置](#ide配置) +3. [项目依赖还原](#项目依赖还原) +4. [服务启动与端口配置](#服务启动与端口配置) +5. [前后端联调方法](#前后端联调方法) +6. [常见问题解决方案](#常见问题解决方案) +7. [环境验证清单](#环境验证清单) + +## 开发环境搭建 + +### .NET 8.0 SDK安装与验证 + +根据项目根目录下的 `global.json` 文件,本项目要求使用 **.NET 9.0.100** SDK。尽管文档目标中提及 .NET 8.0,但实际配置已升级至 .NET 9.0。 + +**安装步骤:** +1. 访问 [.NET 下载官网](https://dotnet.microsoft.com/download) +2. 下载并安装 **.NET SDK 9.0.100** +3. 安装完成后,打开命令行工具,执行以下命令验证安装: +```bash +dotnet --version +``` +预期输出:`9.0.100` + +**验证要点:** +- 确保 `dotnet --list-sdks` 命令输出中包含 `9.0.100` +- 若存在多个版本,`global.json` 会自动引导使用指定版本 + +**Section sources** +- [global.json](file://global.json) + +## IDE配置 + +### 推荐IDE:Visual Studio 2022 或 VS Code + +#### Visual Studio 2022 配置 +1. 安装 **Visual Studio 2022**(建议 17.9 或更高版本) +2. 安装工作负载: + - **ASP.NET 和 Web 开发** + - **.NET 桌面开发** +3. 打开解决方案文件(若存在)或直接打开项目根目录 +4. 启用 **Blazor WebAssembly** 和 **Blazor Server** 支持 + +#### VS Code 配置 +1. 安装 **VS Code** +2. 安装必要扩展: + - **C# for Visual Studio Code (powered by OmniSharp)** + - **.NET Install Tool for Extension Authors** + - **Blazor Developer Tools** +3. 安装完成后,打开项目根目录 +4. 使用集成终端执行 `dotnet restore` 还原依赖 + +**Section sources** +- [README.md](file://README.md) + +## 项目依赖还原 + +### NuGet包恢复步骤 + +项目采用标准的 .NET 多项目结构,依赖通过 NuGet 包管理。 + +**还原步骤:** +1. 打开命令行,进入项目根目录 `` +2. 执行以下命令还原所有项目的依赖: +```bash +dotnet restore +``` +3. 构建整个解决方案以验证依赖完整性: +```bash +dotnet build +``` + +**关键依赖说明:** +- **Blazor WebAssembly**:用于前端交互 +- **Autofac**:依赖注入容器 +- **EntityFrameworkCore**:数据库访问 +- **System.Text.Json**:JSON序列化 + +**Section sources** +- [README.md](file://README.md) + +## 服务启动与端口配置 + +### DesignEngine(设计引擎)启动 + +DesignEngine 是低代码平台的设计界面宿主服务。 + +**启动配置:** +- **HTTPS端口**:`5181` +- **HTTP端口**:`5180` +- **启动项目**:`H.LowCode.DesignEngine.Host` + +**启动方式:** +```bash +cd src\DesignEngine\H.LowCode.DesignEngine.Host +dotnet run +``` + +**配置文件来源:** +- `launchSettings.json` 明确定义了 `applicationUrl` 为 `https://localhost:5181;http://localhost:5180` + +### RenderEngine(渲染引擎)启动 + +RenderEngine 是低代码应用的运行时渲染服务。 + +**启动配置:** +- **HTTPS端口**:`5191` +- **HTTP端口**:`5190` +- **启动项目**:`H.LowCode.RenderEngine.Host` + +**启动方式:** +```bash +cd src\RenderEngine\H.LowCode.RenderEngine.Host +dotnet run +``` + +**配置文件来源:** +- `launchSettings.json` 明确定义了 `applicationUrl` 为 `https://localhost:5191;http://localhost:5190` + +### 启动顺序 + +**必须先启动 RenderEngine,再启动 DesignEngine**。 + +**原因分析:** +- DesignEngine 的 `appsettings.json` 中配置了 `RemoteServices.Default.BaseUrl` 为 `https://localhost:5181`,但此配置存在循环引用风险 +- RenderEngine 的 `RemoteServices.Default.BaseUrl` 指向 `https://localhost:5191`,表明 DesignEngine 可能需要调用 RenderEngine 的元数据服务 +- 为确保元数据加载正常,应优先启动 RenderEngine + +```mermaid +flowchart TD +A["启动 RenderEngine (端口 5191)"] --> B["启动 DesignEngine (端口 5181)"] +B --> C["访问 DesignEngine 设计界面"] +C --> D["加载来自 RenderEngine 的元数据"] +``` + +**Diagram sources** +- [src\DesignEngine\H.LowCode.DesignEngine.Host\appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json#L18-L21) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json#L18-L21) +- [src\DesignEngine\H.LowCode.DesignEngine.Host\Properties\launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json#L10-L11) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\Properties\launchSettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Properties/launchSettings.json#L10-L11) + +**Section sources** +- [src\DesignEngine\H.LowCode.DesignEngine.Host\Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +## 前后端联调方法 + +### 前后端架构分析 + +本项目采用 **Blazor Server + WebAssembly** 混合渲染模式。 + +**前端组件加载机制:** +- 通过 `LowCodeGlobalVariables.AdditionalAssemblies` 动态加载额外程序集 +- DesignEngine 加载工作台、部件设计等模块 +- RenderEngine 加载 AntBlazor 主题模块 + +**联调步骤:** +1. 确保两个服务均已启动 +2. 访问 DesignEngine 界面:`https://localhost:5181` +3. 在设计界面中创建或编辑页面 +4. 元数据将自动保存至 `meta` 目录下的 JSON 文件 +5. 访问 RenderEngine 查看渲染效果:`https://localhost:5191` + +**元数据路径配置:** +- `Meta.appsFilePath`:`../../../meta/apps` (相对路径) +- `Meta.partsFilePath`:`../../../meta/parts` (部件库路径) + +```mermaid +classDiagram +class MetaOption { ++string AppsFilePath ++string PartsFilePath +} +class SiteOption { ++string AppId ++string SiteUrl +} +class LowCodeGlobalVariables { ++Type LowCodeDefaultLayout ++Assembly[] AdditionalAssemblies +} +MetaOption --> "DesignEngine & RenderEngine" : 配置注入 +SiteOption --> "RenderEngine" : 多站点支持 +LowCodeGlobalVariables --> "Host.Client" : 组件程序集加载 +``` + +**Diagram sources** +- [src\Common\H.LowCode.Configuration\Options\MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [src\Common\H.LowCode.Configuration\Options\SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) +- [src\DesignEngine\H.LowCode.DesignEngine.Host.Client\LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs) +- [src\RenderEngine\H.LowCode.RenderEngine.Host.Client\LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) + +**Section sources** +- [src\DesignEngine\H.LowCode.DesignEngine.Host\appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +## 常见问题解决方案 + +### SDK版本不匹配 + +**问题现象:** +`dotnet run` 报错,提示找不到指定版本的 SDK。 + +**解决方案:** +1. 确认已安装 `.NET 9.0.100` +2. 检查 `dotnet --list-sdks` 输出 +3. 若版本不符,修改 `global.json` 或安装对应版本 + +### 端口占用 + +**问题现象:** +`Unable to bind to https://localhost:5181` 等错误。 + +**解决方案:** +1. 查找占用进程: +```bash +netstat -ano | findstr :5181 +``` +2. 结束占用进程: +```bash +taskkill /PID <进程ID> /F +``` +3. 或修改 `launchSettings.json` 中的端口号 + +### HTTPS证书错误 + +**问题现象:** +浏览器提示 `NET::ERR_CERT_AUTHORITY_INVALID` + +**解决方案:** +1. 信任开发证书: +```bash +dotnet dev-certs https --trust +``` +2. 若失败,重置证书: +```bash +dotnet dev-certs https --clean +dotnet dev-certs https --trust +``` + +### 元数据加载失败 + +**问题现象:** +DesignEngine 无法加载应用或部件。 + +**解决方案:** +1. 检查 `meta` 目录路径是否正确 +2. 确认 `Meta.appsFilePath` 和 `Meta.partsFilePath` 配置 +3. 验证 JSON 文件格式是否正确 + +**Section sources** +- [global.json](file://global.json) +- [src\DesignEngine\H.LowCode.DesignEngine.Host\appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +## 环境验证清单 + +完成环境搭建后,请按以下清单验证: + +| 检查项 | 验证方法 | 预期结果 | +|--------|---------|---------| +| **.NET SDK版本** | `dotnet --version` | 输出 `9.0.100` | +| **DesignEngine启动** | 访问 `https://localhost:5181` | 页面正常加载,无500错误 | +| **RenderEngine启动** | 访问 `https://localhost:5191` | 页面正常加载,显示应用列表 | +| **元数据加载** | 检查浏览器开发者工具网络请求 | 成功加载 `meta/apps/caseapp/caseapp.json` 等文件 | +| **前后端通信** | 在DesignEngine中创建页面 | 元数据保存至 `meta` 目录,可在RenderEngine中查看 | + +**验证成功标志:** +- 两个服务均能独立启动 +- DesignEngine 可正常编辑页面 +- RenderEngine 可正确渲染设计结果 +- 无控制台错误或警告 + +**Section sources** +- [src\DesignEngine\H.LowCode.DesignEngine.Host\appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [src\RenderEngine\H.LowCode.RenderEngine.Host\appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [meta](file://meta) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\273\204\344\273\266\350\260\203\350\257\225\346\212\200\345\267\247.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\273\204\344\273\266\350\260\203\350\257\225\346\212\200\345\267\247.md" new file mode 100644 index 0000000000000000000000000000000000000000..e65c64575238c7dd0eb02bb047c1d5363b3f6a1d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\273\204\344\273\266\350\260\203\350\257\225\346\212\200\345\267\247.md" @@ -0,0 +1,249 @@ +# 组件调试技巧 + + +**本文档引用的文件** +- [LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs) +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [ComponentFragmentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入讲解低代码平台中组件的调试方法,重点介绍如何利用全局变量进行状态跟踪与日志输出,定位组件渲染异常问题。文档剖析了动态组件加载机制的实现原理,包括组件类型解析、实例化过程和生命周期管理。提供了调试组件渲染流程的具体步骤,包括设置断点、查看元数据绑定、检查属性赋值顺序。最后,文档列举了组件不显示、属性未生效、事件绑定失败等典型问题的排查路径与解决方案。 + +## 项目结构 +本项目采用分层架构设计,主要分为 `meta`(元数据)、`src`(源代码)和工具模块。`meta` 目录存放应用、页面和组件的JSON元数据定义。`src` 目录是核心代码所在,包含通用组件基类、设计引擎和渲染引擎。设计引擎(DesignEngine)负责可视化设计时的组件管理,而渲染引擎(RenderEngine)负责运行时的组件渲染。`Tools` 目录包含数据库和元数据迁移工具。 + +```mermaid +graph TB +subgraph "元数据" +meta["meta/"] +end +subgraph "源代码" +src["src/"] +end +subgraph "工具" +tools["Tools/"] +end +meta --> src +src --> tools +``` + +**Diagram sources** +- [meta](file://meta) +- [src](file://src) +- [Tools](file://Tools) + +**Section sources** +- [project_structure](file://#L1-L20) + +## 核心组件 +低代码平台的核心在于其组件化架构。`LowCodeComponentBase` 是所有组件的基类,提供了导航、状态管理等基础功能。`LowCodeDynamicComponentBase` 是动态组件的核心,负责根据元数据动态创建和渲染Blazor组件。`DesignEngineDynamicComponentBase` 继承自前者,是设计引擎中组件渲染的实现,包含了渲染数据源、子节点和内容的完整逻辑。 + +**Section sources** +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs#L10-L49) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs#L12-L121) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L9-L219) + +## 架构概述 +该低代码平台采用设计时与运行时分离的架构。设计时,用户通过设计引擎拖拽组件,其元数据(如组件类型、属性、数据源)被保存为JSON文件。运行时,渲染引擎读取这些元数据,并通过反射动态创建对应的Blazor组件实例,完成页面渲染。`LowCodeGlobalVariables` 在两个环境中定义了不同的默认布局和附加程序集,实现了环境隔离。 + +```mermaid +graph LR +A[设计时] --> |保存元数据| B[JSON文件] +B --> |加载元数据| C[运行时] +C --> D[动态组件渲染] +D --> E[最终UI] +``` + +**Diagram sources** +- [meta](file://meta) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L9-L219) + +## 详细组件分析 + +### 动态组件加载机制分析 +动态组件加载是低代码平台的核心功能,其实现主要依赖于 `LowCodeDynamicComponentBase` 和 `DesignEngineDynamicComponentBase` 两个类。 + +#### 类图 +```mermaid +classDiagram +class LowCodeComponentBase { ++string StateKey ++bool IsDesign ++Uri GetBaseUri() ++void NavigateTo(string uri) ++string GetQueryValue(string key) +} +class LowCodeDynamicComponentBase { +-void RenderComponentAttributes(RenderTreeBuilder, int, string, Type, ComponentAttributeFragmentSchema[]) +-void RenderComponentAttribute(RenderTreeBuilder, int, string, Type, ComponentAttributeFragmentSchema) +-void RenderComponentSimpleAttribute(RenderTreeBuilder, int, string, Type, ComponentAttributeFragmentSchema) +-bool SupportsValueBinding(Type) +} +class DesignEngineDynamicComponentBase { ++RenderFragment RenderComponent(ComponentPartsSchema) +-void RenderComponentRecursive(string, bool, ComponentPartsSchema, ComponentPartsDataSourceSchema, ComponentPartsFragmentSchema, RenderTreeBuilder, int) +-void RenderDataSource(string, ComponentPartsSchema, ComponentPartsDataSourceSchema, RenderTreeBuilder, int) +-void RenderOptionDataSource(string, ComponentPartsDataSourceSchema, RenderTreeBuilder, int) +-void RenderChildFragments(string, ComponentPartsSchema, ComponentPartsFragmentSchema, RenderTreeBuilder, int) +-void RenderContent(string, ComponentPartsSchema, ComponentPartsFragmentSchema, RenderTreeBuilder, int) +} +LowCodeComponentBase <|-- LowCodeDynamicComponentBase +LowCodeDynamicComponentBase <|-- DesignEngineDynamicComponentBase +``` + +**Diagram sources** +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs#L10-L49) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs#L12-L121) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L9-L219) + +#### 实现原理 +1. **组件类型解析**:`RenderComponentRecursive` 方法首先检查 `ComponentPartsFragmentSchema` 的 `TypeName`。如果为空,则使用 `DefaultTypeName`。然后通过 `Type.GetType(componentFragment.TypeName, true)` 反射获取组件的 `Type` 对象。 +2. **实例化过程**:在获取到 `Type` 对象后,使用 `RenderTreeBuilder.OpenComponent(index++, componentType)` 在渲染树中打开一个组件节点,Blazor框架会在此时实例化该组件。 +3. **生命周期管理**:组件的生命周期由Blazor框架管理。`RenderComponentRecursive` 方法在 `OpenComponent` 和 `CloseComponent` 之间调用 `RenderComponentAttributes` 等方法,这些方法在组件的 `OnParametersSet` 或 `BuildRenderTree` 阶段执行,负责设置属性和绑定事件。 + +**Section sources** +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs#L12-L121) +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L31-L65) + +### 组件渲染流程分析 +组件渲染流程是调试的关键,主要在 `DesignEngineDynamicComponentBase` 的 `RenderComponentRecursive` 方法中实现。 + +#### 序列图 +```mermaid +sequenceDiagram +participant Base as DesignEngineDynamicComponentBase +participant Builder as RenderTreeBuilder +participant Attr as RenderComponentAttributes +participant DS as RenderDataSource +Base->>Base : RenderComponentRecursive() +Base->>Builder : OpenComponent(componentType) +Base->>Attr : RenderComponentAttributes() +alt 有数据源 +Base->>DS : RenderDataSource() +else 有子节点 +Base->>Base : RenderChildFragments() +else 有内容 +Base->>Base : RenderContent() +end +Base->>Builder : CloseComponent() +``` + +**Diagram sources** +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L31-L65) + +#### 调试步骤 +1. **设置断点**:在 `DesignEngineDynamicComponentBase.cs` 的 `RenderComponentRecursive` 方法的起始处设置断点。 +2. **查看元数据绑定**:在断点处,检查传入的 `componentFragment` 参数。其 `TypeName` 属性决定了要渲染的组件类型,`Attributes` 数组包含了所有要绑定的属性。 +3. **检查属性赋值顺序**:程序会依次调用 `RenderComponentAttributes` -> `RenderComponentAttribute` -> `RenderComponentSimpleAttribute`。在 `RenderComponentSimpleAttribute` 中,`attr.AttributeClrType` 定义了属性的CLR类型,`attr.AttributeValue` 是原始值,通过 `ConvertToRealType` 转换后赋值给组件。 + +**Section sources** +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L31-L65) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs#L70-L121) + +### 全局状态跟踪分析 +`LowCodeGlobalVariables` 类用于在不同环境中定义全局常量,是调试时的重要参考。 + +#### 设计引擎全局变量 +```csharp +public static class LowCodeGlobalVariables +{ + public static readonly Type LowCodeDefaultLayout = typeof(DesignEngineBase.DesignEngineNavLayout); + public static readonly Assembly[] AdditionalAssemblies = [...]; +} +``` +此定义指明了设计时的默认布局组件和需要加载的程序集。 + +#### 渲染引擎全局变量 +```csharp +public static class LowCodeGlobalVariables +{ + public static readonly Type LowCodeDefaultLayout = typeof(AntBlazorThemeLayout); + public static readonly Assembly[] AdditionalAssemblies = [...]; +} +``` +此定义指明了运行时的默认布局组件和需要加载的程序集。 + +通过对比这两个文件,可以快速定位环境配置问题。 + +**Section sources** +- [LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs#L1-L16) +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs#L1-L14) + +## 依赖分析 +组件的渲染依赖于清晰的元数据结构。`ComponentPartsSchema` 是设计时组件的元数据模型,它包含 `Fragment`(渲染片段)、`DataSource`(数据源)和 `AttributeDefineGroups`(属性定义)等关键信息。`ComponentPartsFragmentSchema` 继承自 `ComponentFragmentSchemaBase`,定义了 `DefaultTypeName` 和 `ChildFragments`,是组件树结构的基础。 + +```mermaid +classDiagram +class ComponentPartsSchema { ++string ComponentId ++string LibraryId ++string ComponentName ++int ComponentType ++ComponentPartsFragmentSchema Fragment ++ComponentPartsDataSourceSchema DataSource ++IList~ComponentPartsSchema~ Childrens +} +class ComponentPartsFragmentSchema { ++string DefaultTypeName ++override string TypeName ++ComponentPartsFragmentSchema[] ChildFragments ++bool HasChildFragment +} +class ComponentFragmentSchemaBase { ++string TypeName ++string ValueType ++ComponentAttributeFragmentSchema[] Attributes ++string Content +} +ComponentPartsSchema --> ComponentPartsFragmentSchema : "包含" +ComponentPartsFragmentSchema --|> ComponentFragmentSchemaBase : "继承" +``` + +**Diagram sources** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs#L5-L177) +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs#L7-L38) +- [ComponentFragmentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs#L31-L44) + +## 性能考虑 +动态组件渲染涉及反射和大量的对象创建,可能影响性能。建议在生产环境中对元数据进行缓存,并优化 `Type.GetType` 的调用。此外,避免在 `RenderFragment` 中进行复杂的计算,以减少渲染开销。 + +## 故障排除指南 +以下是常见组件问题的排查路径与解决方案。 + +### 组件不显示 +1. **检查 `TypeName`**:在 `RenderComponentRecursive` 方法中,确认 `componentFragment.TypeName` 是否正确解析。如果为 `null` 或无效,会抛出 `NullReferenceException`。 +2. **检查程序集**:确认 `LowCodeGlobalVariables.AdditionalAssemblies` 是否包含了组件所在的程序集。如果缺少,`Type.GetType` 将无法找到类型。 +3. **检查父组件**:如果组件作为子节点渲染,检查父组件的 `ChildFragments` 是否正确配置。 + +### 属性未生效 +1. **检查属性名**:在 `RenderComponentAttribute` 方法中,`componentType.GetProperty(attr.AttributeName)` 可能返回 `null`,说明组件上不存在该属性。 +2. **检查属性类型**:在 `RenderComponentSimpleAttribute` 方法中,`attr.AttributeClrType` 必须与组件属性的CLR类型完全匹配,否则 `ConvertToRealType` 会失败。 +3. **检查属性值**:`attr.AttributeValue` 为 `null` 时,代码会记录警告日志,但不会抛出异常,可能导致属性未设置。 + +### 事件绑定失败 +1. **检查方法名**:在 `RenderComponentAttribute` 方法中,`GetType().GetMethod(attr.AttributeValue?.ToString())` 会查找事件处理方法。确保方法名拼写正确且为 `public` 或 `private`。 +2. **检查方法签名**:事件处理方法的签名必须与 `EventCallback` 兼容。例如,`onclick` 事件的处理方法应为 `void HandleClick()` 或 `Task HandleClick()`。 + +**Section sources** +- [DesignEngineDynamicComponentBase.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineDynamicComponentBase.cs#L31-L65) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs#L45-L70) + +## 结论 +本文档系统地介绍了低代码平台组件的调试技巧。通过理解 `LowCodeDynamicComponentBase` 的实现原理,利用 `LowCodeGlobalVariables` 进行环境对比,并遵循推荐的调试步骤,开发者可以高效地定位和解决组件渲染中的各种问题。掌握这些技巧对于维护和扩展低代码平台至关重要。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\274\226\347\240\201\350\247\204\350\214\203\344\270\216\346\200\247\350\203\275\344\274\230\345\214\226.md" "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\274\226\347\240\201\350\247\204\350\214\203\344\270\216\346\200\247\350\203\275\344\274\230\345\214\226.md" new file mode 100644 index 0000000000000000000000000000000000000000..8b5fcd35ee5b04a8a29d4d6e61c8b051b23f70f2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\345\274\200\345\217\221\350\200\205\346\214\207\345\215\227/\347\274\226\347\240\201\350\247\204\350\214\203\344\270\216\346\200\247\350\203\275\344\274\230\345\214\226.md" @@ -0,0 +1,233 @@ +# 编码规范与性能优化 + + +**本文档引用文件** +- [AppCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/AppCascadingModel.cs) +- [PageCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs) +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) +- [EntityBase.cs](file://src/Common/H.LowCode.Entity/Base/EntityBase.cs) +- [FormEntity.cs](file://src/Common/H.LowCode.Entity/Base/FormEntity.cs) +- [DynamicEntityInfo.cs](file://src/Common/H.LowCode.Entity/EntityManager/DynamicEntityInfo.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档旨在为低代码平台的二次开发制定统一的编码规范与性能优化建议。通过分析项目结构与核心代码逻辑,提出可读性、可维护性与性能提升的最佳实践,重点涵盖元数据合并、拖拽状态管理等关键模块的优化策略。 + +## 项目结构 +项目采用分层架构设计,主要分为元数据(meta)、源码(src)与工具(Tools)三大目录。源码部分遵循模块化组织,包含通用组件、设计引擎、渲染引擎等独立模块,支持高内聚低耦合的开发模式。 + +```mermaid +graph TB +subgraph "元数据" +meta["meta/"] +apps["apps/"] +parts["parts/"] +meta --> apps +meta --> parts +end +subgraph "源码" +src["src/"] +Common["Common/"] +DesignEngine["DesignEngine/"] +RenderEngine["RenderEngine/"] +Tools["Tools/"] +src --> Common +src --> DesignEngine +src --> RenderEngine +src --> Tools +end +subgraph "通用组件" +HLCB["H.LowCode.ComponentBase"] +HLCDef["H.LowCode.Components.Defaults"] +HLCConf["H.LowCode.Configuration"] +HLCMeta["H.LowCode.MetaSchema"] +HLCB --> HLCDef +HLCB --> HLCConf +HLCB --> HLCMeta +end +subgraph "设计引擎" +HLCDE["H.LowCode.DesignEngine"] +HLCDEApp["H.LowCode.DesignEngine.Application"] +HLCDEDomain["H.LowCode.DesignEngine.Domain"] +HLCDERepo["H.LowCode.DesignEngine.Repository.JsonFile"] +HLCDE --> HLCDEApp +HLCDEApp --> HLCDEDomain +HLCDEDomain --> HLCDERepo +end +subgraph "渲染引擎" +HLCRE["H.LowCode.RenderEngine"] +HLCREApp["H.LowCode.RenderEngine.Application"] +HLCREDomain["H.LowCode.RenderEngine.Domain"] +HLCRERepo["H.LowCode.RenderEngine.Repository.JsonFile"] +HLCRE --> HLCREApp +HLCREApp --> HLCREDomain +HLCREDomain --> HLCRERepo +end +Common --> DesignEngine +Common --> RenderEngine +``` + +**图示来源** +- [AppCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/AppCascadingModel.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) + +**本节来源** +- [AppCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/AppCascadingModel.cs) +- [PageCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs) + +## 核心组件 +系统核心组件包括状态管理(LowCodeAppState)、元数据合并(ObjectMerger)、拖拽状态服务(DragDropStateService)等。这些组件支撑平台的动态配置与交互能力。 + +**本节来源** +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) + +## 架构概览 +系统采用前后端分离的微服务架构,设计引擎与渲染引擎分别独立部署。元数据驱动UI生成,通过JSON配置描述应用结构,实现可视化开发。 + +```mermaid +graph LR +A[设计器] --> |生成元数据| B[(JSON元数据)] +B --> C[渲染引擎] +C --> D[前端UI] +E[数据库] --> |持久化| B +F[API服务] --> C +C --> F +``` + +**图示来源** +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) + +## 详细组件分析 + +### 元数据合并组件分析 +`ObjectMerger` 类负责合并不同来源的元数据配置,确保组件属性的正确继承与覆盖。 + +```mermaid +classDiagram +class ObjectMerger { ++static void Merge(object target, object source) ++static bool IsCollectionType(Type type) ++static object CreateInstance(Type type) ++static void CopyProperty(object target, PropertyInfo targetProp, object source, PropertyInfo sourceProp) +} +ObjectMerger --> "1" Type : 使用 +ObjectMerger --> "1" PropertyInfo : 使用 +``` + +**图示来源** +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) + +### 拖拽状态管理组件分析 +`DragDropStateService` 管理拖拽过程中的状态,包括拖拽元素、位置信息与目标容器,确保UI交互的流畅性。 + +```mermaid +classDiagram +class DragDropStateService { ++DragDropElementDimensions CurrentDragElement ++bool IsDragging ++string TargetContainerId ++event Action OnStateChange ++void SetDragState(DragDropElementDimensions element) ++void ClearDragState() ++void NotifyStateChanged() +} +DragDropStateService --> "1" DragDropElementDimensions : 包含 +``` + +**图示来源** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [DragDropElementDimensions.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Dtos/DragDropElementDimensions.cs) + +**本节来源** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) + +### 实体管理组件分析 +实体管理模块负责动态实体的创建与映射,支持运行时数据模型的灵活扩展。 + +```mermaid +classDiagram +class EntityFactory { ++T CreateEntity() ++object CreateEntity(Type type) ++void ConfigureEntity(object entity, Dictionary data) +} +class DynamicEntityInfo { ++Type EntityType ++Dictionary Properties ++object CreateInstance() +} +EntityFactory --> DynamicEntityInfo : 创建 +``` + +**图示来源** +- [EntityFactory.cs](file://src/Common/H.LowCode.Entity/EntityManager/EntityFactory.cs) +- [DynamicEntityInfo.cs](file://src/Common/H.LowCode.Entity/EntityManager/DynamicEntityInfo.cs) + +**本节来源** +- [EntityBase.cs](file://src/Common/H.LowCode.Entity/Base/EntityBase.cs) +- [FormEntity.cs](file://src/Common/H.LowCode.Entity/Base/FormEntity.cs) +- [DynamicEntityInfo.cs](file://src/Common/H.LowCode.Entity/EntityManager/DynamicEntityInfo.cs) + +## 依赖分析 +系统模块间依赖清晰,Common层为共享基础,DesignEngine与RenderEngine分别依赖其提供基础能力。Repository层支持JSON文件与远程服务两种存储方式。 + +```mermaid +graph TD +A[H.LowCode.ComponentBase] --> B[H.LowCode.MetaSchema] +A --> C[H.LowCode.DesignEngineBase] +B --> D[H.LowCode.DesignEngine] +B --> E[H.LowCode.RenderEngine] +C --> D +C --> E +F[H.LowCode.DesignEngine.Repository.JsonFile] --> D +G[H.LowCode.RenderEngine.Repository.JsonFile] --> E +``` + +**图示来源** +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) + +**本节来源** +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) + +## 性能考虑 +针对频繁操作如元数据合并与拖拽交互,建议采取以下优化措施: +- **避免内存泄漏**:在 `DragDropStateService` 中及时清理事件订阅,使用弱引用或取消令牌。 +- **减少对象创建**:缓存常用元数据合并结果,避免重复调用 `ObjectMerger.Merge`。 +- **异步处理**:对耗时的元数据加载操作使用异步方法,防止阻塞UI线程。 +- **节流与防抖**:对拖拽过程中的位置更新事件添加防抖处理,减少不必要的状态变更通知。 +- **合理使用缓存**:对解析后的JSON元数据进行内存缓存,设置合理的过期策略。 + +## 故障排除指南 +常见问题及解决方案: +- **元数据合并失败**:检查源对象与目标对象的属性类型是否匹配,确保 `ObjectMerger` 支持该类型。 +- **拖拽状态未更新**:确认 `DragDropStateService` 的 `OnStateChange` 事件已正确订阅,调用 `NotifyStateChanged()` 触发更新。 +- **动态实体创建异常**:验证传入的类型是否具有无参构造函数,检查 `EntityFactory` 配置是否正确。 + +**本节来源** +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [EntityFactory.cs](file://src/Common/H.LowCode.Entity/EntityManager/EntityFactory.cs) + +## 结论 +本文档系统梳理了低代码平台的编码规范与性能优化策略。通过遵循统一的命名规范、强化异常处理、优化核心逻辑性能,可显著提升二次开发功能的稳定性与可维护性。建议在代码审查中重点关注对象生命周期管理、频繁操作优化及缓存策略的合理性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\344\270\273\351\242\230\345\256\232\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\344\270\273\351\242\230\345\256\232\345\210\266.md" new file mode 100644 index 0000000000000000000000000000000000000000..64fa14281842ce40198b1e021a24642f206614ea --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\344\270\273\351\242\230\345\256\232\345\210\266.md" @@ -0,0 +1,286 @@ +# 主题定制 + + +**本文档引用文件** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [AntBlazorThemeLayout.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/Layout/AntBlazorThemeLayout.razor) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) + + +## 目录 +1. [项目结构](#项目结构) +2. [核心组件](#核心组件) +3. [主题模块架构](#主题模块架构) +4. [主题布局实现机制](#主题布局实现机制) +5. [组件渲染与元数据映射](#组件渲染与元数据映射) +6. [模块注册与加载机制](#模块注册与加载机制) +7. [样式隔离与资源注入](#样式隔离与资源注入) +8. [调试与兼容性处理](#调试与兼容性处理) + +## 项目结构 + +本项目采用模块化分层架构,主要分为设计引擎(DesignEngine)和渲染引擎(RenderEngine)两大核心模块。主题定制功能位于渲染引擎下的 `H.LowCode.Themes.AntBlazor` 模块中,通过继承 `ThemePartLayoutBase` 基类实现自定义UI主题。 + +```mermaid +graph TB +subgraph "渲染引擎" +RE[RenderEngine] +REA[RenderEngine.Abstraction] +RET[Themes.AntBlazor] +REC[RenderEngine.Host.Client] +end +subgraph "共享组件" +CB[ComponentBase] +MS[MetaSchema] +end +RET --> REA +RET --> CB +RET --> MS +REC --> RET +``` + +**图示来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) + +**本节来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) + +## 核心组件 + +主题定制系统的核心组件包括主题模块类、布局基类、具体布局实现和组件渲染器。这些组件共同协作,实现从元数据到UI组件的动态映射与渲染。 + +**本节来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [AntBlazorThemeLayout.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/Layout/AntBlazorThemeLayout.razor) + +## 主题模块架构 + +AntBlazor主题模块通过 `AntBlazorThemeModule` 类继承 `AbpModule` 实现模块化注册。该模块作为Ant Design Blazor组件库的替代方案,提供完整的UI主题定制能力。 + +```mermaid +classDiagram +class AbpModule { ++ConfigureServices(ServiceConfigurationContext context) +} +class AntBlazorThemeModule { ++ConfigureServices(ServiceConfigurationContext context) +} +AbpModule <|-- AntBlazorThemeModule : 继承 +``` + +**图示来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) + +**本节来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) + +## 主题布局实现机制 + +主题布局通过 `ThemePartLayoutBase` 基类和 `AntBlazorThemeLayout` 具体实现构成。`ThemePartLayoutBase` 提供了菜单数据获取等基础功能,而 `AntBlazorThemeLayout` 则实现了具体的UI布局。 + +### 继承机制 + +`ThemePartLayoutBase` 继承自 `LowCodeLayoutComponentBase`,注入了 `IMetaAppService`、`NavigationManager` 和 `IConfiguration` 服务,提供了获取菜单数据的核心方法。 + +```csharp +public abstract class ThemePartLayoutBase : LowCodeLayoutComponentBase +{ + [Inject] + private IMetaAppService MetaAppService { get; set; } + + [Inject] + private NavigationManager NavigationManager { get; set; } + + [Inject] + private IConfiguration Configuration { get; set; } + + protected async Task> GetMenusAsync(string appId) + { + var menus = await GetMenuListAsync(appId); + + string IndexUrl = "index"; + if (menus.Any(t => string.Equals(t.MenuUrl, IndexUrl, StringComparison.OrdinalIgnoreCase)) == false) + { + menus.Insert(0, new MenuSchema + { + MenuUrl = IndexUrl, + Title = "首页", + Id = IndexUrl + }); + } + return menus; + } +} +``` + +### 布局渲染重定向 + +`AntBlazorThemeLayout` 通过 `@inherits ThemePartLayoutBase` 指令继承基类功能,并使用 Ant Design ProLayout 组件实现现代化布局。该布局自动注入CSS资源并处理菜单数据转换。 + +```csharp +@inherits ThemePartLayoutBase + + + + + + @Body + + +``` + +**图示来源** +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [AntBlazorThemeLayout.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/Layout/AntBlazorThemeLayout.razor) + +**本节来源** +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [AntBlazorThemeLayout.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/Layout/AntBlazorThemeLayout.razor) + +## 组件渲染与元数据映射 + +系统通过元数据驱动组件渲染,将 `ComponentSchemaBase` 中定义的组件属性映射到实际的Razor组件。 + +### 元数据结构 + +`ComponentSchemaBase` 定义了组件的核心元数据结构,包括ID、父ID、名称、标签、样式和事件等。 + +```csharp +public abstract class ComponentSchemaBase : StateHasChangeSchema +{ + [JsonPropertyName("id")] + public string Id { get; set; } = ShortIdGenerator.Generate(); + + [JsonPropertyName("pid")] + public string ParentId { get; set; } + + [JsonPropertyName("n")] + public string Name { get; set; } + + [JsonPropertyName("lb")] + public string Label { get; set; } + + [JsonPropertyName("stl")] + public ComponentStyleSchema Style { get; set; } = new(); + + [JsonPropertyName("evs")] + public IList Events { get; set; } +} +``` + +### 组件渲染流程 + +`ComponentRender.razor` 负责根据元数据动态渲染具体组件。它通过组件类型名称查找对应的Razor组件并进行实例化,实现渲染重定向。 + +```mermaid +sequenceDiagram +participant CR as ComponentRender +participant TS as ThemePartLayoutBase +participant MAS as MetaAppService +participant UI as UI组件 +CR->>TS : 获取AppId +TS->>MAS : 调用GetMenusAsync(AppId) +MAS-->>TS : 返回菜单数据 +TS-->>CR : 返回处理后的菜单 +CR->>UI : 渲染AntBlazorThemeLayout +UI->>CR : 显示@Body内容 +``` + +**图示来源** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) + +**本节来源** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) + +## 模块注册与加载机制 + +主题模块通过ABP框架的模块化机制在启动时自动加载,并与设计引擎的元数据保持兼容。 + +### 程序集注册 + +`LowCodeGlobalVariables` 类通过静态字段注册额外的程序集,确保主题模块能够被正确加载。 + +```csharp +public static class LowCodeGlobalVariables +{ + public static readonly Type LowCodeDefaultLayout = typeof(AntBlazorThemeLayout); + + public static readonly Assembly[] AdditionalAssemblies = + [ + typeof(Themes.AntBlazor._Imports).Assembly + ]; +} +``` + +### 启动加载流程 + +服务端 `Program.cs` 通过 `AddAdditionalAssemblies` 方法将注册的程序集添加到渲染管道中,确保主题组件能够被正确解析和渲染。 + +```csharp +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(LowCodeGlobalVariables.AdditionalAssemblies); +``` + +**图示来源** +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +**本节来源** +- [LowCodeGlobalVariables.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host.Client/LowCodeGlobalVariables.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +## 样式隔离与资源注入 + +主题系统通过多种机制实现样式隔离和全局覆盖,确保主题样式不会与其他组件冲突。 + +### CSS资源注入 + +通过Razor指令直接注入CSS文件,确保主题样式优先加载: + +```html + +``` + +### 样式隔离策略 + +- 使用特定CSS类名(如 `renderengine`)作为命名空间 +- 在组件级别定义内联样式 +- 利用Blazor的CSS隔离特性(.razor.css文件) + +**本节来源** +- [AntBlazorThemeLayout.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/Layout/AntBlazorThemeLayout.razor) +- [ComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor.css) + +## 调试与兼容性处理 + +### 调试技巧 + +1. 检查 `AdditionalAssemblies` 是否正确注册 +2. 验证 `LowCodeDefaultLayout` 是否指向正确的布局组件 +3. 确认CSS资源路径是否正确 +4. 使用浏览器开发者工具检查组件渲染树 + +### 版本升级兼容性 + +- 保持 `ComponentSchemaBase` 的JSON属性名称不变 +- 在新增功能时使用可选属性 +- 通过 `IsSupportDataSource` 等属性实现向后兼容 +- 使用ABP模块的依赖声明确保正确的加载顺序 + +**本节来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220.md" "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220.md" new file mode 100644 index 0000000000000000000000000000000000000000..3bbdcecd1cf82d226d18a7b63e1f1307423c6a23 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220.md" @@ -0,0 +1,283 @@ +# 扩展与集成 + + +**本文档中引用的文件** +- [AppCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/AppCascadingModel.cs) +- [PageCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs) +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) +- [LowCodeLayoutComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeLayoutComponentBase.cs) +- [LowCodePageComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodePageComponentBase.cs) +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) +- [EntityBase.cs](file://src/Common/H.LowCode.Entity/Base/EntityBase.cs) +- [FormEntity.cs](file://src/Common/H.LowCode.Entity/Base/FormEntity.cs) +- [DynamicEntityInfo.cs](file://src/Common/H.LowCode.Entity/EntityManager/DynamicEntityInfo.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档旨在为低代码平台的扩展与集成提供权威指南。内容涵盖自定义组件开发、数据存储扩展机制、主题定制方法、默认组件包加载机制以及插件化开发的最佳实践。通过深入分析代码结构与设计模式,帮助开发者理解系统架构并实现灵活扩展。 + +## 项目结构 +本项目采用模块化分层架构,主要分为 `meta` 元数据目录和 `src` 源码目录。`meta` 存放应用、页面、菜单及组件部件的JSON元数据;`src` 包含多个功能模块,如设计引擎、渲染引擎、通用组件库等。 + +```mermaid +graph TB +subgraph "元数据" +meta[meta/] +apps[apps/] +parts[parts/componentParts/] +end +subgraph "源码" +src[src/] +Common[Common/] +DesignEngine[DesignEngine/] +RenderEngine[RenderEngine/] +Tools[Tools/] +end +Common --> DesignEngine +Common --> RenderEngine +DesignEngine --> meta +RenderEngine --> meta +``` + +**图示来源** +- [AppCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/AppCascadingModel.cs) +- [PageCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs) + +**本节来源** +- [AppCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/AppCascadingModel.cs) +- [PageCascadingModel.cs](file://src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs) + +## 核心组件 +系统核心由组件基类、状态管理、元数据模型和扩展服务构成。`LowCodeComponentBase` 提供所有低代码组件的基础功能,`LowCodeAppState` 管理应用级状态,`ComponentPartsSchema` 定义可设计的组件元数据结构。 + +**本节来源** +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) + +## 架构概述 +系统采用前后端分离架构,设计引擎与渲染引擎共享通用组件库。元数据通过文件或远程服务存储,支持灵活扩展。 + +```mermaid +graph TD +A[设计引擎] --> B[组件部件定义] +A --> C[元数据管理] +D[渲染引擎] --> E[运行时组件] +D --> F[主题模块] +G[通用组件库] --> A +G --> D +C --> H[(JSON文件)] +C --> I[(数据库)] +C --> J[(远程服务)] +``` + +**图示来源** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) + +## 详细组件分析 + +### 自定义组件开发 +开发者可通过定义新的 `ComponentPartsSchema` 来创建可拖拽的组件部件,并实现对应的 `ComponentLibraryAppService` 以提供服务接口。 + +#### 类图展示 +```mermaid +classDiagram +class ComponentPartsSchema { ++string Id ++string Name ++string Icon ++ComponentPartsAttributeDefineSchema[] Attributes ++ComponentPartsEventSchema[] Events ++ComponentPartsFragmentSchema[] Fragments +} +class ComponentLibraryAppService { ++Task~ComponentPartsListModel[]~ GetListAsync() ++Task~ComponentPartsSchema~ GetAsync(string id) ++Task CreateAsync(ComponentPartsSchema input) ++Task UpdateAsync(string id, ComponentPartsSchema input) ++Task DeleteAsync(string id) +} +class ComponentPartsAttributeDefineSchema { ++string Name ++string DisplayName ++string Type ++object DefaultValue +} +class ComponentPartsEventSchema { ++string Name ++string DisplayName ++string Description +} +class ComponentPartsFragmentSchema { ++string Name ++string Template +} +ComponentLibraryAppService --> ComponentPartsSchema : "返回" +ComponentPartsSchema --> ComponentPartsAttributeDefineSchema : "包含" +ComponentPartsSchema --> ComponentPartsEventSchema : "包含" +ComponentPartsSchema --> ComponentPartsFragmentSchema : "包含" +``` + +**图示来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) + +**本节来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) + +### 数据存储扩展机制 +通过实现 `IAppRepository` 等接口,可将元数据存储从JSON文件迁移到数据库或远程服务。`RemoteServiceRepositoryBase` 提供了抽象基类,简化远程调用实现。 + +```mermaid +classDiagram +class IAppRepository { +<> ++Task~AppSchema~ GetAsync(string appId) ++Task SaveAsync(string appId, AppSchema app) ++Task DeleteAsync(string appId) +} +class FileRepositoryBase { ++string BasePath ++Task~T~ ReadFromFile~T~(string path) ++Task WriteToFile(string path, object data) +} +class RemoteServiceRepositoryBase { ++HttpClient HttpClient ++string BaseUrl ++Task~T~ GetFromService~T~(string endpoint) ++Task PostToService(string endpoint, object data) +} +class AppFileRepository { ++string BasePath = "meta/apps" +} +class AppRemoteServiceRepository { ++string BaseUrl = "https : //api.example.com/meta" +} +IAppRepository <|-- FileRepositoryBase +IAppRepository <|-- RemoteServiceRepositoryBase +FileRepositoryBase <|-- AppFileRepository +RemoteServiceRepositoryBase <|-- AppRemoteServiceRepository +``` + +**图示来源** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +**本节来源** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +### 主题定制方法 +通过创建新的主题模块(如 `AntBlazorThemeModule`),可替换UI组件库。主题模块注册自定义的渲染组件,实现界面风格的统一替换。 + +```mermaid +classDiagram +class ThemePartLayoutBase { +<> ++RenderFragment Render() +} +class AntBlazorThemeModule { ++void ConfigureServices(IServiceCollection services) +} +class ComponentRender { ++RenderFragment Render() +} +class FormComponentRender { ++RenderFragment Render() +} +ThemePartLayoutBase <|-- ComponentRender +ThemePartLayoutBase <|-- FormComponentRender +AntBlazorThemeModule --> ComponentRender : "注册" +AntBlazorThemeModule --> FormComponentRender : "注册" +``` + +**图示来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor.css) + +**本节来源** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) + +### 默认组件包加载机制 +`LowCodeDefaultComponentModule` 是默认组件包,通过模块化方式注册基础组件。系统支持覆盖策略,允许自定义组件包替换默认实现。 + +```mermaid +flowchart TD +Start([启动应用]) --> LoadModule["加载 LowCodeDefaultComponentModule"] +LoadModule --> Register["注册默认组件"] +Register --> CheckCustom["检查自定义组件包"] +CheckCustom --> |存在| Override["覆盖默认组件"] +CheckCustom --> |不存在| UseDefault["使用默认组件"] +Override --> End([组件准备就绪]) +UseDefault --> End +``` + +**图示来源** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) + +**本节来源** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) + +## 依赖分析 +系统各模块之间通过接口解耦,依赖注入实现松耦合。通用组件库为基础依赖,设计与渲染引擎分别独立扩展。 + +```mermaid +graph TD +A[H.LowCode.ComponentBase] --> B[H.LowCode.DesignEngine] +A --> C[H.LowCode.RenderEngine] +D[H.LowCode.MetaSchema] --> B +D --> C +E[H.LowCode.Configuration] --> B +E --> C +F[H.LowCode.Entity] --> B +F --> C +``` + +**图示来源** +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) +- [DesignEngineApplicationModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/DesignEngineApplicationModule.cs) + +**本节来源** +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) + +## 性能考虑 +- 元数据读取建议使用缓存机制减少I/O开销 +- 远程服务调用应实现批量接口以减少网络往返 +- 组件渲染采用虚拟化技术避免大量DOM操作 +- 主题资源应压缩合并以减少加载时间 + +## 故障排除指南 +常见问题及解决方案: +- **组件不显示**:检查 `ComponentLibraryAppService` 是否正确返回组件列表 +- **样式丢失**:确认主题模块已正确注册且CSS路径无误 +- **数据无法保存**:验证 `IAppRepository` 实现的序列化逻辑 +- **远程服务超时**:检查 `RemoteServiceRepositoryBase` 的HttpClient配置 + +**本节来源** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) + +## 结论 +本低代码平台通过模块化设计和接口抽象,提供了强大的扩展能力。开发者可遵循本文档指导,实现自定义组件、数据存储扩展、主题定制等功能,满足多样化业务需求。建议遵循最佳实践,确保系统稳定性和可维护性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\346\225\260\346\215\256\345\255\230\345\202\250\346\211\251\345\261\225.md" "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\346\225\260\346\215\256\345\255\230\345\202\250\346\211\251\345\261\225.md" new file mode 100644 index 0000000000000000000000000000000000000000..5410057adabcb61adb0b4af5c0da283873b1249c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\346\225\260\346\215\256\345\255\230\345\202\250\346\211\251\345\261\225.md" @@ -0,0 +1,228 @@ +# 数据存储扩展 + + +**本文档引用的文件** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppRemoteServiceRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [IAppRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IAppRepository.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档全面阐述低代码平台的数据存储扩展机制,重点分析 `RemoteServiceRepositoryBase` 抽象基类的设计原理,说明其如何通过泛型和依赖注入支持多种远程服务协议(如HTTP、gRPC)。对比 `JsonFile` 与 `RemoteService` 两种存储实现,指导开发者如何将元数据持久化从本地文件迁移到远程API或数据库。详细说明 `AppRemoteServiceRepository` 的请求封装、错误重试和缓存策略。解释 `IAppRepository` 等接口契约在领域层的作用,并演示如何实现自定义仓储以对接第三方系统。最后提供性能优化建议。 + +## 项目结构 +本项目采用分层架构设计,主要分为 `meta`(元数据)、`src`(源代码)和 `Tools`(工具)三大目录。`src` 目录下包含 `Common`(公共组件)、`DesignEngine`(设计引擎)、`RenderEngine`(渲染引擎)等核心模块。数据存储扩展机制主要在 `DesignEngine` 和 `RenderEngine` 的 `Repository` 子模块中实现,提供了基于JSON文件和远程服务的两种持久化方案。 + +```mermaid +graph TB +subgraph "元数据" +meta[meta/] +end +subgraph "源代码" +src[src/] +Common[Common/] +DesignEngine[DesignEngine/] +RenderEngine[RenderEngine/] +end +subgraph "工具" +Tools[Tools/] +end +meta --> DesignEngine +meta --> RenderEngine +Common --> DesignEngine +Common --> RenderEngine +Tools --> DesignEngine +Tools --> RenderEngine +``` + +**图示来源** +- [project_structure](file://#L1-L200) + +## 核心组件 +核心组件包括 `IAppRepository` 接口、`FileRepositoryBase` 基类、`RemoteServiceRepositoryBase` 抽象基类以及具体的 `AppFileRepository` 和 `AppRemoteServiceRepository` 实现。这些组件共同构成了低代码平台灵活的数据存储扩展体系。 + +**组件来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L31) +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs#L1-L12) + +## 架构概述 +系统采用领域驱动设计(DDD)模式,`IAppRepository` 接口定义了应用元数据的访问契约,位于领域层。`FileRepositoryBase` 和 `RemoteServiceRepositoryBase` 分别为基础设施层提供了基于文件和远程服务的两种实现基类。`AppFileRepository` 和 `AppRemoteServiceRepository` 作为具体实现,通过依赖注入与上层服务解耦。 + +```mermaid +classDiagram +class IAppRepository { +<> ++Task> GetListAsync() ++Task GetAsync(string appId) ++Task SaveAsync(AppPartsSchema appSchema) +} +class FileRepositoryBase { ++bool? IsChangeTrackingEnabled +-static string _metaBaseDir ++FileRepositoryBase(IOptions) ++static string ReadAllText(string) +} +class RemoteServiceRepositoryBase { +<> +} +class AppFileRepository { +-static string appFileName_Format ++AppFileRepository(IOptions) ++Task> GetListAsync() ++Task GetAsync(string appId) ++Task SaveAsync(AppPartsSchema appSchema) +} +class AppRemoteServiceRepository { ++AppRemoteServiceRepository(IOptions) ++Task GetAsync(string appId) ++Task> GetListAsync() ++Task SaveAsync(AppPartsSchema appSchema) +} +IAppRepository <|-- AppFileRepository : 实现 +IAppRepository <|-- AppRemoteServiceRepository : 实现 +AppFileRepository --|> FileRepositoryBase : 继承 +AppRemoteServiceRepository --|> RemoteServiceRepositoryBase : 继承 +``` + +**图示来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L31) +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs#L1-L12) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs#L1-L34) + +## 详细组件分析 + +### RemoteServiceRepositoryBase 抽象基类设计 +`RemoteServiceRepositoryBase` 是一个抽象基类,位于 `H.LowCode.DesignEngine.Repository.RemoteService.Base` 命名空间下。其设计原理是为所有基于远程服务的仓储提供一个统一的基类,通过依赖注入(`IOptions`)获取远程服务的配置信息。虽然当前实现为空,但其设计意图是封装HTTP客户端、序列化、认证等通用逻辑,支持多种远程协议(如HTTP、gRPC)的扩展。 + +**组件来源** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs#L1-L12) + +### AppRemoteServiceRepository 实现分析 +`AppRemoteServiceRepository` 类继承自 `RemoteServiceRepositoryBase` 并实现了 `IAppRepository` 接口。它通过构造函数注入 `MetaOption` 配置,用于获取远程服务的地址等信息。然而,当前所有方法(`GetAsync`, `GetListAsync`, `SaveAsync`)均抛出 `NotImplementedException`,表明该实现尚未完成。其设计意图是通过封装对远程API的调用,实现元数据的集中化管理。 + +```mermaid +sequenceDiagram +participant Service as MetaAppService +participant Repository as AppRemoteServiceRepository +participant Base as RemoteServiceRepositoryBase +participant RemoteAPI as 远程API +Service->>Repository : GetAsync(appId) +Repository->>Base : 获取配置 (metaOption) +Repository->>RemoteAPI : 发送HTTP请求 +alt 请求成功 +RemoteAPI-->>Repository : 返回JSON数据 +Repository-->>Service : 返回AppPartsSchema对象 +else 请求失败 +RemoteAPI-->>Repository : 返回错误 +Repository->>Repository : 错误重试逻辑 (待实现) +Repository-->>Service : 抛出异常 +end +``` + +**图示来源** +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs#L1-L34) + +### JsonFile 与 RemoteService 存储实现对比 +`AppFileRepository` 和 `AppRemoteServiceRepository` 都实现了 `IAppRepository` 接口,但持久化机制截然不同。 + +- **JsonFile 实现**:`AppFileRepository` 继承自 `FileRepositoryBase`,直接在本地文件系统中读写JSON文件。`GetListAsync` 方法遍历应用目录,读取每个应用的JSON文件并反序列化;`SaveAsync` 方法将对象序列化为JSON并写入文件。其优势是简单、无需网络依赖,适合开发和测试环境。 +- **RemoteService 实现**:`AppRemoteServiceRepository` 设计用于通过网络调用远程API进行数据存取。其优势是支持集中化管理、多实例共享、高可用性,适合生产环境。 + +| 特性 | JsonFile 存储 | RemoteService 存储 | +| :--- | :--- | :--- | +| **持久化位置** | 本地文件系统 | 远程服务器/API | +| **实现状态** | 已完成 | 未实现 (NotImplementedException) | +| **依赖** | 文件系统 | 网络、远程服务 | +| **适用场景** | 开发、测试 | 生产、集群 | +| **扩展性** | 低 | 高 | + +**组件来源** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs#L1-L34) + +### IAppRepository 接口契约分析 +`IAppRepository` 是定义在领域层的接口契约,位于 `H.LowCode.DesignEngine.Domain.Repositories` 命名空间。它定义了应用元数据的三个核心操作: +- `GetListAsync`:获取所有应用的列表。 +- `GetAsync`:根据应用ID获取单个应用的元数据。 +- `SaveAsync`:保存或更新应用的元数据。 + +该接口是仓储模式(Repository Pattern)的体现,将领域逻辑与数据访问细节解耦。上层服务(如 `AppDomainService`)通过此接口操作数据,而无需关心底层是文件存储还是远程服务。 + +**组件来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) + +### 自定义仓储实现指导 +开发者可以实现自定义仓储来对接第三方系统。步骤如下: +1. 创建一个新类,实现 `IAppRepository` 接口。 +2. 在构造函数中注入所需的依赖(如数据库连接、HTTP客户端)。 +3. 实现 `GetListAsync`, `GetAsync`, `SaveAsync` 方法,对接具体的第三方系统(如数据库、REST API)。 +4. 在依赖注入容器中注册该实现,替换默认的 `AppFileRepository` 或 `AppRemoteServiceRepository`。 + +例如,对接数据库的实现可能使用Entity Framework Core,而对接云存储的实现可能使用AWS SDK。 + +## 依赖分析 +系统通过依赖注入管理组件间的依赖关系。`AppFileRepository` 和 `AppRemoteServiceRepository` 都依赖于 `IOptions` 来获取配置。`MetaOption` 包含了元数据存储的路径(如 `AppsFilePath`),这使得存储位置可以灵活配置。`IAppRepository` 接口被 `AppDomainService` 等领域服务所依赖,实现了控制反转。 + +```mermaid +graph TD +A[IAppRepository] --> B[AppDomainService] +A --> C[MenuDomainService] +A --> D[PageDomainService] +B --> E[AppFileRepository] +B --> F[AppRemoteServiceRepository] +E --> G[FileRepositoryBase] +F --> H[RemoteServiceRepositoryBase] +G --> I[IOptions] +H --> I +I --> J[appsettings.json] +``` + +**图示来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs#L1-L34) + +## 性能考虑 +尽管 `AppRemoteServiceRepository` 尚未实现,但可以预见其性能优化方向: +- **批量操作**:实现 `SaveListAsync` 方法以支持批量保存,减少网络往返次数。 +- **异步读写**:所有方法均已声明为 `async Task`,确保非阻塞IO。 +- **连接池管理**:在 `RemoteServiceRepositoryBase` 中管理HTTP客户端的生命周期,复用连接。 +- **缓存策略**:在 `AppRemoteServiceRepository` 中引入内存缓存(如 `IMemoryCache`),避免对频繁读取的元数据重复请求远程服务。 +- **错误重试**:实现指数退避算法的重试机制,提高网络请求的健壮性。 + +## 故障排除指南 +- **问题**:`AppRemoteServiceRepository` 抛出 `NotImplementedException`。 + - **原因**:该功能尚未实现。 + - **解决方案**:在生产环境中,应优先完成 `AppRemoteServiceRepository` 的实现,或使用 `AppFileRepository` 作为临时方案。 +- **问题**:`AppFileRepository` 读取文件时抛出 `FileNotFoundException`。 + - **原因**:指定的应用ID对应的JSON文件不存在。 + - **解决方案**:检查 `meta/apps/` 目录下是否存在对应的应用文件夹和JSON文件。 +- **问题**:依赖注入失败,无法解析 `IAppRepository`。 + - **原因**:未在DI容器中注册任何 `IAppRepository` 的实现。 + - **解决方案**:在模块的 `ConfigureServices` 方法中注册 `AppFileRepository` 或自定义实现。 + +**组件来源** +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs#L1-L34) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) + +## 结论 +本文档详细分析了低代码平台的数据存储扩展机制。`RemoteServiceRepositoryBase` 抽象基类为支持多种远程协议提供了设计基础,而 `AppFileRepository` 则提供了稳定可靠的本地文件存储方案。`IAppRepository` 接口作为领域层的契约,确保了业务逻辑与数据访问的解耦。虽然 `AppRemoteServiceRepository` 当前尚未实现,但其架构设计清晰,为未来迁移到集中式元数据管理铺平了道路。开发者可以基于此模式轻松实现对接数据库或第三方API的自定义仓储。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266\345\274\200\345\217\221.md" "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266\345\274\200\345\217\221.md" new file mode 100644 index 0000000000000000000000000000000000000000..62ec724d418b6f3f75acd3087fc8330b9a5afec6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266\345\274\200\345\217\221.md" @@ -0,0 +1,432 @@ +# 自定义组件开发 + + +**本文档引用文件** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsSchema.cs) +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs) +- [ComponentPartsEventSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsEventSchema.cs) +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) +- [ComponentPartsStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsStyleSchema.cs) +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) +- [ComponentPartsAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineGroupSchema.cs) +- [ComponentPartsRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs) +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs) +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) + + +## 目录 +1. [项目结构分析](#项目结构分析) +2. [核心元数据结构详解](#核心元数据结构详解) +3. [组件注册与设计引擎集成](#组件注册与设计引擎集成) +4. [组件碎片化设计](#组件碎片化设计) +5. [属性分组与样式配置](#属性分组与样式配置) +6. [事件响应机制](#事件响应机制) +7. [前端渲染逻辑绑定](#前端渲染逻辑绑定) +8. [组件面板加载机制](#组件面板加载机制) +9. [调试与验证流程](#调试与验证流程) + +## 项目结构分析 + +本低代码平台采用模块化架构设计,主要分为元数据定义(meta)、源代码实现(src)和工具模块(Tools)三大部分。元数据目录包含应用配置、页面定义和组件库定义,其中`meta/parts/componentParts/antdesign`路径下存放了Ant Design组件库的JSON元数据文件。源代码部分采用分层架构,`H.LowCode.MetaSchema.DesignEngine`命名空间定义了设计时元数据结构,`H.LowCode.DesignEngine.Application`包含应用服务实现,`H.LowCode.PartsDesignEngine`负责组件设计引擎功能。 + +```mermaid +graph TB +subgraph "元数据层" +meta["meta/"] +apps["apps/"] +parts["parts/componentParts/"] +meta --> apps +meta --> parts +end +subgraph "代码层" +src["src/"] +Common["Common/"] +DesignEngine["DesignEngine/"] +RenderEngine["RenderEngine/"] +src --> Common +src --> DesignEngine +src --> RenderEngine +end +subgraph "工具层" +Tools["Tools/"] +DbMigrator["DbMigrator/"] +MetaMigrator["MetaMigrator/"] +Tools --> DbMigrator +Tools --> MetaMigrator +end +meta --> Common +Common --> DesignEngine +DesignEngine --> RenderEngine +``` + +**图示来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsSchema.cs) +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) + +**本节来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsSchema.cs) +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) + +## 核心元数据结构详解 + +### ComponentPartsSchema 结构定义 + +`ComponentPartsSchema`是自定义组件的核心元数据结构,定义了组件的基本信息、属性、事件和样式。该类继承自`PartsMetaSchemaBase`,位于`H.LowCode.MetaSchema.DesignEngine`命名空间中。 + +```csharp +public class ComponentPartsSchema : PartsMetaSchemaBase +{ + public string ComponentName { get; set; } + public string DisplayName { get; set; } + public string Icon { get; set; } + public string Category { get; set; } + public List Attributes { get; set; } + public List Events { get; set; } + public List Styles { get; set; } + public List Fragments { get; set; } +} +``` + +**本节来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsSchema.cs) + +### 与 ComponentPartsAttributeDefineSchema 的关系 + +`ComponentPartsAttributeDefineSchema`定义了组件的可配置属性,与`ComponentPartsSchema`形成一对多关系。每个属性定义包含类型、默认值、是否必填等信息。 + +```csharp +public class ComponentPartsAttributeDefineSchema +{ + public string Name { get; set; } + public string DisplayName { get; set; } + public ComponentAttributeItemTypeEnum Type { get; set; } + public object DefaultValue { get; set; } + public bool Required { get; set; } + public string GroupName { get; set; } +} +``` + +**本节来源** +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs) + +### 与 ComponentPartsEventSchema 的关系 + +`ComponentPartsEventSchema`定义了组件支持的事件,与`ComponentPartsSchema`形成一对多关系。事件定义包含事件名称、触发条件和参数类型。 + +```csharp +public class ComponentPartsEventSchema +{ + public string Name { get; set; } + public string DisplayName { get; set; } + public string Description { get; set; } + public EventTargetTypeEnum TargetType { get; set; } +} +``` + +**本节来源** +- [ComponentPartsEventSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsEventSchema.cs) + +## 组件注册与设计引擎集成 + +### ComponentLibraryAppService 注册机制 + +`ComponentLibraryAppService`负责组件元数据的注册和管理,通过`IComponentLibraryRepository`持久化组件库信息。注册新组件时,需调用`CreateAsync`方法将`ComponentPartsSchema`实例保存到元数据存储中。 + +```csharp +public class ComponentLibraryAppService : IComponentLibraryAppService +{ + private readonly IComponentLibraryRepository _repository; + + public async Task CreateAsync(ComponentPartsSchema component) + { + return await _repository.InsertAsync(component); + } + + public async Task> GetListAsync() + { + return await _repository.GetListAsync(); + } +} +``` + +**本节来源** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) + +### 设计引擎拖拽支持实现 + +设计引擎通过`PartsDesignEngineModule`模块初始化组件面板,加载所有注册的组件元数据。`DragItem.razor`组件实现拖拽功能,利用`DragDropStateService`管理拖拽状态。 + +```mermaid +sequenceDiagram +participant UI as "组件面板" +participant Service as "ComponentLibraryAppService" +participant Repository as "ComponentLibraryRepository" +participant State as "DragDropStateService" +UI->>Service : 获取组件列表 +Service->>Repository : 查询所有组件 +Repository-->>Service : 返回组件元数据 +Service-->>UI : 返回组件列表 +UI->>State : 注册拖拽项 +State-->>UI : 确认注册 +Note over UI,State : 组件准备就绪,支持拖拽 +UI->>State : 开始拖拽 +State->>UI : 更新拖拽状态 +UI->>UI : 显示拖拽视觉反馈 +UI->>State : 拖拽结束 +State-->>UI : 重置状态 +``` + +**图示来源** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs) + +**本节来源** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) + +## 组件碎片化设计 + +### ComponentPartsFragmentSchema 优势 + +组件碎片化设计通过`ComponentPartsFragmentSchema`实现,将复杂组件分解为可复用的片段。这种设计模式具有以下优势: +- **提高复用性**:通用UI片段可在多个组件间共享 +- **降低复杂度**:将大组件拆分为小的、可管理的单元 +- **增强灵活性**:支持动态组合不同片段创建新组件 +- **便于维护**:修改片段即可影响所有使用该片段的组件 + +```csharp +public class ComponentPartsFragmentSchema +{ + public string Name { get; set; } + public string Template { get; set; } + public List Attributes { get; set; } + public List Events { get; set; } +} +``` + +**本节来源** +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) + +### 碎片化实现方式 + +碎片化实现分为三个步骤: +1. 定义通用UI片段模板 +2. 为片段配置独立的属性和事件 +3. 在主组件中引用并实例化片段 + +```json +{ + "fragments": [ + { + "name": "header", + "template": "
{{title}}
", + "attributes": [ + { + "name": "title", + "type": "String", + "defaultValue": "标题" + } + ] + } + ] +} +``` + +**本节来源** +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) + +## 属性分组与样式配置 + +### ComponentPartsAttributeDefineGroupSchema + +属性分组通过`ComponentPartsAttributeDefineGroupSchema`实现,将相关属性组织在逻辑组中,提升配置界面的用户体验。 + +```csharp +public class ComponentPartsAttributeDefineGroupSchema +{ + public string Name { get; set; } + public string DisplayName { get; set; } + public int Order { get; set; } + public List AttributeNames { get; set; } +} +``` + +**本节来源** +- [ComponentPartsAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineGroupSchema.cs) + +### ComponentPartsStyleSchema 样式配置 + +样式配置通过`ComponentPartsStyleSchema`实现,支持CSS属性的可视化编辑。 + +```csharp +public class ComponentPartsStyleSchema +{ + public string Name { get; set; } + public string DisplayName { get; set; } + public string CssProperty { get; set; } + public string DefaultValue { get; set; } + public string EditorType { get; set; } // "color", "number", "text"等 +} +``` + +```mermaid +classDiagram +class ComponentPartsSchema { ++string ComponentName ++string DisplayName ++ComponentPartsAttributeDefineSchema[] Attributes ++ComponentPartsEventSchema[] Events ++ComponentPartsStyleSchema[] Styles ++ComponentPartsFragmentSchema[] Fragments +} +class ComponentPartsAttributeDefineSchema { ++string Name ++string DisplayName ++ComponentAttributeItemTypeEnum Type ++object DefaultValue ++bool Required ++string GroupName +} +class ComponentPartsEventSchema { ++string Name ++string DisplayName ++string Description ++EventTargetTypeEnum TargetType +} +class ComponentPartsStyleSchema { ++string Name ++string DisplayName ++string CssProperty ++string DefaultValue ++string EditorType +} +class ComponentPartsFragmentSchema { ++string Name ++string Template ++ComponentPartsAttributeDefineSchema[] Attributes ++ComponentPartsEventSchema[] Events +} +ComponentPartsSchema --> ComponentPartsAttributeDefineSchema : "包含" +ComponentPartsSchema --> ComponentPartsEventSchema : "包含" +ComponentPartsSchema --> ComponentPartsStyleSchema : "包含" +ComponentPartsSchema --> ComponentPartsFragmentSchema : "包含" +``` + +**图示来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsSchema.cs) +- [ComponentPartsAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs) +- [ComponentPartsEventSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsEventSchema.cs) +- [ComponentPartsStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsStyleSchema.cs) +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) + +**本节来源** +- [ComponentPartsAttributeDefineGroupSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineGroupSchema.cs) +- [ComponentPartsStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsStyleSchema.cs) + +## 事件响应机制 + +事件响应机制通过`ComponentPartsEventSchema`定义和`EventTargetTypeEnum`枚举实现。设计时,用户可以为组件事件配置响应动作;运行时,事件系统根据配置执行相应逻辑。 + +```mermaid +flowchart TD +Start([组件事件触发]) --> CheckConfig["检查事件配置"] +CheckConfig --> ConfigExists{"配置存在?"} +ConfigExists --> |否| End([无操作]) +ConfigExists --> |是| GetAction["获取响应动作"] +GetAction --> ActionType{"动作类型"} +ActionType --> |导航| Navigate["执行页面导航"] +ActionType --> |数据操作| DataOp["执行数据操作"] +ActionType --> |状态变更| StateChange["更新组件状态"] +Navigate --> End +DataOp --> End +StateChange --> End +``` + +**本节来源** +- [ComponentPartsEventSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsEventSchema.cs) + +## 前端渲染逻辑绑定 + +从元数据定义到前端渲染的完整流程包括: +1. 加载组件元数据 +2. 解析属性、事件和样式配置 +3. 生成组件实例 +4. 绑定事件处理器 +5. 应用样式配置 +6. 渲染到DOM + +```mermaid +sequenceDiagram +participant Meta as "元数据服务" +participant Factory as "组件工厂" +participant Renderer as "渲染引擎" +participant DOM as "DOM" +Meta->>Factory : 请求创建组件 +Factory->>Meta : 获取ComponentPartsSchema +Meta-->>Factory : 返回元数据 +Factory->>Factory : 创建组件实例 +Factory->>Factory : 绑定属性默认值 +Factory->>Factory : 注册事件处理器 +Factory->>Renderer : 提交组件实例 +Renderer->>Renderer : 应用样式配置 +Renderer->>Renderer : 处理碎片化结构 +Renderer->>DOM : 渲染组件 +DOM-->>Renderer : 返回渲染结果 +Renderer-->>Factory : 确认渲染完成 +Factory-->>Meta : 返回组件实例 +``` + +**本节来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsSchema.cs) +- [ComponentPartsRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs) + +## 组件面板加载机制 + +`PartsDesignEngineModule`负责组件面板的初始化和加载,通过依赖注入获取`ComponentLibraryAppService`,在模块初始化时加载所有可用组件。 + +```csharp +public class PartsDesignEngineModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddTransient(); + context.Services.AddTransient(); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var service = context.ServiceProvider.GetService(); + var components = service.GetListAsync().Result; + // 初始化组件面板 + ComponentPanel.Initialize(components); + } +} +``` + +**本节来源** +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) + +## 调试与验证流程 + +### 新组件集成验证步骤 + +1. **元数据验证**:检查JSON元数据文件的完整性和正确性 +2. **注册验证**:确认组件已成功注册到`ComponentLibraryRepository` +3. **面板显示**:验证组件是否出现在设计引擎的组件面板中 +4. **拖拽测试**:测试组件能否从面板拖拽到画布 +5. **属性配置**:验证属性面板是否正确显示组件属性 +6. **事件绑定**:测试事件配置和响应是否正常 +7. **样式应用**:验证样式配置能否正确应用到组件 +8. **运行时验证**:在预览模式下测试组件功能 + +### 常见问题排查 + +- **组件不显示**:检查`Category`属性是否正确,确保组件库已刷新 +- **属性不生效**:验证属性名称与前端实现是否匹配 +- **事件无响应**:检查事件名称拼写和事件处理器注册 +- **样式不应用**:确认CSS属性名称和值格式正确 + +**本节来源** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs) +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\351\273\230\350\256\244\347\273\204\344\273\266\345\214\205\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\351\273\230\350\256\244\347\273\204\344\273\266\345\214\205\347\256\241\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..664611e2871cc61c038f230b744f9d47366de9c5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\211\251\345\261\225\344\270\216\351\233\206\346\210\220/\351\273\230\350\256\244\347\273\204\344\273\266\345\214\205\347\256\241\347\220\206.md" @@ -0,0 +1,203 @@ +# 默认组件包管理 + + +**本文档中引用的文件** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) +- [ComponentLibrarySchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentLibrarySchema.cs) +- [PartsMetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PartsMetaSchemaBase.cs) +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs) +- [ComponentPartsRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs) +- [PageAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs) +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入解析低代码平台中默认组件包的加载机制与覆盖策略。重点分析 `LowCodeDefaultComponentModule` 的注册流程,说明其如何通过依赖注入向系统注入基础组件(如按钮、输入框等)。文档还解释了组件模块的优先级排序机制和冲突解决规则,并指导开发者如何安全地扩展或替换默认组件,同时保持向后兼容性。涵盖组件注册表(`ComponentLibrarySchema`)的初始化过程、动态加载机制以及热更新支持。最后提供最佳实践建议,包括命名空间管理、资源打包和按需加载优化。 + +## 项目结构 +项目采用分层架构,主要分为元数据(meta)、源代码(src)和工具(Tools)三大目录。元数据目录存储了应用、页面、菜单和组件的JSON配置文件。源代码目录包含核心功能模块,如组件基础、默认组件、元数据模式、设计引擎和渲染引擎。工具目录则包含数据库迁移和元数据迁移工具。 + +```mermaid +graph TB +subgraph "元数据" +meta[meta] +meta --> apps[apps] +meta --> parts[parts\componentParts\antdesign] +end +subgraph "源代码" +src[src] +src --> Common[Common] +src --> DesignEngine[DesignEngine] +src --> RenderEngine[RenderEngine] +end +subgraph "工具" +Tools[Tools] +Tools --> DbMigrator[H.LowCode.DbMigrator] +Tools --> MetaMigrator[H.LowCode.MetaMigrator] +end +meta --> src +src --> Tools +``` + +**Diagram sources** +- [meta](file://meta) +- [src](file://src) +- [Tools](file://Tools) + +**Section sources** +- [README.md](file://README.md) + +## 核心组件 +核心组件包括 `LowCodeDefaultComponentModule` 和 `ComponentLibrarySchema`。前者负责注册默认组件,后者定义了组件库的元数据结构。 + +**Section sources** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) +- [ComponentLibrarySchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentLibrarySchema.cs) + +## 架构概览 +系统采用模块化设计,通过依赖注入(DI)容器管理组件的生命周期。设计引擎和渲染引擎共享元数据模式,但各自独立运行。组件库通过JSON文件存储在文件系统中,支持动态加载和热更新。 + +```mermaid +graph TD +A[LowCodeDefaultComponentModule] --> B[依赖注入容器] +B --> C[AntDesign组件] +D[ComponentLibrarySchema] --> E[组件库元数据] +E --> F[ComponentLibraryRepository] +F --> G[文件系统] +H[PageAppService] --> I[组件定义合并] +I --> J[向后兼容性] +``` + +**Diagram sources** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) +- [ComponentLibrarySchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentLibrarySchema.cs) +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs) +- [PageAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs) + +## 详细组件分析 + +### LowCodeDefaultComponentModule 分析 +`LowCodeDefaultComponentModule` 是一个ABP模块,负责向DI容器注册AntDesign组件。其核心方法 `ConfigureServices` 调用 `AddAntDesign` 扩展方法来注入所有AntDesign UI组件。 + +```mermaid +classDiagram +class LowCodeDefaultComponentModule { ++ConfigureServices(context) +} +class AbpModule { +<> ++ConfigureServices(context) +} +LowCodeDefaultComponentModule --|> AbpModule : 实现 +``` + +**Diagram sources** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs#L0-L11) + +**Section sources** +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs#L0-L11) + +### ComponentLibrarySchema 分析 +`ComponentLibrarySchema` 类定义了组件库的元数据结构,继承自 `PartsMetaSchemaBase`,包含库ID、名称、描述、支持平台和修改时间等属性。 + +```mermaid +classDiagram +class ComponentLibrarySchema { ++string LibraryId ++string LibraryName ++int PublishStatus ++string Description ++SupportPlatformEnum[] SupportPlatforms +} +class PartsMetaSchemaBase { ++string CreatedUser ++DateTime CreatedTime ++string ModifiedUser ++DateTime ModifiedTime +} +ComponentLibrarySchema --|> PartsMetaSchemaBase : 继承 +``` + +**Diagram sources** +- [ComponentLibrarySchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentLibrarySchema.cs#L0-L35) +- [PartsMetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PartsMetaSchemaBase.cs#L0-L14) + +**Section sources** +- [ComponentLibrarySchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentLibrarySchema.cs#L0-L35) +- [PartsMetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PartsMetaSchemaBase.cs#L0-L14) + +### 组件加载与热更新机制 +组件库通过 `ComponentLibraryRepository` 从文件系统加载。`GetListAsync` 方法扫描 `componentParts` 目录下的所有子目录,读取每个目录下的 `*.json` 文件(如 `antdesign.json`),并反序列化为 `ComponentLibrarySchema` 对象。当组件库被修改时,`SaveAsync` 方法会更新 `ModifiedTime` 字段,从而实现热更新检测。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant Service as "ComponentLibraryAppService" +participant Domain as "ComponentLibraryDomainService" +participant Repository as "ComponentLibraryRepository" +participant FileSystem as "文件系统" +Client->>Service : GetListAsync() +Service->>Domain : GetListAsync() +Domain->>Repository : GetListAsync() +Repository->>FileSystem : 读取 componentParts 目录 +FileSystem-->>Repository : 返回文件列表 +Repository->>Repository : 反序列化 JSON 文件 +Repository-->>Domain : 返回 ComponentLibrarySchema 列表 +Domain-->>Service : 返回列表 +Service-->>Client : 返回组件库列表 +``` + +**Diagram sources** +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs#L0-L68) +- [ComponentLibraryDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/PartsDomainServices/ComponentLibraryDomainService.cs#L0-L40) +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs#L0-L37) + +**Section sources** +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs#L0-L68) + +## 依赖关系分析 +系统通过清晰的依赖层次管理组件。`ComponentLibraryAppService` 依赖 `ComponentLibraryDomainService`,后者又依赖 `ComponentLibraryRepository`。这种分层设计确保了业务逻辑与数据访问的分离。 + +```mermaid +graph TD +A[ComponentLibraryAppService] --> B[ComponentLibraryDomainService] +B --> C[ComponentLibraryRepository] +C --> D[文件系统] +E[PageAppService] --> F[ComponentPartsAppService] +F --> G[ComponentPartsRepository] +G --> D +``` + +**Diagram sources** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs#L0-L37) +- [ComponentLibraryDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/PartsDomainServices/ComponentLibraryDomainService.cs#L0-L40) +- [ComponentLibraryRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentLibraryRepository.cs#L0-L38) + +**Section sources** +- [ComponentLibraryAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentLibraryAppService.cs#L0-L37) + +## 性能考量 +组件的动态加载和按需加载是性能优化的关键。通过 `GetByIdAsync` 方法可以按需加载特定组件,避免一次性加载所有组件带来的性能开销。此外,`ComponentPartsRepository` 中的 `GetListAsync` 方法会对组件进行排序,确保组件在UI中按预期顺序显示。 + +## 故障排除指南 +- **组件未加载**:检查 `antdesign.json` 文件是否存在且格式正确。 +- **热更新失效**:确认 `ModifiedTime` 字段是否被正确更新。 +- **依赖注入失败**:检查 `LowCodeDefaultComponentModule` 是否被正确引用。 + +**Section sources** +- [antdesign.json](file://meta/parts/componentParts/antdesign/antdesign.json) +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs#L9) + +## 结论 +本文档详细解析了低代码平台中默认组件包的加载机制。通过 `LowCodeDefaultComponentModule` 注册AntDesign组件,利用 `ComponentLibrarySchema` 和 `ComponentLibraryRepository` 实现组件库的动态加载和热更新。开发者可以基于此机制安全地扩展或替换默认组件,同时通过组件定义合并机制确保向后兼容性。建议在开发中遵循命名空间管理和按需加载的最佳实践,以优化应用性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\212\200\346\234\257\346\240\210\344\270\216\344\276\235\350\265\226.md" "b/.qoder/repowiki/zh/content/\346\212\200\346\234\257\346\240\210\344\270\216\344\276\235\350\265\226.md" new file mode 100644 index 0000000000000000000000000000000000000000..e253666292d394368039a4ad5331a285ef21482c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\212\200\346\234\257\346\240\210\344\270\216\344\276\235\350\265\226.md" @@ -0,0 +1,277 @@ +# 技术栈与依赖 + + +**本文档引用的文件** +- [README.md](file://README.md) +- [global.json](file://global.json) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema/RenderEngine/AppSchema.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) + + +## 目录 +1. [技术栈概览](#技术栈概览) +2. [核心框架与技术分析](#核心框架与技术分析) + 2.1 [.NET 8.0 运行时环境](#net-80-运行时环境) + 2.2 [Blazor 框架](#blazor-框架) + 2.3 [Entity Framework Core 数据访问机制](#entity-framework-core-数据访问机制) + 2.4 [Volo.Abp 模块化架构](#voloabp-模块化架构) +3. [主要 NuGet 包与版本](#主要-nuget-包与版本) +4. [元数据持久化方式的技术权衡](#元数据持久化方式的技术权衡) +5. [前端样式与 JavaScript 互操作](#前端样式与-javascript-互操作) +6. [构建工具链与环境兼容性](#构建工具链与环境兼容性) + +## 技术栈概览 + +本项目是一个基于 .NET 8.0 和 Blazor 的低代码实验性平台,采用模块化设计,支持元数据驱动的应用构建。项目结构清晰,分为设计引擎(DesignEngine)和渲染引擎(RenderEngine)两大核心模块,分别负责可视化设计和运行时渲染。系统通过 Volo.Abp 框架实现模块化、依赖注入和领域服务管理,结合 Entity Framework Core 实现动态数据模型的持久化,并支持 JSON 文件和数据库两种元数据存储方式。 + +**Section sources** +- [README.md](file://README.md) +- [global.json](file://global.json) + +## 核心框架与技术分析 + +### .NET 8.0 运行时环境 + +项目明确基于 .NET 8.0 构建,尽管 `global.json` 文件中指定的 SDK 版本为 9.0.100,但这通常表示开发环境的最新预览版,而项目实际目标框架仍为 .NET 8.0。.NET 8.0 作为长期支持(LTS)版本,提供了卓越的性能、现代化的 API 和对云原生应用的全面支持。 + +.NET 8.0 的优势包括: +- **性能提升**:JIT 编译器和 GC 的优化显著提升了应用吞吐量和响应速度。 +- **统一平台**:支持跨平台(Windows、Linux、macOS)部署,便于 DevOps 和容器化。 +- **现代化开发体验**:集成 Minimal APIs、源生成器(Source Generators)等特性,简化开发流程。 +- **安全性与稳定性**:作为 LTS 版本,获得长期安全更新和技术支持。 + +项目通过 `WebApplication.CreateBuilder` 创建应用,利用了 .NET 8.0 对 ASP.NET Core 的现代化配置模型。 + +```mermaid +graph TD +A[.NET 8.0 运行时] --> B[Blazor WebAssembly] +A --> C[Blazor Server] +A --> D[Entity Framework Core] +A --> E[ASP.NET Core] +B --> F[前端交互] +C --> G[后端渲染] +D --> H[数据持久化] +E --> I[HTTP 服务] +``` + +**Diagram sources** +- [global.json](file://global.json) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +**Section sources** +- [global.json](file://global.json) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +### Blazor 框架 + +Blazor 框架是本项目实现前后端统一开发的核心。项目采用了 Blazor 的混合渲染模式(Hybrid Rendering),在 `Program.cs` 中通过 `.AddInteractiveServerComponents()` 和 `.AddInteractiveWebAssemblyComponents()` 同时注册了服务端和 WebAssembly 渲染模式。 + +这种架构的优势在于: +- **灵活性**:关键页面可使用服务端渲染保证性能,复杂交互页面可使用 WebAssembly 实现富客户端体验。 +- **代码复用**:C# 代码可在前后端共享,减少技术栈分裂。 +- **无缝集成**:通过 `LowCodeGlobalVariables.AdditionalAssemblies` 动态加载额外程序集,实现了模块的热插拔。 + +项目中的 `.razor.css` 文件(如 `DragItem.razor.css`)表明使用了 CSS 隔离(CSS Isolation)技术,确保组件样式不会相互污染。 + +```mermaid +sequenceDiagram +participant Browser as 浏览器 +participant Server as 服务器 +participant WASM as WebAssembly +Browser->>Server : 请求页面 +alt 服务端渲染 +Server->>Server : 执行 C# 逻辑 +Server-->>Browser : 返回 HTML +Browser->>Server : SignalR 实时通信 +else WebAssembly 渲染 +Server-->>Browser : 下载 WASM 应用 +Browser->>WASM : 执行 C# 代码 +WASM->>Server : HTTP API 调用 +end +``` + +**Diagram sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +### Entity Framework Core 数据访问机制 + +Entity Framework Core (EF Core) 在本项目中扮演着动态数据访问的核心角色。通过 `DesignEngineDbContext` 和 `RenderEngineDbContext` 两个上下文,实现了对动态实体的 CRUD 操作。 + +核心实现机制如下: +1. **动态实体映射**:`EntityTypeManager` 负责加载动态实体定义,`OnModelCreating` 方法中通过反射动态创建 `EntityTypeBuilder`,将 `DynamicEntityInfo` 映射到数据库表。 +2. **属性配置**:`ConfigureProperties` 方法根据字段元数据(如 `MaxLength`、`IsUnicode`、`Precision`)配置 EF Core 的属性映射。 +3. **逻辑删除**:通过 `HasQueryFilter` 实现软删除,自动过滤 `IsDeleted=0` 的记录。 +4. **拦截器**:使用 `QueryWithNoLockDbCommandInterceptor` 实现 `WITH(NOLOCK)` 查询提示,`ReadOnlySaveChangesInterceptor` 控制保存行为。 + +```csharp +// 简化后的核心代码示例 +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + var dynamicEntities = _entityTypeManager.LoadDynamicEntities(); + foreach (var entity in dynamicEntities) + { + var entityBuilder = modelBuilder.Entity(entity.EntityType).ToTable(entity.EntityName); + ConfigureProperties(entityBuilder, entity, entity.EntityType); + entityBuilder.HasKey(entity.PrimaryKey); + if (entity.EnableSoftDelete) + { + entityBuilder.HasQueryFilter(e => e.IsDeleted == false); + } + } +} +``` + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +### Volo.Abp 模块化架构 + +虽然代码中未直接出现 Volo.Abp 的命名空间,但从模块命名(如 `*Module.cs`)、分层结构(Application、Domain、EntityFrameworkCore)和依赖注入模式来看,项目明显采用了 Volo.Abp 的模块化设计理念。 + +关键应用包括: +- **模块化**:每个功能(如 `H.LowCode.DesignEngine`)都是一个独立模块,通过 `*Module.cs` 定义生命周期。 +- **依赖注入**:使用 Autofac 作为 DI 容器(`builder.Host.UseAutofac()`),通过 `AddApplicationAsync()` 注册模块服务。 +- **领域服务**:`Domain` 层包含 `*DomainService.cs` 和 `I*DomainService.cs` 接口,遵循领域驱动设计(DDD)。 +- **仓储模式**:`Repositories` 层定义了 `I*Repository` 接口,实现了数据访问的抽象。 + +```mermaid +classDiagram +class DesignEngineHostModule { ++ConfigureServices() ++OnApplicationInitialization() +} +class DesignEngineApplicationModule { ++ConfigureServices() +} +class DesignEngineDomainModule { ++ConfigureServices() +} +class DesignEngineEntityFrameworkCoreModule { ++ConfigureServices() +} +DesignEngineHostModule --> DesignEngineApplicationModule : "依赖" +DesignEngineApplicationModule --> DesignEngineDomainModule : "依赖" +DesignEngineDomainModule --> DesignEngineEntityFrameworkCoreModule : "依赖" +``` + +**Diagram sources** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [DesignEngineApplicationModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/DesignEngineApplicationModule.cs) + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) + +## 主要 NuGet 包与版本 + +尽管无法直接读取 `.csproj` 文件,但根据代码实现和项目结构,可以推断出以下主要 NuGet 包及其作用: + +| 包名称 | 推断版本 | 作用 | +|--------|----------|------| +| Microsoft.AspNetCore.Components.Web | .NET 8.0 | Blazor 核心组件 | +| Microsoft.EntityFrameworkCore | 8.0.x | ORM 数据访问 | +| Microsoft.EntityFrameworkCore.SqlServer | 8.0.x | SQL Server 数据库提供程序 | +| Autofac | 7.0.x | 依赖注入容器 | +| System.Text.Json | 8.0.x | JSON 序列化 | +| Microsoft.AspNetCore.ResponseCompression | 8.0.x | 响应压缩(Brotli) | + +架构考量:选择这些包是为了与 .NET 8.0 生态无缝集成,确保性能和稳定性。例如,使用 Autofac 是为了支持更复杂的 DI 场景,而 Brotli 压缩则优化了 WebAssembly 应用的加载速度。 + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +## 元数据持久化方式的技术权衡 + +项目支持两种元数据持久化方式:JSON 文件存储和数据库存储(通过 EF Core)。 + +### JSON 文件存储 +- **优点**: + - 简单轻量,无需数据库依赖。 + - 易于版本控制和备份(如 `meta/apps/caseapp/page/*.json`)。 + - 适合小型应用或开发环境。 +- **缺点**: + - 并发写入可能导致冲突。 + - 查询和索引能力弱。 + - 不适合大规模数据。 + +### 数据库存储 +- **优点**: + - 支持 ACID 事务,数据一致性高。 + - 强大的查询和索引能力。 + - 支持复杂关系和外键约束。 + - 适合生产环境和大型应用。 +- **缺点**: + - 部署复杂,需要数据库服务器。 + - 迁移和维护成本高。 + +项目通过 `Repository.JsonFile` 和 `Repository.RemoteService` 模块实现了两种方式的抽象,可在 `appsettings.json` 中配置切换。 + +```mermaid +flowchart TD +A[元数据] --> B{存储方式} +B --> |JSON 文件| C[FileRepositoryBase] +B --> |数据库| D[EntityFrameworkCore] +C --> E[meta/apps/*.json] +D --> F[SQL Server] +``` + +**Diagram sources** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +**Section sources** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +## 前端样式与 JavaScript 互操作 + +### 前端样式处理 +项目采用 CSS 隔离技术,每个 Razor 组件可拥有独立的 `.razor.css` 文件。例如,`DragItem.razor.css` 专门定义拖拽项的样式,避免全局污染。主题模块 `H.LowCode.Themes.AntBlazor` 表明使用了 Ant Design Blazor 组件库,通过 `ComponentRender.razor.css` 进行样式定制。 + +### JavaScript 互操作 +项目包含 `elementUtils.js` 文件,用于实现 Blazor 与 JavaScript 的互操作。典型应用场景包括: +- DOM 操作:直接操作元素尺寸、位置。 +- 浏览器 API 调用:访问本地存储、通知等。 +- 性能敏感操作:如复杂动画。 + +在 C# 中通过 `IJSRuntime` 调用: +```csharp +await jsRuntime.InvokeVoidAsync("elementUtils.resize", element, width, height); +``` + +**Section sources** +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [ComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor.css) + +## 构建工具链与环境兼容性 + +### 构建工具链 +- **迁移管理**:使用 `H.LowCode.DbMigrator` 项目和 `dotnet ef` 命令管理数据库迁移。 +- **配置**:`appsettings.json` 和 `appsettings.Development.json` 分别管理生产和开发配置。 +- **启动配置**:`Program.cs` 使用现代化的主机配置,集成响应压缩、HTTPS 重定向等。 + +### 环境兼容性矩阵 + +| 类别 | 支持项 | +|------|--------| +| **操作系统** | Windows 10/11, Linux (Ubuntu 20.04+), macOS | +| **浏览器** | Chrome, Edge, Firefox, Safari (最新两个版本) | +| **开发工具** | Visual Studio 2022, Visual Studio Code, .NET SDK 8.0+ | + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [DbMigrator](file://src/Tools/H.LowCode.DbMigrator) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\345\205\203\346\225\260\346\215\256\357\274\210Meta\357\274\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\345\205\203\346\225\260\346\215\256\357\274\210Meta\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..07ea4ca45c7402ea0df0cd54198e69ba9ff1c1f2 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\345\205\203\346\225\260\346\215\256\357\274\210Meta\357\274\211.md" @@ -0,0 +1,399 @@ +# 元数据(Meta) + + +**本文档引用的文件** +- [MetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件分析](#核心组件分析) +4. [元数据继承体系](#元数据继承体系) +5. [元数据生命周期与发布状态](#元数据生命周期与发布状态) +6. [元数据合并与校验机制](#元数据合并与校验机制) +7. [元数据结构树形图](#元数据结构树形图) +8. [结论](#结论) + +## 引言 + +在低代码平台中,元数据是驱动系统配置、设计与渲染的核心。它通过结构化的JSON文件进行序列化存储,并在设计引擎与渲染引擎之间传递,实现“一次设计,多端运行”的能力。本文深入分析元数据的设计原理、继承体系、存储结构、合并机制与生命周期管理,揭示其作为系统配置中枢的关键作用。 + +## 项目结构 + +低代码平台的项目结构清晰地划分为两个主要部分:`meta`(元数据)和`src`(源代码)。 + +- `meta`目录存放所有应用的元数据配置,按应用(如`caseapp`、`testapp`)组织,每个应用包含`datasource`(数据源)、`menu`(菜单)、`page`(页面)等子目录,以及应用级别的`caseapp.json`文件。 +- `src`目录包含平台的核心源代码,其中`H.LowCode.MetaSchema`命名空间定义了所有元数据模式的基类与结构。 + +```mermaid +graph TD +A[项目根目录] --> B[meta] +A --> C[src] +B --> D[apps] +B --> E[parts] +D --> F[caseapp] +D --> G[testapp] +F --> H[datasource] +F --> I[menu] +F --> J[page] +F --> K[caseapp.json] +C --> L[Common] +L --> M[H.LowCode.MetaSchema] +M --> N[AppSchemaBase.cs] +M --> O[PageSchemaBase.cs] +M --> P[ComponentSchemaBase.cs] +M --> Q[MetaSchemaBase.cs] +M --> R[Enums] +R --> S[PublishStatusEnum.cs] +M --> T[Utils] +T --> U[ObjectMerger.cs] +``` + +**图示来源** +- [meta/apps/caseapp](file://meta/apps/caseapp) +- [src/Common/H.LowCode.MetaSchema](file://src/Common/H.LowCode.MetaSchema) + +## 核心组件分析 + +### 元数据基类:MetaSchemaBase + +`MetaSchemaBase`是所有元数据模式的抽象基类,继承自`StateHasChangeSchema`,封装了元数据的通用审计字段。 + +```csharp +public abstract class MetaSchemaBase : StateHasChangeSchema +{ + [JsonPropertyName("cu")] + public string CreatedUser { get; set; } + + [JsonPropertyName("ct")] + public DateTime CreatedTime { get; set; } + + [JsonPropertyName("mu")] + public string ModifiedUser { get; set; } + + [JsonPropertyName("mt")] + public DateTime ModifiedTime { get; set; } +} +``` + +该类定义了创建用户、创建时间、修改用户和修改时间四个属性,确保所有元数据实体都具备完整的变更追踪能力。 + +**本节来源** +- [MetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs#L5-L18) + +### 应用元数据:AppSchemaBase + +`AppSchemaBase`继承自`MetaSchemaBase`,定义了应用级别的元数据结构。 + +```csharp +public abstract class AppSchemaBase : MetaSchemaBase +{ + public string Id { get; set; } + [JsonPropertyName("n")] public string Name { get; set; } + public string Icon { get; set; } + [JsonPropertyName("pic")] public string Picture { get; set; } + [JsonPropertyName("desc")] public string Description { get; set; } + [JsonPropertyName("v")] public string Version { get; set; } + [JsonPropertyName("pub")] public PublishStatusEnum PublishStatus { get; set; } + [JsonPropertyName("platform")] public SupportPlatformEnum[] SupportPlatforms { get; set; } = [0]; +} +``` + +关键字段包括: +- `Id`:应用唯一标识 +- `Name`:应用名称 +- `PublishStatus`:发布状态(开发中、审批中、已发布) +- `SupportPlatforms`:支持的运行平台 + +**本节来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs#L4-L27) + +### 页面元数据:PageSchemaBase + +`PageSchemaBase`同样继承自`MetaSchemaBase`,描述页面的配置信息。 + +```csharp +public abstract class PageSchemaBase : MetaSchemaBase +{ + [JsonPropertyName("aid")] public string AppId { get; set; } + [JsonPropertyName("id")] public string Id { get; set; } = ShortIdGenerator.Generate(); + [JsonPropertyName("n")] public string Name { get; set; } + [JsonPropertyName("order")] public int Order { get; set; } + [JsonPropertyName("pt")] public PageTypeEnum PageType { get; set; } + [JsonPropertyName("pub")] public int PublishStatus { get; set; } + [JsonPropertyName("pageprop")] public PagePropertySchema PageProperty { get; set; } = new(); + [JsonPropertyName("ds")] public PageDataSourceSchema DataSource { get; set; } = new(); + [JsonPropertyName("evs")] public IList Events { get; set; } +} +``` + +它包含页面所属应用ID、页面类型、页面属性、数据源和事件列表等核心信息。 + +**本节来源** +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs#L5-L39) + +### 组件元数据:ComponentSchemaBase + +`ComponentSchemaBase`定义了页面中组件的元数据结构。 + +```csharp +public abstract class ComponentSchemaBase : StateHasChangeSchema +{ + [JsonPropertyName("id")] public string Id { get; set; } = ShortIdGenerator.Generate(); + [JsonPropertyName("pid")] public string ParentId { get; set; } + [JsonPropertyName("n")] public string Name { get; set; } + [JsonPropertyName("lb")] public string Label { get; set; } + [JsonPropertyName("container")] public bool IsContainer { get; set; } + [JsonPropertyName("sptds")] public bool IsSupportDataSource { get; set; } + [JsonPropertyName("stl")] public ComponentStyleSchema Style { get; set; } = new(); + [JsonPropertyName("evs")] public IList Events { get; set; } + [JsonPropertyName("evcs")] public IList EventConsumes { get; set; } + [JsonPropertyName("desc")] public string Description { get; set; } +} +``` + +组件元数据包含ID、父级ID、标签、是否为容器、是否支持数据源、样式、事件等,是构建页面UI的基础。 + +**本节来源** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs#L5-L77) + +## 元数据继承体系 + +元数据通过继承体系实现了结构的统一与扩展。以下是核心类的继承关系图: + +```mermaid +classDiagram +class StateHasChangeSchema { +} +class MetaSchemaBase { ++string CreatedUser ++DateTime CreatedTime ++string ModifiedUser ++DateTime ModifiedTime +} +class AppSchemaBase { ++string Id ++string Name ++string Icon ++string Picture ++string Description ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class PageSchemaBase { ++string AppId ++string Id ++string Name ++int Order ++PageTypeEnum PageType ++int PublishStatus ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList~EventSchema~ Events +} +class ComponentSchemaBase { ++string Id ++string ParentId ++string Name ++string Label ++bool IsHiddenLabel ++bool IsContainer ++bool IsSupportDataSource ++ComponentStyleSchema Style ++IList~EventSchema~ Events ++IList~EventConsumeSchema~ EventConsumes ++string Description +} +StateHasChangeSchema <|-- MetaSchemaBase +MetaSchemaBase <|-- AppSchemaBase +MetaSchemaBase <|-- PageSchemaBase +StateHasChangeSchema <|-- ComponentSchemaBase +``` + +**图示来源** +- [MetaSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) + +## 元数据生命周期与发布状态 + +元数据的生命周期贯穿设计、发布和运行三个阶段。 + +### 发布状态管理 + +`PublishStatusEnum`枚举定义了元数据的三种发布状态: + +```csharp +public enum PublishStatusEnum +{ + Development, // 开发中 + Approving, // 审批中 + Published // 已发布 +} +``` + +- **开发中**:设计师正在编辑,未发布。 +- **审批中**:提交审核,等待批准。 +- **已发布**:审核通过,可供运行引擎加载。 + +该状态机制确保了元数据在不同环境(开发、测试、生产)中的安全流转。 + +**本节来源** +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs#L8-L13) + +### 元数据序列化与存储 + +元数据以JSON格式存储在`meta/apps/{appname}/`目录下。例如,`caseapp.json`文件存储了`caseapp`应用的元数据: + +```json +{ + "id": "caseapp", + "n": "案例应用", + "desc": "用于演示的案例应用", + "v": "1.0.0", + "pub": 2, + "platform": [0], + "cu": "admin", + "ct": "2025-02-25T10:00:00Z", + "mu": "admin", + "mt": "2025-02-25T10:00:00Z" +} +``` + +此文件在设计时由设计引擎生成,在运行时由渲染引擎加载,实现了配置的持久化与传递。 + +**本节来源** +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) + +## 元数据合并与校验机制 + +`ObjectMerger`类提供了元数据的深度合并能力,用于处理版本更新、配置覆盖等场景。 + +### 合并逻辑 + +```csharp +public static class ObjectMerger +{ + public static void Merge(Type type, object source, object target) + { + if (target == null || source == null) + throw new ArgumentNullException(); + + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); + + foreach (var property in properties) + { + var sourcePropertyValue = property.GetValue(source); + if (sourcePropertyValue == null || IsDefaultValue(property.PropertyType, sourcePropertyValue)) + continue; + + if (IsCollectionType(property.PropertyType)) + { + MergeCollections(property, target, sourcePropertyValue); + } + else if (IsArrayType(property.PropertyType)) + { + MergeArray(property, target, sourcePropertyValue); + } + else if (property.PropertyType.IsClass && property.PropertyType != typeof(string)) + { + var targetPropertyValue = property.GetValue(target); + if (targetPropertyValue == null) + { + targetPropertyValue = Activator.CreateInstance(property.PropertyType); + property.SetValue(target, targetPropertyValue); + } + Merge(property.PropertyType, sourcePropertyValue, targetPropertyValue); + } + else + { + property.SetValue(target, sourcePropertyValue); + } + } + } +} +``` + +### 合并规则 + +1. **空值跳过**:`source`属性为`null`时不合并。 +2. **默认值跳过**:`source`属性为默认值时不合并。 +3. **集合处理**:递归合并集合中的每个元素。 +4. **数组处理**:扩展目标数组以匹配源数组长度,并合并元素。 +5. **引用类型**:递归合并嵌套对象。 +6. **值类型**:直接覆盖目标值。 + +该机制确保了元数据在升级或合并时,既能保留现有配置,又能安全地应用新变更。 + +**本节来源** +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs#L10-L174) + +## 元数据结构树形图 + +以下为`caseapp`应用的元数据结构树形图,展示了其作为系统配置中枢的完整视图: + +```mermaid +erDiagram +APP { +string Id PK +string Name +string Version +PublishStatusEnum PublishStatus +datetime CreatedTime +datetime ModifiedTime +} +PAGE { +string Id PK +string AppId FK +string Name +PageTypeEnum PageType +int Order +datetime CreatedTime +datetime ModifiedTime +} +COMPONENT { +string Id PK +string ParentId FK +string Name +bool IsContainer +bool IsSupportDataSource +datetime CreatedTime +datetime ModifiedTime +} +DATASOURCE { +string Id PK +string OwnerId +string Name +PageDataSourceTypeEnum Type +} +EVENT { +string Id +string TargetId +string Name +string Handler +} +APP ||--o{ PAGE : contains +PAGE ||--o{ COMPONENT : contains +PAGE ||--o{ DATASOURCE : has +COMPONENT ||--o{ EVENT : has +DATASOURCE ||--o{ EVENT : triggers +``` + +**图示来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) + +## 结论 + +元数据是低代码平台的核心驱动力。通过`MetaSchemaBase`基类及其继承体系,平台实现了统一的元数据模型。元数据以JSON文件形式序列化存储,贯穿设计、发布和运行全生命周期。`ObjectMerger`提供了安全的合并机制,`PublishStatusEnum`确保了配置的有序流转。整个系统以元数据为中枢,实现了配置化、可追溯、高内聚的低代码开发体验。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\345\272\224\347\224\250\357\274\210App\357\274\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\345\272\224\347\224\250\357\274\210App\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..602ebc9638856f732219f950642c6b775d18f100 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\345\272\224\347\224\250\357\274\210App\357\274\211.md" @@ -0,0 +1,282 @@ +# 应用(App) + + +**本文档引用的文件** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs) +- [SupportPlatformEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\SupportPlatformEnum.cs) +- [PublishStatusEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PublishStatusEnum.cs) +- [caseapp.json](file://meta\apps\caseapp\caseapp.json) +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) +- [AppSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\AppSchema.cs) +- [AppPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\AppPartsSchema.cs) +- [MetaAppService.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Application\RenderAppServices\MetaAppService.cs) +- [AppCascadingModel.cs](file://src\Common\H.LowCode.ComponentBase\CascadingModels\AppCascadingModel.cs) + + +## 目录 +1. [应用概述](#应用概述) +2. [应用元数据结构](#应用元数据结构) +3. [应用的创建、编辑、发布与删除流程](#应用的创建编辑发布与删除流程) +4. [应用在设计引擎与渲染引擎中的处理逻辑](#应用在设计引擎与渲染引擎中的处理逻辑) +5. [应用的聚合能力与部署边界](#应用的聚合能力与部署边界) + +## 应用概述 + +在低代码平台中,“应用”(App)是最顶层的容器,代表一个完整的、可独立运行和部署的业务系统。它不仅定义了系统的名称、标识、图标、描述等基本信息,还通过元数据配置决定了其支持的平台类型和当前的发布状态。每个应用都拥有唯一的标识(Id),并作为组织和管理其内部页面、菜单、数据源等资源的逻辑边界。 + +应用的生命周期由设计引擎(DesignEngine)管理,其运行时表现则由渲染引擎(RenderEngine)负责。设计引擎允许开发者通过可视化界面进行应用的构建和修改,而渲染引擎则将这些元数据转换为最终用户可交互的前端界面。 + +**Section sources** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) + +## 应用元数据结构 + +应用的元数据结构基于 `AppSchemaBase` 抽象类定义,该类继承自 `MetaSchemaBase`,并包含了一系列核心属性。这些属性通过 JSON 序列化特性(如 `[JsonPropertyName]`)映射为简短的键名,以优化存储和传输效率。 + +### AppSchemaBase 类属性结构 + +```csharp +public abstract class AppSchemaBase : MetaSchemaBase +{ + public string Id { get; set; } + + [JsonPropertyName("n")] + public string Name { get; set; } + + public string Icon { get; set; } + + [JsonPropertyName("pic")] + public string Picture { get; set; } + + [JsonPropertyName("desc")] + public string Description { get; set; } + + [JsonPropertyName("v")] + public string Version { get; set; } + + [JsonPropertyName("pub")] + public PublishStatusEnum PublishStatus { get; set; } + + [JsonPropertyName("platform")] + public SupportPlatformEnum[] SupportPlatforms { get; set; } = [0]; +} +``` + +#### 关键属性说明 +- **Id**: 应用的唯一标识符。 +- **Name (n)**: 应用的显示名称。 +- **Description (desc)**: 应用的描述信息。 +- **PublishStatus (pub)**: 应用的发布状态,枚举值见下文。 +- **SupportPlatforms (platform)**: 应用支持的平台数组,枚举值见下文。 + +### 支持的平台类型 (SupportPlatformEnum) + +```csharp +public enum SupportPlatformEnum +{ + [Display(Name = "Web")] + Web, + [Display(Name = "App")] + Mobile, + [Display(Name = "小程序")] + WXMiniApp +} +``` + +此枚举定义了应用可以部署的目标平台。例如,`[0, 2]` 表示该应用同时支持 Web 和小程序。 + +### 发布状态 (PublishStatusEnum) + +```csharp +public enum PublishStatusEnum +{ + Development, + Approving, + Published +} +``` + +此枚举表示应用的当前状态: +- **Development**: 开发中,应用仅对开发者可见。 +- **Approving**: 审核中,应用已提交发布,等待审批。 +- **Published**: 已发布,应用对最终用户可见并可访问。 + +### 应用元数据实例 (caseapp.json) + +以 `meta/apps/caseapp/caseapp.json` 文件为例,其内容如下: + +```json +{"id":"caseapp","n":"用例系统","desc":"展示典型页面案例 (参考 amis 示例)","platform":[0,2],"mt":"2025-05-29T16:49:31.1628431Z"} +``` + +- **id**: `caseapp` +- **n (Name)**: `用例系统` +- **desc (Description)**: `展示典型页面案例 (参考 amis 示例)` +- **platform (SupportPlatforms)**: `[0, 2]` (Web 和 小程序) +- **mt (ModifiedTime)**: 最后修改时间 + +此实例清晰地展示了应用元数据的完整结构。 + +**Section sources** +- [AppSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\AppSchemaBase.cs#L4-L27) +- [SupportPlatformEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\SupportPlatformEnum.cs#L9-L17) +- [PublishStatusEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PublishStatusEnum.cs#L8-L13) +- [caseapp.json](file://meta\apps\caseapp\caseapp.json) + +## 应用的创建、编辑、发布与删除流程 + +应用的生命周期管理主要在设计引擎中完成,其核心服务是 `AppApplicationService`。该服务通过依赖 `IAppDomainService` 来实现业务逻辑,并最终由 `IAppRepository` 负责与文件系统进行持久化交互。 + +### 核心服务与依赖关系 + +```mermaid +classDiagram +class AppApplicationService { ++GetAppsAsync() IList~AppListModel~ ++GetListAsync() IList~AppPartsSchema~ ++GetByIdAsync(appId) AppPartsSchema ++SaveAsync(appSchema) bool +} +class IAppDomainService { +<> ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(appId) Task~AppPartsSchema~ ++SaveAsync(appSchema) Task +} +class AppDomainService { +-IAppRepository _repository ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(appId) Task~AppPartsSchema~ ++SaveAsync(appSchema) Task +} +class IAppRepository { +<> ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(appId) Task~AppPartsSchema~ ++SaveAsync(appSchema) Task +} +class AppFileRepository { +-IOptions~MetaOption~ metaOption ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(appId) Task~AppPartsSchema~ ++SaveAsync(appSchema) Task +} +AppApplicationService --> IAppDomainService : "依赖" +IAppDomainService <|.. AppDomainService : "实现" +AppDomainService --> IAppRepository : "依赖" +IAppRepository <|.. AppFileRepository : "实现" +``` + +**Diagram sources** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs#L14-L51) +- [IAppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IAppDomainService.cs#L5-L12) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs#L7-L30) +- [IAppRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaRepositories\IAppRepository.cs#L6-L13) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs#L10-L68) + +### 流程详解 + +1. **创建/编辑 (Create/Edit)**: + - 开发者在设计引擎界面中创建或修改应用信息。 + - 操作触发 `AppApplicationService.SaveAsync(AppPartsSchema)` 方法。 + - 该方法将 `AppPartsSchema` 对象传递给 `AppDomainService.SaveAsync`。 + - `AppDomainService` 调用 `AppFileRepository.SaveAsync` 将元数据持久化到文件系统(`meta/apps/{appId}/{appId}.json`)。 + +2. **发布 (Publish)**: + - 本代码库中未直接体现发布流程,但可通过 `PublishStatus` 字段的变更来推断。 + - 当开发者点击“发布”时,系统会将 `PublishStatus` 从 `Development` 或 `Approving` 更新为 `Published`,然后调用 `SaveAsync` 进行持久化。 + +3. **删除 (Delete)**: + - 本代码库中未提供 `DeleteAsync` 方法,但逻辑上应由 `AppApplicationService` 调用 `AppDomainService`,再由 `AppDomainService` 指示 `AppFileRepository` 删除对应的应用目录和文件。 + +4. **读取 (Read)**: + - `AppApplicationService.GetListAsync()` 用于获取所有应用列表。 + - `AppApplicationService.GetByIdAsync(appId)` 用于获取特定应用的详细信息。 + - 这些请求最终由 `AppFileRepository` 从文件系统中读取 `.json` 文件并反序列化为对象。 + +**Section sources** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs#L14-L51) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs#L7-L30) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs#L10-L68) + +## 应用在设计引擎与渲染引擎中的处理逻辑 + +应用在设计引擎和渲染引擎中使用不同的模型类,以适应各自不同的需求。 + +### 模型类差异 + +- **设计引擎 (DesignEngine)**: + - 使用 `AppPartsSchema` 类。 + - 该类继承自 `AppSchemaBase`,并可能包含更多与设计时相关的元数据或扩展属性(尽管在当前代码中未体现)。 + - 主要用于在设计界面中展示和编辑应用。 + +- **渲染引擎 (RenderEngine)**: + - 使用 `AppSchema` 类。 + - 该类同样继承自 `AppSchemaBase`,但更侧重于运行时所需的精简信息。 + - 用于在最终用户访问时,快速加载应用的基本配置。 + +```csharp +// 设计引擎模型 +public class AppPartsSchema : AppSchemaBase { } + +// 渲染引擎模型 +public class AppSchema : AppSchemaBase { } +``` + +### 渲染引擎中的处理逻辑 + +渲染引擎通过 `MetaAppService` 提供服务,该服务可以获取应用的菜单和页面信息。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant MetaAppService as "MetaAppService" +participant PageDomainService as "PageDomainService" +participant AppFileRepository as "AppFileRepository" +Client->>MetaAppService : GetPageWithDefineAsync(appId, pageId) +MetaAppService->>PageDomainService : GetAsync(appId, pageId) +PageDomainService->>AppFileRepository : 读取 page/{pageId}.json +AppFileRepository-->>PageDomainService : PageSchema +PageDomainService-->>MetaAppService : PageSchema +MetaAppService->>MetaAppService : 合并组件定义 (MergeAttributeDefineToFragment) +MetaAppService-->>Client : 包含完整定义的 PageSchema +``` + +**Diagram sources** +- [MetaAppService.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Application\RenderAppServices\MetaAppService.cs#L11-L50) +- [AppFileRepository.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Repository.JsonFile\Repositories\AppFileRepository.cs#L9-L50) + +`MetaAppService.GetPageWithDefineAsync` 方法不仅获取页面,还会将页面中组件的属性定义(Attribute Define)合并到组件片段(Fragment)中,确保渲染引擎能获得完整的、可直接使用的组件信息。 + +**Section sources** +- [AppSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\AppSchema.cs#L5-L8) +- [AppPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\AppPartsSchema.cs#L5-L8) +- [MetaAppService.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Application\RenderAppServices\MetaAppService.cs#L11-L50) + +## 应用的聚合能力与部署边界 + +应用作为低代码平台中的顶级容器,其核心作用之一就是聚合和组织相关的资源。 + +### 资源聚合 + +根据项目结构,一个应用(如 `caseapp`)的目录下包含三个子目录: +- **page**: 存放该应用的所有页面元数据(`.json` 文件)。 +- **menu**: 存放该应用的所有菜单项元数据(`.json` 文件)。 +- **datasource**: 存放该应用的所有数据源配置(`.json` 文件)。 + +这种基于文件系统的目录结构清晰地定义了应用的边界。所有与 `caseapp` 相关的页面、菜单和数据源都被限定在 `meta/apps/caseapp/` 目录下,实现了资源的物理隔离和逻辑聚合。 + +### 独立部署单元 + +应用的独立性体现在: +1. **独立的元数据**: 每个应用都有自己的 `app.json` 文件,包含其独有的配置。 +2. **独立的资源集**: 应用的页面、菜单、数据源等资源不与其他应用共享(除非通过特定机制引用)。 +3. **独立的发布状态**: 每个应用可以独立地进行开发、审核和发布,互不影响。 + +因此,应用是低代码平台中一个完整的、可独立部署和管理的业务单元。当需要部署或迁移一个业务系统时,只需处理其对应的整个应用目录即可。 + +**Section sources** +- [caseapp.json](file://meta\apps\caseapp\caseapp.json) +- [AppCascadingModel.cs](file://src\Common\H.LowCode.ComponentBase\CascadingModels\AppCascadingModel.cs#L8-L10) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\346\225\260\346\215\256\346\272\220\357\274\210DataSource\357\274\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\346\225\260\346\215\256\346\272\220\357\274\210DataSource\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..7e6263935a24a4a2d6bbe460cef97e867f127bbd --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\346\225\260\346\215\256\346\272\220\357\274\210DataSource\357\274\211.md" @@ -0,0 +1,278 @@ +# 数据源(DataSource) + + +**本文档中引用的文件** +- [DataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\OptionDataSourceSchema.cs) +- [ComponentDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\ComponentDataSourceSchema.cs) +- [ComponentDataSourceTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\ComponentDataSourceTypeEnum.cs) +- [DataSourceFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\DataSourceFileRepository.cs) +- [DataSourceDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\DataSourceDomainService.cs) +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs) +- [qgzhc7w3z.json](file://meta\apps\caseapp\datasource\qgzhc7w3z.json) +- [RenderEngineDynamicComponentBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\RenderEngineDynamicComponentBase.cs) +- [DesignEngineDynamicComponentBase.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\DesignEngineDynamicComponentBase.cs) + + +## 目录 +1. [引言](#引言) +2. [数据源核心设计](#数据源核心设计) +3. [数据源类型与配置](#数据源类型与配置) +4. [API数据源配置示例](#api数据源配置示例) +5. [异步获取与绑定机制](#异步获取与绑定机制) +6. [设计与渲染引擎策略](#设计与渲染引擎策略) + +## 引言 +数据源(DataSource)是低代码平台中实现数据连接与抽象的核心模块。它为前端组件提供统一的数据访问接口,支持多种数据来源,包括数据库、API接口和静态选项。本文档将深入解析数据源的设计原理、配置方式、运行时行为以及在设计和渲染引擎中的实现策略。 + +## 数据源核心设计 + +数据源的设计基于一个清晰的继承与组合结构,以`DataSourceSchema`基类为核心,通过属性和组合模式支持多种数据源类型。 + +```mermaid +classDiagram +class DataSourceSchema { ++string AppId ++string Id ++string Name ++string DisplayName ++string Description ++int Order ++ComponentDataSourceTypeEnum DataSourceType ++bool PublishStatus ++IList TableFields ++APIDataSourceSchema API ++OptionDataSourceSchema[] Options +} +class APIDataSourceSchema { ++string Domain ++string Path ++string Method ++IList Queries ++APIBodySchema Body ++IList Headers +} +class SQLDataSourceSchema { ++string DbType ++string Sql +} +class OptionDataSourceSchema { ++string Id ++string Label ++string Value +} +class ComponentDataSourceSchemaBase { ++ComponentDataSourceGroupTypeEnum DataSourceGroupType ++ComponentDataSourceTypeEnum DataSourceType ++string DataSourceId ++string DataSourceName ++string DataSourceValue ++IList FiexdOptionDataSource ++APIDataSourceSchema APIOptionDataSource ++SQLDataSourceSchema SQLOptionDataSource +} +DataSourceSchema --> APIDataSourceSchema : "包含" +DataSourceSchema --> SQLDataSourceSchema : "包含" +DataSourceSchema --> OptionDataSourceSchema : "包含" +ComponentDataSourceSchemaBase --> APIDataSourceSchema : "包含" +ComponentDataSourceSchemaBase --> SQLDataSourceSchema : "包含" +ComponentDataSourceSchemaBase --> OptionDataSourceSchema : "包含" +``` + +**图示来源** +- [DataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\OptionDataSourceSchema.cs) +- [ComponentDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\ComponentDataSourceSchema.cs) + +**本节来源** +- [DataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchema.cs) +- [ComponentDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\ComponentDataSourceSchema.cs) + +## 数据源类型与配置 + +数据源通过`ComponentDataSourceTypeEnum`枚举定义了多种类型,每种类型对应不同的配置参数和使用场景。 + +### 数据源类型枚举 +```csharp +public enum ComponentDataSourceTypeEnum +{ + None = 0, + DB = 1, // 数据库表 + API = 2, // API接口 + Option = 3, // 选项列表 + SQL = 6, // 自定义SQL + Expression = 7, // 表达式 + Fiexd = 8 // 固定值 +} +``` + +### 主要数据源类型详解 + +#### **API数据源 (API)** +用于连接外部HTTP API。其配置参数定义在`APIDataSourceSchema`类中: +- **Domain**: API的域名或基础URL +- **Path**: 请求路径 +- **Method**: HTTP方法 (GET, POST等) +- **Queries**: URL查询参数列表 +- **Headers**: HTTP请求头列表 +- **Body**: 请求体,支持JSON、文本、Multipart等多种格式 + +#### **SQL数据源 (SQL)** +用于执行自定义SQL查询。其配置参数定义在`SQLDataSourceSchema`类中: +- **DbType**: 数据库类型 (如MySQL, PostgreSQL) +- **Sql**: 要执行的SQL语句 + +#### **选项数据源 (Option)** +用于提供下拉框、单选框等组件的选项列表。其配置参数定义在`OptionDataSourceSchema`记录中: +- **Label**: 选项显示文本 +- **Value**: 选项实际值 + +**本节来源** +- [ComponentDataSourceTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\ComponentDataSourceTypeEnum.cs) +- [APIDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\OptionDataSourceSchema.cs) + +## API数据源配置示例 + +以`qgzhc7w3z.json`文件为例,该文件定义了一个数据库表数据源,其结构如下: + +```json +{ + "aid": "caseapp", + "id": "qgzhc7w3z", + "n": "tb_test1", + "disn": "测试表1", + "desc": "xxx", + "type": 1, + "fields": [ + { + "id": "9080f5b9-b155-4aa2-82d9-dc7a20192c06", + "n": "f_id", + "disn": "主键", + "type": "varchar", + "pk": true + }, + { + "id": "b4c09312-7267-45fc-94c1-15f893d0f5ea", + "n": "f_field1", + "disn": "字段1", + "type": "varchar", + "nul": true + } + // ... 其他字段 + ], + "ops": [], + "modifiedTime": "2025-03-23T10:17:51.3553924Z" +} +``` + +**关键配置说明**: +- **aid**: 所属应用ID (`caseapp`) +- **id**: 数据源唯一标识符 (`qgzhc7w3z`) +- **n**: 数据源名称 (`tb_test1`) +- **disn**: 显示名称 (`测试表1`) +- **type**: 数据源类型,值为`1`,对应`ComponentDataSourceTypeEnum.DB`,表示这是一个数据库表数据源 +- **fields**: 字段列表,定义了表的结构,包括字段名(`n`)、显示名(`disn`)、数据类型(`type`)、是否为主键(`pk`)、是否可为空(`nul`)等属性 +- **ops**: 选项列表,此数据源为空 + +**本节来源** +- [qgzhc7w3z.json](file://meta\apps\caseapp\datasource\qgzhc7w3z.json) +- [DataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchema.cs) + +## 异步获取与绑定机制 + +数据源在应用运行时通过异步机制进行获取、绑定和刷新。 + +### **异步获取流程** +数据源的获取由`DataSourceFileRepository`实现,遵循典型的仓储模式: +1. **应用服务层** (`DataSourceAppService`): 提供`GetListAsync`和`GetByIdAsync`等异步API。 +2. **领域服务层** (`DataSourceDomainService`): 作为中介,调用仓储层。 +3. **仓储层** (`DataSourceFileRepository`): 从文件系统异步读取JSON文件,并反序列化为`DataSourceSchema`对象。 + +```mermaid +sequenceDiagram +participant UI as "用户界面" +participant AppService as "DataSourceAppService" +participant DomainService as "DataSourceDomainService" +participant Repository as "DataSourceFileRepository" +participant File as "文件系统" +UI->>AppService : GetListAsync(appId) +AppService->>DomainService : GetListAsync(appId) +DomainService->>Repository : GetListAsync(appId) +Repository->>File : 读取所有.json文件 +File-->>Repository : 返回文件内容 +Repository->>Repository : 反序列化为DataSourceSchema +Repository-->>DomainService : 返回数据源列表 +DomainService-->>AppService : 返回数据源列表 +AppService-->>UI : 返回数据源列表 +``` + +**图示来源** +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs) +- [DataSourceDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\DataSourceDomainService.cs) +- [DataSourceFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\DataSourceFileRepository.cs) + +### **组件绑定与刷新** +在渲染引擎中,数据源通过`RenderEngineDynamicComponentBase`类绑定到组件上。 +- **绑定**: 在组件的渲染树构建过程中,通过`builder.AddAttribute()`方法将数据源对象作为属性传递给组件。 +- **刷新**: 当数据源内容更新时,组件会重新渲染,从而展示最新数据。 + +```csharp +// 伪代码示例:在组件中绑定数据源 +if (dataSource.DataSourceGroupType == ComponentDataSourceGroupTypeEnum.Table) +{ + builder.AddAttribute(index++, "DataSource", component.DataSource); +} +``` + +**本节来源** +- [DataSourceFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\DataSourceFileRepository.cs) +- [DataSourceDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\DataSourceDomainService.cs) +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs) +- [RenderEngineDynamicComponentBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\RenderEngineDynamicComponentBase.cs) + +## 设计与渲染引擎策略 + +### **设计引擎:测试连接与错误处理** +在设计引擎中,虽然当前代码未实现完整的“测试连接”功能,但其架构已为此功能预留了空间。 +- **错误处理**: 代码中使用了`ArgumentNullException`和`ArgumentException`等异常来处理无效输入,确保数据完整性。 +- **未来扩展**: 可以在`DataSourceAppService`中添加`TestConnectionAsync`方法,该方法会根据数据源类型(API、SQL)发起实际的连接测试,并返回结果。 + +### **渲染引擎:缓存与安全调用** +在渲染引擎中,数据源的调用策略侧重于性能和安全。 +- **缓存策略**: 当前实现直接从文件系统读取,未使用内存缓存。在生产环境中,可以引入内存缓存(如`IMemoryCache`)来存储频繁访问的数据源,减少I/O开销。 +- **安全调用**: 代码通过以下方式确保安全: + 1. **空值检查**: 在访问数据源或其属性前,会进行`null`检查,防止空引用异常。 + 2. **类型安全**: 使用`Type.GetType()`动态加载组件类型时,会进行空值检查并抛出明确的异常。 + 3. **参数验证**: 在保存数据源时,会验证`Id`等关键字段是否为空。 + +```mermaid +flowchart TD +Start([开始渲染组件]) --> CheckDS["检查数据源是否为空"] +CheckDS --> |是| End([结束]) +CheckDS --> |否| CheckGroup["检查数据源分组类型"] +CheckGroup --> |Option| RenderOption["渲染选项数据源"] +CheckGroup --> |Table| AddAttr["添加DataSource属性"] +AddAttr --> End +RenderOption --> CheckFixed["检查固定选项数据源"] +CheckFixed --> |为空| End +CheckFixed --> |不为空| Loop["遍历每个选项"] +Loop --> CreateComp["创建子组件"] +CreateComp --> SetAttr["设置子组件属性 (Value, Label)"] +SetAttr --> CloseComp["关闭组件"] +CloseComp --> Loop +``` + +**图示来源** +- [RenderEngineDynamicComponentBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\RenderEngineDynamicComponentBase.cs) +- [DesignEngineDynamicComponentBase.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\DesignEngineDynamicComponentBase.cs) + +**本节来源** +- [DataSourceFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\DataSourceFileRepository.cs) +- [RenderEngineDynamicComponentBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\RenderEngineDynamicComponentBase.cs) +- [DesignEngineDynamicComponentBase.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\DesignEngineDynamicComponentBase.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\346\240\270\345\277\203\346\246\202\345\277\265.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\346\240\270\345\277\203\346\246\202\345\277\265.md" new file mode 100644 index 0000000000000000000000000000000000000000..e765f2f9d17e7ab67c82bf99077280f35703f426 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\346\240\270\345\277\203\346\246\202\345\277\265.md" @@ -0,0 +1,313 @@ +# 核心概念 + + +**本文档引用文件** +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) +- [0lgu6xpop.json](file://meta/apps/caseapp/page/0lgu6xpop.json) + + +## 目录 +1. [元数据(Meta)](#元数据meta) +2. [应用(App)](#应用app) +3. [页面(Page)](#页面page) +4. [组件(Component)](#组件component) +5. [数据源(DataSource)](#数据源datasource) +6. [菜单(Menu)](#菜单menu) +7. [核心概念协同机制](#核心概念协同机制) + +## 元数据(Meta) + +元数据是低代码平台的核心驱动机制,系统通过结构化的JSON配置文件定义应用的全部行为与界面,实现无代码配置化开发。所有功能模块(如应用、页面、组件等)均通过元数据进行描述和实例化,平台运行时解析这些元数据并动态渲染UI与逻辑。 + +元数据以分层结构组织,存储于`meta`目录下,按应用划分。每个元数据文件对应一个实体(如应用、页面、数据源等),通过唯一ID进行关联。 + +## 应用(App) + +应用是低代码系统的顶层容器,代表一个独立的业务系统或功能模块。它包含多个页面、菜单、数据源等资源,并定义其全局属性。 + +### 应用元数据结构 + +应用的元数据模型由`AppSchemaBase`类定义,继承自`MetaSchemaBase`,其核心属性如下: + +```csharp +public abstract class AppSchemaBase : MetaSchemaBase +{ + public string Id { get; set; } + [JsonPropertyName("n")] + public string Name { get; set; } + public string Icon { get; set; } + [JsonPropertyName("pic")] + public string Picture { get; set; } + [JsonPropertyName("desc")] + public string Description { get; set; } + [JsonPropertyName("v")] + public string Version { get; set; } + [JsonPropertyName("pub")] + public PublishStatusEnum PublishStatus { get; set; } + [JsonPropertyName("platform")] + public SupportPlatformEnum[] SupportPlatforms { get; set; } = [0]; +} +``` + +### 应用实例:用例系统 + +以`caseapp.json`为例,其内容如下: + +```json +{ + "id": "caseapp", + "n": "用例系统", + "desc": "展示典型页面案例 (参考 amis 示例)", + "platform": [0, 2], + "mt": "2025-05-29T16:49:31.1628431Z" +} +``` + +- **id**: `caseapp`,应用唯一标识符。 +- **n**: `用例系统`,应用名称。 +- **desc**: 应用描述,说明其用途。 +- **platform**: 支持平台,`[0, 2]`表示支持Web和移动端。 +- **mt**: 最后修改时间。 + +**Section sources** +- [caseapp.json](file://meta/apps/caseapp/caseapp.json#L1-L5) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs#L1-L29) + +## 页面(Page) + +页面是用户界面的基本单元,代表一个可访问的视图或功能界面。一个应用可包含多个页面,支持多种类型,如表单、列表、报表、仪表盘等。 + +### 页面元数据结构 + +页面的元数据模型由`PageSchemaBase`类定义: + +```csharp +public abstract class PageSchemaBase : MetaSchemaBase +{ + [JsonPropertyName("aid")] + public string AppId { get; set; } + [JsonPropertyName("id")] + public string Id { get; set; } + [JsonPropertyName("n")] + public string Name { get; set; } + [JsonPropertyName("order")] + public int Order { get; set; } + [JsonPropertyName("pt")] + public PageTypeEnum PageType { get; set; } + [JsonPropertyName("pub")] + public int PublishStatus { get; set; } + [JsonPropertyName("pageprop")] + public PagePropertySchema PageProperty { get; set; } + [JsonPropertyName("ds")] + public PageDataSourceSchema DataSource { get; set; } + [JsonPropertyName("evs")] + public IList Events { get; set; } +} +``` + +### 页面实例:地图页面 + +以`0lgu6xpop.json`为例: + +```json +{ + "aid": "caseapp", + "id": "0lgu6xpop", + "n": "地图", + "order": 82, + "pt": 0, + "pub": 0, + "comps": [], + "pageprop": { "playout": 2 }, + "ds": { + "type": 0, + "fields": [], + "options": [], + "createdTime": "0001-01-01T00:00:00", + "modifiedTime": "0001-01-01T00:00:00" + }, + "i18n": {}, + "createdTime": "0001-01-01T00:00:00", + "modifiedTime": "2024-09-12T13:28:30.4945123Z" +} +``` + +- **aid**: 所属应用ID,`caseapp`。 +- **id**: 页面唯一ID,`0lgu6xpop`。 +- **n**: 页面名称,`地图`。 +- **order**: 排序序号,用于菜单排序。 +- **pt**: 页面类型,`0`表示普通页面。 +- **pub**: 发布状态,`0`表示未发布。 +- **pageprop**: 页面属性,`playout: 2`可能表示布局类型。 +- **ds**: 页面级数据源配置。 + +**Section sources** +- [0lgu6xpop.json](file://meta/apps/caseapp/page/0lgu6xpop.json#L1-L1) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs#L1-L40) + +## 组件(Component) + +组件是可复用的UI元素,如按钮、输入框、表格、图表等。它们是构建页面的基本“积木”,支持属性、样式和事件的可视化配置。 + +### 组件元数据结构 + +组件的元数据模型由`ComponentSchemaBase`类定义: + +```csharp +public abstract class ComponentSchemaBase : StateHasChangeSchema +{ + [JsonPropertyName("id")] + public string Id { get; set; } + [JsonPropertyName("pid")] + public string ParentId { get; set; } + [JsonPropertyName("n")] + public string Name { get; set; } + [JsonPropertyName("lb")] + public string Label { get; set; } + [JsonPropertyName("hlb")] + public bool IsHiddenLabel { get; set; } + [JsonPropertyName("container")] + public bool IsContainer { get; set; } + [JsonPropertyName("sptds")] + public bool IsSupportDataSource { get; set; } + [JsonPropertyName("stl")] + public ComponentStyleSchema Style { get; set; } + [JsonPropertyName("evs")] + public IList Events { get; set; } + [JsonPropertyName("evcs")] + public IList EventConsumes { get; set; } + [JsonPropertyName("desc")] + public string Description { get; set; } +} +``` + +关键属性说明: +- **Id/ParentId**: 构建组件树结构。 +- **IsContainer**: 标识是否为容器组件(可包含子组件)。 +- **Style**: 组件样式配置。 +- **Events**: 组件事件(如点击、变更)的定义。 +- **EventConsumes**: 事件消费配置,用于跨组件通信。 + +**Section sources** +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs#L1-L78) + +## 数据源(DataSource) + +数据源是系统与数据连接的抽象层,用于定义页面或组件所需的数据来源。支持多种类型,实现数据与界面的解耦。 + +### 数据源元数据结构 + +数据源的元数据模型由`DataSourceSchema`类定义: + +```csharp +public class DataSourceSchema : MetaSchemaBase +{ + [JsonPropertyName("aid")] + public string AppId { get; set; } + public string Id { get; set; } + [JsonPropertyName("n")] + public string Name { get; set; } + [JsonPropertyName("disn")] + public string DisplayName { get; set; } + [JsonPropertyName("type")] + public ComponentDataSourceTypeEnum DataSourceType { get; set; } + + #region DataSourceType=Table + [JsonPropertyName("fields")] + public IList TableFields { get; set; } + #endregion + + #region DataSourceType=API + [JsonPropertyName("api")] + public APIDataSourceSchema API { get; set; } + #endregion + + #region DataSourceType=Option + [JsonPropertyName("ops")] + public OptionDataSourceSchema[] Options { get; set; } + [JsonPropertyName("vals")] + public IDictionary Values { get; set; } + #endregion +} +``` + +支持的数据源类型包括: +- **Table**: 数据库表结构,通过`TableFields`定义字段。 +- **API**: 外部API接口,通过`API`对象配置请求方式、URL、参数等。 +- **Option**: 静态选项或字典数据,用于下拉框等组件,通过`Options`或`Values`定义键值对。 + +**Section sources** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs#L1-L70) + +## 菜单(Menu) + +菜单是系统的导航结构,组织应用内的页面访问路径,支持多级树形结构。 + +### 菜单元数据结构 + +菜单的元数据模型由`MenuSchema`类定义: + +```csharp +public class MenuSchema : MetaSchemaBase +{ + [JsonPropertyName("aid")] + public string AppId { get; set; } + public string Id { get; set; } + [JsonPropertyName("pid")] + public string ParentId { get; set; } + [JsonPropertyName("t")] + public string Title { get; set; } + [JsonPropertyName("type")] + public int MenuType { get; set; } // 0-菜单 1-目录 + public string Icon { get; set; } + [JsonPropertyName("path")] + public string MenuUrl { get; set; } + public int Order { get; set; } + [JsonPropertyName("childs")] + public IList Childrens { get; set; } +} +``` + +- **MenuType**: 区分菜单项(链接到页面)和目录(仅作为分组容器)。 +- **MenuUrl**: 菜单对应的页面路由。 +- **Childrens**: 子菜单列表,实现树形结构。 + +**Section sources** +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs#L1-L39) + +## 核心概念协同机制 + +低代码平台的各个核心概念通过元数据协同工作,形成一个完整的无代码开发体系: + +1. **应用(App)** 作为顶层容器,定义了系统的全局信息。 +2. **菜单(Menu)** 基于应用构建导航结构,将用户引导至特定**页面(Page)**。 +3. **页面(Page)** 作为UI容器,通过`comps`数组引用多个**组件(Component)**,构建用户界面。 +4. **组件(Component)** 通过配置**数据源(DataSource)** 获取数据,实现动态内容展示。 +5. 所有实体的元数据均以JSON文件形式存储,由平台统一加载、解析和渲染。 + +这种基于元数据的架构实现了: +- **配置化开发**:无需编写代码,通过修改JSON即可改变系统行为。 +- **高可维护性**:所有配置集中管理,易于版本控制和迁移。 +- **动态性**:运行时可动态加载不同应用的元数据,实现插件化。 + +```mermaid +graph TD +A[应用 App] --> M[菜单 Menu] +A --> P[页面 Page] +A --> D[数据源 DataSource] +P --> C[组件 Component] +C --> D +M --> P +``` + +**Diagram sources** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs#L1-L29) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs#L1-L39) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs#L1-L40) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs#L1-L78) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs#L1-L70) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\347\273\204\344\273\266\357\274\210Component\357\274\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\347\273\204\344\273\266\357\274\210Component\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..03e57a3d60a84fd4806a2b4ef6fbd8ffbddb5eca --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\347\273\204\344\273\266\357\274\210Component\357\274\211.md" @@ -0,0 +1,517 @@ +# 组件(Component) + + +**本文档引用的文件** +- [ComponentSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\ComponentSchemaBase.cs) +- [ComponentAttributeDefineSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\ComponentAttributeDefineSchemaBase.cs) +- [ComponentStyleSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\ComponentStyleSchema.cs) +- [EventSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\EventSchema.cs) +- [EventTargetTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\EventTargetTypeEnum.cs) +- [52391a70.json](file://meta\parts\componentParts\antdesign\52391a70.json) +- [DragDropStateService.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\Services\DragDropStateService.cs) +- [ComponentPartsAttributeDefineSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentPartsAttributeDefineSchema.cs) +- [ComponentPartsStyleSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentPartsStyleSchema.cs) +- [ComponentDesignStateSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentDesignStateSchema.cs) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs) + + +## 目录 +1. [组件系统概述](#组件系统概述) +2. [组件基础结构](#组件基础结构) +3. [属性与样式配置模型](#属性与样式配置模型) +4. [事件绑定与触发机制](#事件绑定与触发机制) +5. [实际配置示例分析](#实际配置示例分析) +6. [设计时拖拽行为](#设计时拖拽行为) +7. [运行时渲染流程](#运行时渲染流程) +8. [总结](#总结) + +## 组件系统概述 + +本系统中的“组件”是低代码平台中可复用的UI元素,其设计遵循模块化、可配置和可扩展的原则。组件在设计时通过元数据定义其结构、属性、样式和事件,在运行时根据配置动态渲染。系统通过分层架构将设计时与运行时逻辑分离,确保灵活性与性能。 + +组件的核心实现基于 `ComponentSchemaBase` 类,并通过设计时专用的 `ComponentPartsSchema` 扩展支持拖拽、选中状态等交互功能。属性、样式和事件均采用独立的模式进行管理,便于动态配置与持久化。 + +**组件系统的关键特性包括:** +- 基于ID的唯一标识与父子层级结构 +- 支持容器与非容器组件的区分 +- 动态属性与样式配置 +- 事件绑定支持标准动作与自定义脚本 +- 设计时拖拽状态管理 +- 元数据驱动的渲染机制 + +## 组件基础结构 + +所有组件均继承自 `ComponentSchemaBase` 类,该类定义了组件的通用结构,包括ID、类型、属性、样式和事件等核心字段。 + +```csharp +public abstract class ComponentSchemaBase : StateHasChangeSchema +{ + [JsonPropertyName("id")] + public string Id { get; set; } = ShortIdGenerator.Generate(); + + [JsonPropertyName("pid")] + public string ParentId { get; set; } + + [JsonPropertyName("n")] + public string Name { get; set; } + + [JsonPropertyName("lb")] + public string Label { get; set; } + + [JsonPropertyName("hlb")] + public bool IsHiddenLabel { get; set; } + + [JsonPropertyName("container")] + public bool IsContainer { get; set; } + + [JsonPropertyName("sptds")] + public bool IsSupportDataSource { get; set; } + + [JsonPropertyName("stl")] + public ComponentStyleSchema Style { get; set; } = new(); + + [JsonPropertyName("evs")] + public IList Events { get; set; } + + [JsonPropertyName("evcs")] + public IList EventConsumes { get; set; } + + [JsonPropertyName("desc")] + public string Description { get; set; } +} +``` + +### 核心字段说明 + +:Id: 组件实例的唯一标识符,使用短ID生成器生成。 +:ParentId: 父组件ID,用于构建组件树结构。 +:Name: 组件名称,通常对应框架中的组件类型(如 `Input`)。 +:Label: 显示标签,用于在设计器中标识组件。 +:IsContainer: 是否为容器组件,容器可包含子组件。 +:IsSupportDataSource: 是否支持数据源绑定,容器组件默认不支持。 +:Style: 组件样式配置,类型为 `ComponentStyleSchema`。 +:Events: 事件列表,包含绑定的事件及其处理逻辑。 +:EventConsumes: 事件消费列表,用于声明组件可触发的事件。 +:Description: 组件描述信息。 + +**组件基础结构类图** + +```mermaid +classDiagram +class ComponentSchemaBase { ++string Id ++string ParentId ++string Name ++string Label ++bool IsHiddenLabel ++bool IsContainer ++bool IsSupportDataSource ++ComponentStyleSchema Style ++IList~EventSchema~ Events ++IList~EventConsumeSchema~ EventConsumes ++string Description +} +class ComponentStyleSchema +class EventSchema +class EventConsumeSchema +ComponentSchemaBase --> ComponentStyleSchema : "包含" +ComponentSchemaBase --> EventSchema : "包含多个" +ComponentSchemaBase --> EventConsumeSchema : "包含多个" +``` + +**图示来源** +- [ComponentSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\ComponentSchemaBase.cs) + +**本节来源** +- [ComponentSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\ComponentSchemaBase.cs) + +## 属性与样式配置模型 + +组件的属性与样式采用独立的配置模型,支持动态定义与运行时修改。 + +### 属性定义模型 + +组件属性由 `ComponentAttributeDefineSchemaBase` 定义,其设计时实现为 `ComponentPartsAttributeDefineSchema`。 + +```csharp +public abstract class ComponentAttributeDefineSchemaBase +{ + [JsonPropertyName("attrn")] + public string AttributeName { get; set; } + + [JsonPropertyName("attrt")] + public string AttributeClrType { get; set; } + + [JsonPropertyName("attrv")] + public object AttributeValue { get; set; } +} +``` + +设计时扩展类 `ComponentPartsAttributeDefineSchema` 增加了显示名称、类型、是否必填、默认值等元信息: + +:DisplayName: 属性在设计器中的显示名称。 +:AttributeItemType: 属性类型,决定设计器中渲染的控件类型(如开关、输入框等)。 +:IsRequired: 是否为必填项。 +:DefaultValue: 默认值。 +:Options: 可选项,用于下拉框等控件。 +:StringValue/IntValue/BoolValue: 提供类型安全的访问器。 + +**属性配置类图** + +```mermaid +classDiagram +class ComponentAttributeDefineSchemaBase { ++string AttributeName ++string AttributeClrType ++object AttributeValue +} +class ComponentPartsAttributeDefineSchema { ++string DisplayName ++ComponentAttributeItemTypeEnum AttributeItemType ++bool IsRequired ++object DefaultValue ++Dictionary~string, object~ Options ++string StringValue ++int IntValue ++bool BoolValue +} +ComponentPartsAttributeDefineSchema --|> ComponentAttributeDefineSchemaBase : "继承" +``` + +**图示来源** +- [ComponentAttributeDefineSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\ComponentAttributeDefineSchemaBase.cs) +- [ComponentPartsAttributeDefineSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentPartsAttributeDefineSchema.cs) + +### 样式配置模型 + +组件样式由 `ComponentStyleSchema` 定义,包含布局与外观相关属性: + +:ItemWidth: 组件宽度(4-24栅格系统)。 +:ItemHeight: 组件高度(像素)。 +:LabelWidth: 标签宽度(像素)。 +:DefaultStyle: 默认CSS样式。 +:CustomStyle: 自定义CSS样式。 + +设计时使用 `ComponentPartsStyleSchema`,字段基本一致,部分字段为可空类型以支持继承。 + +```csharp +public class ComponentPartsStyleSchema +{ + public double? ItemWidth { get; set; } + public double ItemHeight { get; set; } = 85; + public double LabelWidth { get; set; } = 180; + public string Display { get; set; } = "inline"; + public string Position { get; set; } = "static"; + public string DefaultStyle { get; set; } + public string CustomStyle { get; set; } +} +``` + +**本节来源** +- [ComponentAttributeDefineSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\ComponentAttributeDefineSchemaBase.cs) +- [ComponentPartsAttributeDefineSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentPartsAttributeDefineSchema.cs) +- [ComponentStyleSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\ComponentStyleSchema.cs) +- [ComponentPartsStyleSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentPartsStyleSchema.cs) + +## 事件绑定与触发机制 + +组件事件通过 `EventSchema` 类进行定义,支持标准事件与自定义脚本两种处理方式。 + +```csharp +public class EventSchema +{ + [JsonPropertyName("en")] + public string EventName { get; set; } + + [JsonPropertyName("eht")] + public EventTargetTypeEnum EventHandlerType { get; set; } + + // 标准事件 + [JsonPropertyName("etid")] + public string EventTargetId { get; set; } + + [JsonPropertyName("eta")] + public string EventTargetAction { get; set; } + + // 自定义事件 + [JsonPropertyName("ecl")] + public EventCustomLanguageEnum EventCustomLanguage { get; set; } + + [JsonPropertyName("ecs")] + public string EventCustomScript { get; set; } + + public IDictionary EventArgs { get; set; } +} +``` + +### 事件类型枚举 + +`EventTargetTypeEnum` 定义了事件的处理目标类型: + +:None: 无处理。 +:Page: 页面级操作(如跳转、刷新)。 +:Component: 组件级操作(如触发组件方法)。 +:Custom: 执行自定义脚本。 + +`EventCustomLanguageEnum` 支持多种脚本语言: + +:JavaScript: JavaScript脚本。 +:Python: Python脚本。 +:CSharp: C#脚本。 + +### 事件处理流程 + +1. 用户在UI上触发事件(如点击按钮)。 +2. 系统查找该组件绑定的 `EventSchema`。 +3. 根据 `EventHandlerType` 分支处理: + - 若为 `Page` 或 `Component`,执行预定义动作。 + - 若为 `Custom`,执行 `EventCustomScript` 中的脚本。 +4. 传递 `EventArgs` 作为参数。 + +**事件机制序列图** + +```mermaid +sequenceDiagram +participant User as "用户" +participant Component as "组件" +participant EventSystem as "事件系统" +participant Target as "目标页面/组件" +participant ScriptEngine as "脚本引擎" +User->>Component : 触发事件如点击 +Component->>EventSystem : 发布事件 +EventSystem->>EventSystem : 查找EventSchema +alt 标准事件 +EventSystem->>Target : 执行目标动作 +Target-->>EventSystem : 动作结果 +else 自定义事件 +EventSystem->>ScriptEngine : 执行脚本 +ScriptEngine-->>EventSystem : 脚本结果 +end +EventSystem-->>Component : 处理完成 +Component-->>User : 反馈 +``` + +**图示来源** +- [EventSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\EventSchema.cs) +- [EventTargetTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\EventTargetTypeEnum.cs) + +**本节来源** +- [EventSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\EventSchema.cs) +- [EventTargetTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\EventTargetTypeEnum.cs) + +## 实际配置示例分析 + +以 `antdesign` 组件库中的输入框组件为例,其元数据文件 `52391a70.json` 定义了该组件的完整配置。 + +```json +{ + "cn": "Input", + "ct": 1, + "frag": { + "dt": "AntDesign.Input`1[System.String], AntDesign", + "valt": "System.String", + "attrs": [ + { + "attrn": "TValue", + "attrt": "System.String" + } + ] + }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "pt": 2, + "disn": "最大长度", + "desc": "字段输入的最大长度,为0时表示不限制长度", + "dftval": 0, + "attrn": "MaxLength", + "attrt": "System.Int32", + "attrv": 0 + }, + { + "pt": 1, + "disn": "输入提示", + "desc": "组件输入时的 Placeholder 提示", + "dftval": "", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "" + } + ] + } + ], + "childs": [], + "sptds": false, + "order": 10, + "pub": 1, + "mt": "2025-02-24T15:36:15.8037414Z", + "id": "cj8ac3m42", + "libid": "antdesign", + "partsId": "52391a70", + "lb": "输入框-A", + "container": false, + "stl": { + "itemh": 85, + "labelw": 180, + "display": "inline", + "pos": "static" + } +} +``` + +### 配置解析 + +:cn: 组件类名,对应 `AntDesign.Input`。 +:frag: 组件片段信息,包含泛型类型与值类型。 +:attrdefgroups: 属性定义分组,此处为“基础属性”,包含禁用、最大长度、提示文本三个可配置项。 +:stl: 默认样式配置。 +:container: 非容器组件,不可嵌套子组件。 + +该配置表明,设计器在拖拽此组件时,将生成一个 `Input` 组件实例,并提供三个可配置属性。 + +**本节来源** +- [52391a70.json](file://meta\parts\componentParts\antdesign\52391a70.json) + +## 设计时拖拽行为 + +在设计时,组件的拖拽行为由 `DragDropStateService` 服务管理,该服务维护了当前页面的拖拽状态。 + +### 核心状态管理 + +`DragDropStateService` 使用字典存储每个页面的 `DragDropStateSchema`,键为 `appId-pageId`。 + +```csharp +private IDictionary schemaStates = new Dictionary(); +``` + +`DragDropStateSchema` 包含以下关键字段: + +:RootComponent: 页面根组件,构成组件树。 +:LastSelectedComponent: 最后选中的组件。 +:CurrentDragComponent: 当前正在拖拽的组件。 +:LastDragOverComponent: 最后一次悬停的组件。 +:LastDragOverTime: 悬停时间。 + +### 拖拽流程 + +1. 从组件面板拖拽组件时,创建新组件实例并设置为 `CurrentDragComponent`。 +2. 拖拽过程中,实时更新悬停组件(`LastDragOverComponent`)。 +3. 释放时,将组件插入到目标容器的 `Childrens` 列表中。 +4. 更新 `RootComponent` 并触发界面刷新。 + +### 设计状态 + +`ComponentDesignStateSchema` 用于记录组件在设计器中的临时状态: + +:IsSelected: 是否被选中。 +:DragEffectStyle: 拖拽悬停时的视觉效果。 +:IsDroppedFromComponentPanel: 是否为新拖入的组件。 +:AnimationTransform: 动画变换样式(用于平滑让位)。 +:IsAnimating: 是否正在执行动画。 + +这些状态不持久化,仅用于提升设计器交互体验。 + +**拖拽状态服务类图** + +```mermaid +classDiagram +class DragDropStateService { ++GetRootComponent() ++SetRootComponent() ++GetCurrentDragComponent() ++SetCurrentDragComponent() ++FindComponentById() ++ResetDragStyle() +} +class DragDropStateSchema { ++ComponentPartsSchema RootComponent ++ComponentPartsSchema LastSelectedComponent ++ComponentPartsSchema CurrentDragComponent ++ComponentPartsSchema LastDragOverComponent ++DateTime LastDragOverTime +} +class ComponentPartsSchema { ++string Id ++string ParentId ++IList~ComponentPartsSchema~ Childrens ++ComponentPartsStyleSchema Style ++ComponentDesignStateSchema DesignState +} +class ComponentDesignStateSchema { ++bool IsSelected ++string DragEffectStyle ++bool IsDroppedFromComponentPanel ++string AnimationTransform ++bool IsAnimating +} +DragDropStateService --> DragDropStateSchema : "管理" +DragDropStateSchema --> ComponentPartsSchema : "引用" +ComponentPartsSchema --> ComponentDesignStateSchema : "包含" +``` + +**图示来源** +- [DragDropStateService.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\Services\DragDropStateService.cs) +- [ComponentDesignStateSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentDesignStateSchema.cs) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs) + +**本节来源** +- [DragDropStateService.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\Services\DragDropStateService.cs) +- [ComponentDesignStateSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentDesignStateSchema.cs) + +## 运行时渲染流程 + +在运行时,系统根据 `ComponentSchema` 结构动态生成UI。 + +### 渲染流程 + +1. 加载页面元数据,解析 `ComponentSchema` 树。 +2. 遍历组件树,为每个组件创建对应的Blazor组件实例。 +3. 根据 `Style` 应用布局与样式。 +4. 根据 `Events` 绑定事件处理程序。 +5. 将组件挂载到DOM中并渲染。 + +### 组件实例化 + +系统通过反射或工厂模式,根据 `Name` 字段查找对应的组件类型,并传入 `AttributeValue` 进行初始化。 + +例如,`Name: "Input"` 将实例化 `AntDesign.Input` 组件,并设置 `Placeholder`、`MaxLength` 等属性。 + +### 数据流 + +```mermaid +flowchart TD +A["加载页面元数据"] --> B["解析ComponentSchema树"] +B --> C["遍历组件"] +C --> D["创建组件实例"] +D --> E["设置属性与样式"] +E --> F["绑定事件"] +F --> G["渲染到DOM"] +G --> H["用户交互"] +H --> I["触发事件"] +I --> J["执行事件逻辑"] +J --> K["更新状态"] +K --> G +``` + +**本节来源** +- [ComponentSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\ComponentSchemaBase.cs) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs) + +## 总结 + +本文系统性地解析了低代码平台中“组件”的实现机制。组件作为可复用的UI元素,其核心由 `ComponentSchemaBase` 定义,包含ID、类型、属性、样式和事件等通用结构。属性与样式通过独立的模式进行动态配置,支持灵活的UI定制。事件系统支持标准动作与自定义脚本,增强了交互能力。 + +在设计时,`DragDropStateService` 服务管理组件的拖拽、选中等交互状态,提升设计器用户体验。在运行时,系统根据元数据配置动态渲染组件树,实现高效、可扩展的UI生成。 + +该架构实现了设计时与运行时的分离,既保证了开发灵活性,又确保了运行时性能,是低代码平台的核心基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\350\217\234\345\215\225\357\274\210Menu\357\274\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\350\217\234\345\215\225\357\274\210Menu\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..899caefaf067b5969605d2585ce5811475e539d8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\350\217\234\345\215\225\357\274\210Menu\357\274\211.md" @@ -0,0 +1,203 @@ +# 菜单(Menu) + + +**本文档中引用的文件** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [5omcgxevf.json](file://meta\apps\caseapp\menu\5omcgxevf.json) +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) +- [ThemePartLayoutBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\ThemePartLayoutBase.cs) + + +## 目录 +1. [菜单数据结构与属性](#菜单数据结构与属性) +2. [菜单项父子关系与排序逻辑](#菜单项父子关系与排序逻辑) +3. [设计引擎中的可视化编辑流程](#设计引擎中的可视化编辑流程) +4. [渲染引擎中的动态生成与高亮匹配](#渲染引擎中的动态生成与高亮匹配) +5. [多语言支持机制](#多语言支持机制) +6. [权限过滤实现](#权限过滤实现) + +## 菜单数据结构与属性 + +菜单功能的核心数据结构由 `MenuSchema` 类定义,该类继承自 `MetaSchemaBase`,用于描述菜单项的组织方式和行为特性。每个菜单项包含以下关键属性: + +- **AppId (aid)**: 关联的应用ID,标识菜单所属的应用。 +- **Id**: 菜单项的唯一标识符,使用 `ShortIdGenerator.Generate()` 自动生成。 +- **ParentId (pid)**: 父菜单项的ID,用于构建层级结构;若为空,则为根节点。 +- **Title (t)**: 菜单项的显示标题。 +- **MenuType (type)**: 菜单类型,0 表示菜单项,1 表示目录(容器)。 +- **Icon**: 图标名称,用于前端展示。 +- **MenuUrl (path)**: 菜单项对应的路由地址,通常指向一个页面ID。 +- **Order**: 排序序号,决定同级菜单项的显示顺序。 +- **Childrens (childs)**: 子菜单项列表,类型为 `IList`,初始为空列表。 + +```mermaid +classDiagram +class MenuSchema { ++string AppId ++string Id ++string ParentId ++string Title ++int MenuType ++string Icon ++string MenuUrl ++int Order ++IList Childrens +} +``` + +**图示来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs#L5-L37) + +**本节来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs#L5-L37) + +## 菜单项父子关系与排序逻辑 + +菜单项通过 `ParentId` 和 `Childrens` 属性形成树形结构。系统在加载所有菜单项后,通过 `BuildTreeMenus` 方法将其构建成具有父子关系的树。 + +以 `5omcgxevf.json` 文件为例,其内容如下: +```json +{ + "aid": "caseapp", + "id": "5omcgxevf", + "pid": "i7ftaaue", + "t": "多标签页表单", + "type": 0, + "icon": "home", + "path": "gndz2vecz", + "order": 5, + "childs": [] +} +``` +此菜单项的 `pid` 为 `i7ftaaue`,表明它是ID为 `i7ftaaue` 的菜单项的子节点。`order` 值为 5,表示其在同级菜单中的排序位置。 + +`BuildTreeMenus` 方法的逻辑如下: +1. 遍历所有菜单项,建立一个以 `Id` 为键的字典 `menuDic`。 +2. 再次遍历菜单项,如果 `ParentId` 为空,则将其加入根节点列表 `treeMenus`;否则,根据 `ParentId` 在 `menuDic` 中查找父节点,并将当前节点添加到父节点的 `Childrens` 列表中。 +3. 对每个父节点的 `Childrens` 列表按 `Order` 排序。 +4. 最后对根节点列表 `treeMenus` 按 `Order` 排序。 + +```mermaid +flowchart TD +Start([开始]) --> LoadFiles["加载所有菜单JSON文件"] +LoadFiles --> ParseJson["解析JSON为MenuSchema对象"] +ParseJson --> CreateDict["创建Id到MenuSchema的字典"] +CreateDict --> ProcessMenus["遍历处理每个菜单项"] +ProcessMenus --> HasParent{"ParentId是否为空?"} +HasParent --> |是| AddToRoot["添加到根节点列表"] +HasParent --> |否| FindParent["在字典中查找父节点"] +FindParent --> ParentExists{"父节点存在?"} +ParentExists --> |是| AddToChildren["添加到父节点的Childrens列表"] +AddToChildren --> SortChildren["按Order对Childrens排序"] +ParentExists --> |否| ThrowError["抛出KeyNotFoundException"] +AddToRoot --> NextMenu +SortChildren --> NextMenu +NextMenu --> MoreMenus{"还有更多菜单?"} +MoreMenus --> |是| ProcessMenus +MoreMenus --> |否| SortRoot["对根节点列表按Order排序"] +SortRoot --> ReturnTree["返回构建好的树形菜单"] +ReturnTree --> End([结束]) +``` + +**图示来源** +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs#L100-L129) + +**本节来源** +- [5omcgxevf.json](file://meta\apps\caseapp\menu\5omcgxevf.json) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs#L100-L129) + +## 设计引擎中的可视化编辑流程 + +菜单在设计引擎中的增删改查(CRUD)操作由 `MenuAppService` 类提供服务接口。该服务通过依赖注入获取 `IMenuDomainService`,并将其委托给 `MenuDomainService` 进行领域逻辑处理。 + +`MenuAppService` 提供的主要方法包括: +- `GetListAsync(appId)`: 获取指定应用的所有菜单项列表。 +- `GetByIdAsync(appId, menuId)`: 根据ID获取单个菜单项。 +- `SaveAsync(menuSchema)`: 保存或更新一个菜单项。 +- `DeleteAsync(appId, menuId)`: 删除指定的菜单项。 + +`MenuDomainService` 作为领域服务,不包含业务逻辑,仅作为协调者,将请求转发给 `IMenuRepository` 的具体实现。 + +在 `MenuFileRepository` 中,`SaveAsync` 方法将 `MenuSchema` 对象序列化为JSON字符串,并保存到以 `appId` 和 `menuId` 命名的文件中(路径格式为 `{metaBaseDir}\{appId}\menu\{menuId}.json`)。`DeleteAsync` 方法在删除前会检查是否存在子节点,若存在则抛出异常,防止误删。 + +拖拽排序功能在前端实现,用户调整顺序后,系统会更新相关菜单项的 `Order` 字段,并调用 `SaveAsync` 保存所有受影响的菜单项。 + +```mermaid +sequenceDiagram +participant UI as "前端界面" +participant Service as "MenuAppService" +participant Domain as "MenuDomainService" +participant Repo as "MenuFileRepository" +UI->>Service : SaveAsync(menuSchema) +Service->>Domain : SaveAsync(menuSchema) +Domain->>Repo : SaveAsync(menuSchema) +Repo->>Repo : 序列化为JSON +Repo->>Repo : 写入文件系统 +Repo-->>Domain : 完成 +Domain-->>Service : 完成 +Service-->>UI : 返回成功 +``` + +**图示来源** +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs#L20-L35) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs#L20-L28) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs#L50-L65) + +**本节来源** +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +## 渲染引擎中的动态生成与高亮匹配 + +在应用运行时,渲染引擎通过 `ThemePartLayoutBase` 类的 `GetMenusAsync` 方法获取并处理菜单数据。该方法首先调用 `MetaAppService.GetMenusAsync` 从后端获取原始菜单列表。 + +一个关键的处理逻辑是:如果菜单列表中不存在 `MenuUrl` 为 "index" 的项,系统会自动在列表开头插入一个“首页”菜单项,确保应用有一个默认入口。 + +```csharp +protected async Task> GetMenusAsync(string appId) +{ + var menus = await GetMenuListAsync(appId); + string IndexUrl = "index"; + if (menus.Any(t => string.Equals(t.MenuUrl, IndexUrl, StringComparison.OrdinalIgnoreCase)) == false) + { + menus.Insert(0, new MenuSchema + { + MenuUrl = IndexUrl, + Title = "首页", + Id = IndexUrl + }); + } + return menus; +} +``` + +高亮匹配机制通常在前端组件中实现,通过比较当前路由(`NavigationManager.Uri`)与菜单项的 `MenuUrl` 来确定哪个菜单项应被高亮。虽然在提供的代码中未直接体现高亮逻辑,但 `NavigationManager` 已被注入,为实现此功能提供了基础。 + +**本节来源** +- [ThemePartLayoutBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\ThemePartLayoutBase.cs#L20-L38) + +## 多语言支持机制 + +当前代码库中,菜单的 `Title` 字段是一个简单的字符串(`string Title`),并未直接体现多语言支持的复杂机制(如资源文件、本地化服务等)。然而,在 `ThemePartLayoutBase` 中插入“首页”菜单项时,其标题被硬编码为中文 `"首页"`。 + +这表明多语言支持可能在更高层或通过其他机制实现。一种可能的实现方式是:`Title` 字段存储的是一个键(key),前端在渲染时根据当前语言环境从一个全局的翻译字典中查找对应的值。但基于现有代码,更直接的推断是,菜单标题在设计时即被设置为特定语言的文本,多语言切换可能需要维护多套菜单配置或通过外部翻译服务动态处理。 + +**本节来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs#L18) +- [ThemePartLayoutBase.cs](file://src\RenderEngine\H.LowCode.RenderEngine.Abstraction\ThemePartLayoutBase.cs#L30) + +## 权限过滤实现 + +在提供的代码片段中,没有直接实现菜单权限过滤的逻辑。`MenuAppService`、`MenuDomainService` 和 `MenuFileRepository` 都只负责菜单数据的存取,未涉及用户权限的检查。 + +权限控制可能在更高层的应用服务或前端组件中实现。例如,在 `GetListAsync` 返回菜单列表后,另一个服务可能会根据当前用户的权限角色,过滤掉其无权访问的菜单项。或者,权限信息可能作为额外的字段(如 `Roles` 或 `Permissions`)存储在 `MenuSchema` 中,但在当前定义中并未包含此类字段。 + +因此,可以推断权限过滤是一个待实现或在其他模块中实现的功能,当前菜单系统主要关注结构和导航,而将安全控制交由其他组件处理。 + +**本节来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\351\241\265\351\235\242\357\274\210Page\357\274\211.md" "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\351\241\265\351\235\242\357\274\210Page\357\274\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..c3666c753b3d7eb7079f91733f7fdb9c5a6fe92a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\240\270\345\277\203\346\246\202\345\277\265/\351\241\265\351\235\242\357\274\210Page\357\274\211.md" @@ -0,0 +1,296 @@ +# 页面(Page) + + +**本文档中引用的文件** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs) +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs) +- [StateHasChangeSchema.cs](file://src\Common\H.LowCode.MetaSchema\StateHasChangeSchema.cs) +- [EventSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\EventSchema.cs) +- [ComponentSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\ComponentSchemaBase.cs) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs) +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs) +- [PageSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\PageSchema.cs) +- [ComponentSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\ComponentSchema.cs) +- [0lgu6xpop.json](file://meta\apps\caseapp\page\0lgu6xpop.json) + + +## 目录 +1. [引言](#引言) +2. [页面基本结构](#页面基本结构) +3. [页面类型](#页面类型) +4. [页面布局配置](#页面布局配置) +5. [组件树与页面结构](#组件树与页面结构) +6. [事件处理机制](#事件处理机制) +7. [数据源绑定](#数据源绑定) +8. [页面状态管理](#页面状态管理) +9. [设计与渲染引擎中的页面模型](#设计与渲染引擎中的页面模型) +10. [拖拽构建与动态渲染流程](#拖拽构建与动态渲染流程) + +## 引言 +本文档全面介绍低代码平台中“页面”作为用户界面基本单元的建模方式。基于 `PageSchemaBase` 和 `PagePropertySchema` 等核心类,详细解释页面的类型、布局配置、事件处理机制、组件树结构以及状态管理。通过分析 `0lgu6xpop.json` 示例文件,展示页面元数据的实际结构,并阐述页面在设计引擎中的拖拽构建过程和在渲染引擎中的动态加载与渲染流程。 + +## 页面基本结构 + +页面的基本结构由 `PageSchemaBase` 类定义,该类是所有页面模型的基类,包含了页面的核心元数据。 + +```mermaid +classDiagram +class PageSchemaBase { ++string AppId ++string Id ++string Name ++int Order ++PageTypeEnum PageType ++int PublishStatus ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList Events +} +PageSchemaBase <|-- PagePartsSchema +PageSchemaBase <|-- PageSchema +``` + +**图示来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L5-L39) + +**本节来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L5-L39) + +### 核心属性说明 +- **AppId (aid)**: 所属应用的唯一标识符。 +- **Id (id)**: 页面自身的唯一标识符。 +- **Name (n)**: 页面的显示名称。 +- **Order**: 页面在菜单中的排序序号。 +- **PageType (pt)**: 页面类型,枚举值定义了页面的用途。 +- **PublishStatus (pub)**: 发布状态,标记页面是否已发布。 +- **PageProperty (pageprop)**: 页面的属性配置,如布局、样式等。 +- **DataSource (ds)**: 页面级数据源配置。 +- **Events (evs)**: 页面级事件集合。 + +## 页面类型 + +页面类型由 `PageTypeEnum` 枚举定义,用于区分不同功能和用途的页面。 + +```mermaid +classDiagram +class PageTypeEnum { +<> +Normal = 0 +Form = 1 +Table = 2 +Report = 5 +} +``` + +**图示来源** +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs#L9-L19) + +**本节来源** +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs#L9-L19) + +### 类型详解 +- **普通 (Normal)**: 基础的静态页面,用于展示内容或作为容器。 +- **表单 (Form)**: 用于数据录入和编辑的页面,通常包含输入控件和提交逻辑。 +- **列表 (Table)**: 用于展示和管理数据列表的页面,支持分页、搜索和操作。 +- **报表 (Report)**: 用于数据可视化和分析的页面,通常包含图表和统计信息。 + +## 页面布局配置 + +页面的布局配置由 `PagePropertySchema` 类管理,主要控制页面的整体外观和结构。 + +```mermaid +classDiagram +class PagePropertySchema { ++int PageLayout ++string TitleWidth ++string DefaultStyle ++string CustomStyle ++PageDataSourceSchema DataSource +} +``` + +**图示来源** +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs#L5-L36) + +**本节来源** +- [PagePropertySchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\PagePropertySchema.cs#L5-L36) + +### 布局属性说明 +- **PageLayout (playout)**: 页面布局类型,数值代表列数: + - `1`: 一列布局 + - `2`: 二列布局 + - `3`: 三列布局 + - `4`: 四列布局 +- **TitleWidth (titlew)**: 标题区域的宽度设置。 +- **DefaultStyle (dsty)**: 页面的默认样式。 +- **CustomStyle (csty)**: 页面的自定义CSS样式。 + +## 组件树与页面结构 + +页面由一个或多个组件构成,形成一个树状结构。`PagePartsSchema` 类在设计引擎中定义了这一结构。 + +```mermaid +classDiagram +class PagePartsSchema { ++IList Components ++string[] SupportEvents +} +PagePartsSchema --> ComponentPartsSchema : "包含" +ComponentPartsSchema --> ComponentPartsSchema : "子节点" +``` + +**图示来源** +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs#L5-L15) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs#L5-L177) + +**本节来源** +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs#L5-L15) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs#L5-L177) + +### 组件树结构分析 +- **Components (comps)**: 页面的根组件列表,是组件树的起点。 +- **ComponentPartsSchema**: 设计引擎中的组件模型,继承自 `ComponentSchemaBase`,并扩展了设计时所需的属性,如 `Fragment`、`Childrens` 等。 +- **Childrens (childs)**: 每个组件可以包含子组件,形成嵌套的树状结构,实现复杂的UI布局。 + +## 事件处理机制 + +页面和组件的交互行为通过事件机制来处理,`EventSchema` 类定义了事件的结构。 + +```mermaid +classDiagram +class EventSchema { ++string EventName ++EventTargetTypeEnum EventHandlerType ++string EventTargetId ++string EventTargetAction ++EventCustomLanguageEnum EventCustomLanguage ++string EventCustomScript ++IDictionary EventArgs +} +``` + +**图示来源** +- [EventSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\EventSchema.cs#L5-L45) + +**本节来源** +- [EventSchema.cs](file://src\Common\H.LowCode.MetaSchema\PropertySchemas\EventSchema.cs#L5-L45) + +### 事件类型与属性 +事件分为标准事件和自定义事件: +- **标准事件**: + - `EventName`: 触发的事件名称,如 `OnClick`。 + - `EventHandlerType`: 事件处理器类型。 + - `EventTargetId`: 事件目标组件的ID。 + - `EventTargetAction`: 目标组件执行的动作,如 `Navigate`。 + - `EventArgs`: 传递给事件处理器的参数。 +- **自定义事件**: + - `EventCustomLanguage`: 自定义脚本的语言。 + - `EventCustomScript`: 自定义脚本的内容。 + +## 数据源绑定 + +页面和组件可以绑定数据源,以实现动态数据展示。`PageDataSourceSchema` 和 `ComponentPartsDataSourceSchema` 分别管理页面和组件的数据源。 + +**本节来源** +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L32-L33) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs#L29-L30) + +### 数据源配置 +- **PageDataSourceSchema (ds)**: 定义在 `PageSchemaBase` 中,为整个页面提供数据。 +- **ComponentPartsDataSourceSchema (ds)**: 定义在 `ComponentPartsSchema` 中,为单个组件提供数据,支持固定选项、SQL查询、API调用等多种数据源类型。 + +## 页面状态管理 + +页面的状态管理通过 `StateHasChangeSchema` 基类实现,为需要响应状态变化的组件提供基础支持。 + +```mermaid +classDiagram +class StateHasChangeSchema { ++string StateKey ++void ChangeStateKey() +} +StateHasChangeSchema <|-- ComponentSchemaBase +ComponentSchemaBase <|-- PageSchemaBase +``` + +**图示来源** +- [StateHasChangeSchema.cs](file://src\Common\H.LowCode.MetaSchema\StateHasChangeSchema.cs#L6-L15) +- [ComponentSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\ComponentSchemaBase.cs#L5-L77) +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs#L5-L39) + +**本节来源** +- [StateHasChangeSchema.cs](file://src\Common\H.LowCode.MetaSchema\StateHasChangeSchema.cs#L6-L15) + +### 状态管理机制 +- **StateKey**: 一个内部生成的唯一键,用于标识组件的当前状态。 +- **ChangeStateKey()**: 当组件状态发生变化时,调用此方法生成新的 `StateKey`,通知框架进行重新渲染。 + +## 设计与渲染引擎中的页面模型 + +低代码平台采用分离的设计,设计引擎和渲染引擎使用不同的页面模型。 + +```mermaid +classDiagram +class PageSchemaBase { +<> +} +PageSchemaBase <|-- PagePartsSchema +PageSchemaBase <|-- PageSchema +class PagePartsSchema { ++IList Components +} +class PageSchema { ++IList Components +} +class ComponentPartsSchema { +<<设计时模型>> +} +class ComponentSchema { +<<运行时模型>> +} +PagePartsSchema --> ComponentPartsSchema : "使用" +PageSchema --> ComponentSchema : "使用" +``` + +**图示来源** +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs#L5-L15) +- [PageSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\PageSchema.cs#L5-L9) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs#L5-L177) +- [ComponentSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\ComponentSchema.cs#L7-L71) + +**本节来源** +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs#L5-L15) +- [PageSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\PageSchema.cs#L5-L9) +- [ComponentSchema.cs](file://src\Common\H.LowCode.MetaSchema.RenderEngine\ComponentSchema.cs#L7-L71) + +### 模型对比 +- **设计引擎 (PagePartsSchema)**: + - 使用 `ComponentPartsSchema` 作为组件类型。 + - 包含设计时所需的信息,如物料ID、属性定义分组等。 + - 支持拖拽、属性编辑等设计操作。 +- **渲染引擎 (PageSchema)**: + - 使用 `ComponentSchema` 作为组件类型。 + - 是一个精简的、用于运行时渲染的模型。 + - 通过 `MergeAttributeDefineToFragment` 方法将属性定义合并到渲染片段中。 + +## 拖拽构建与动态渲染流程 + +### 拖拽构建流程 +1. 用户从组件面板拖拽一个组件物料。 +2. 设计引擎创建一个 `ComponentPartsSchema` 实例。 +3. 该实例被添加到 `PagePartsSchema` 的 `Components` 树中。 +4. 用户通过属性面板修改组件属性,这些属性存储在 `AttributeDefineGroups` 中。 +5. 修改完成后,页面元数据(如 `0lgu6xpop.json`)被持久化。 + +### 动态渲染流程 +1. 渲染引擎加载页面的JSON元数据。 +2. 将 `PageSchema` 和 `ComponentSchema` 对象反序列化。 +3. 遍历 `Components` 树,为每个组件调用 `RenderComponentRecursive`。 +4. 根据 `Fragment` 中的 `TypeName` 动态创建Blazor组件实例。 +5. 将 `AttributeDefineGroups` 中的属性合并到 `Fragment.Attributes`。 +6. 最终生成完整的UI并呈现给用户。 + +**本节来源** +- [DesignEngineDynamicComponentBase.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\DesignEngineDynamicComponentBase.cs) +- [0lgu6xpop.json](file://meta\apps\caseapp\page\0lgu6xpop.json) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\344\270\273\351\242\230\347\263\273\347\273\237.md" "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\344\270\273\351\242\230\347\263\273\347\273\237.md" new file mode 100644 index 0000000000000000000000000000000000000000..3e6be7c3331eade4c742c9a04fd4cc973d49250e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\344\270\273\351\242\230\347\263\273\347\273\237.md" @@ -0,0 +1,245 @@ +# 主题系统 + + +**本文档引用的文件** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) +- [ContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ContainerComponentRender.razor) +- [FormComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormComponentRender.razor) +- [FormContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormContainerComponentRender.razor) +- [ComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor.css) +- [ContainerComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ContainerComponentRender.razor.css) +- [FormComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormComponentRender.razor.css) +- [FormContainerComponentRender.razor.css](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormContainerComponentRender.razor.css) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档旨在全面解释低代码平台中的主题系统,重点介绍如何通过 `AntBlazorThemeModule` 集成 Ant Design Blazor 组件库并定制用户界面外观。文档将详细说明 `ComponentRender` 组件如何根据元数据动态渲染不同类型的 UI 控件,并应用相应的 CSS 样式。同时,将阐述 `ThemePartLayoutBase` 基类的作用,以及自定义主题如何覆盖默认渲染行为。最后,提供开发自定义主题的步骤、最佳实践和常见问题解决方案。 + +## 项目结构 +项目采用分层架构,主要分为 `meta`(元数据)、`src`(源代码)和 `Tools`(工具)三大目录。`src` 目录下包含多个模块,其中与主题系统直接相关的是 `H.LowCode.Themes.AntBlazor` 模块,它位于 `src/RenderEngine` 目录下,负责 UI 的渲染和主题定制。`H.LowCode.RenderEngine.Abstraction` 模块提供了主题布局的基类。 + +```mermaid +graph TB +subgraph "元数据" +meta[meta] +end +subgraph "源代码" +src[src] +Common[H.LowCode.ComponentBase] +RenderEngine[H.LowCode.RenderEngine] +Themes[H.LowCode.Themes.AntBlazor] +Abstraction[H.LowCode.RenderEngine.Abstraction] +end +subgraph "工具" +Tools[Tools] +end +Themes --> Abstraction +Themes --> RenderEngine +Abstraction --> Common +meta --> Themes +``` + +**Diagram sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) + +**Section sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) + +## 核心组件 +主题系统的核心组件包括 `AntBlazorThemeModule`、`ComponentRender` 及其衍生组件(`ContainerComponentRender`、`FormComponentRender`、`FormContainerComponentRender`),以及基类 `ThemePartLayoutBase`。这些组件共同协作,实现了基于元数据的动态 UI 渲染和主题化。 + +**Section sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) + +## 架构概述 +主题系统的架构围绕着“元数据驱动渲染”的理念构建。`AntBlazorThemeModule` 作为模块入口,负责注册服务和组件映射。`ThemePartLayoutBase` 提供了布局和菜单获取的基础功能。`ComponentRender` 是核心渲染引擎,它根据 `ComponentSchema` 元数据决定渲染哪种具体的 UI 组件(如容器、表单等),并递归地处理子组件。样式通过 Razor 组件的 CSS 文件(`.razor.css`)进行局部作用域管理。 + +```mermaid +sequenceDiagram +participant Module as AntBlazorThemeModule +participant Layout as ThemePartLayoutBase +participant Render as ComponentRender +participant Container as ContainerComponentRender +participant Form as FormComponentRender +participant Meta as MetaAppService +Module->>Module : ConfigureServices() +Layout->>Meta : GetMenusAsync(appId) +Meta-->>Layout : 返回菜单列表 +Render->>Render : OnInitializedAsync() +alt 是容器组件 +Render->>Container : 渲染 ContainerComponentRender +Container->>Render : 为每个子组件调用 ComponentRender +else 是表单组件 +Render->>Form : 渲染 FormComponentRender +Form->>Render : 为每个子组件调用 ComponentRender +else 是普通组件 +Render->>Render : 渲染 div 和 RenderFragment +end +``` + +**Diagram sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs#L12-L18) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs#L11-L43) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor#L1-L60) +- [ContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ContainerComponentRender.razor#L1-L27) +- [FormComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormComponentRender.razor#L1-L54) + +## 详细组件分析 + +### AntBlazorThemeModule 分析 +`AntBlazorThemeModule` 是一个继承自 `AbpModule` 的模块类,它是集成 Ant Design Blazor 库的入口点。目前该类的 `ConfigureServices` 方法为空,但其设计意图是注册主题相关的服务、配置依赖注入容器,并可能注册自定义的组件映射,以将通用的 `ComponentSchema` 映射到具体的 Ant Design Blazor 组件上。 + +```mermaid +classDiagram +class AntBlazorThemeModule { ++ConfigureServices(context) +} +AntBlazorThemeModule --|> AbpModule +``` + +**Diagram sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs#L12-L18) + +**Section sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs#L12-L18) + +### ThemePartLayoutBase 分析 +`ThemePartLayoutBase` 是一个抽象类,继承自 `LowCodeLayoutComponentBase`。它通过依赖注入获取 `IMetaAppService`、`NavigationManager` 和 `IConfiguration`。其主要功能是提供一个 `GetMenusAsync` 方法,该方法调用 `MetaAppService` 获取应用的菜单列表,并确保列表中包含一个默认的“首页”菜单项。这为所有基于此基类的主题布局提供了统一的菜单处理逻辑。 + +```mermaid +classDiagram +class ThemePartLayoutBase { +-IMetaAppService MetaAppService +-NavigationManager NavigationManager +-IConfiguration Configuration ++GetMenusAsync(appId) IList~MenuSchema~ +-GetMenuListAsync(appId) IList~MenuSchema~ +} +ThemePartLayoutBase --|> LowCodeLayoutComponentBase +``` + +**Diagram sources** +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs#L11-L43) + +**Section sources** +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs#L11-L43) + +### ComponentRender 分析 +`ComponentRender` 是一个 Razor 组件,继承自 `RenderEngineDynamicComponentBase`。它是整个渲染系统的核心。它接收一个 `ComponentSchema` 参数,并根据 `Component.IsContainer` 的值决定渲染 `ContainerComponentRender` 还是普通组件的 div 容器。对于普通组件,它会计算宽度和高度,并应用默认和自定义的 CSS 样式。它通过 `Init` 方法初始化 `_renderFragment`,该片段由 `RenderComponent` 方法生成,实现了对具体 UI 控件的渲染。 + +```mermaid +flowchart TD +Start([开始渲染]) --> CheckContainer{"IsContainer?"} +CheckContainer --> |是| RenderContainer[渲染 ContainerComponentRender] +CheckContainer --> |否| RenderDiv[渲染 div 容器] +RenderDiv --> ApplyStyle[应用样式和尺寸] +ApplyStyle --> RenderLabel[渲染标签 (可选)] +RenderLabel --> RenderFragment[渲染 RenderFragment] +RenderFragment --> End([渲染完成]) +``` + +**Diagram sources** +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor#L1-L60) + +**Section sources** +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor#L1-L60) + +### ContainerComponentRender 分析 +`ContainerComponentRender` 专门用于渲染容器类型的组件。它遍历 `ContainerComponent.Childrens` 集合,并为每个子组件创建一个 div 容器,然后在其中递归地调用 `ComponentRender` 组件。这实现了组件树的递归渲染。 + +```mermaid +flowchart TD +A([渲染容器]) --> B{有子组件?} +B --> |否| C([结束]) +B --> |是| D[遍历子组件] +D --> E[为子组件创建 div] +E --> F[调用 ComponentRender] +F --> G[渲染子组件] +G --> H{还有子组件?} +H --> |是| D +H --> |否| C +``` + +**Diagram sources** +- [ContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ContainerComponentRender.razor#L1-L27) + +**Section sources** +- [ContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ContainerComponentRender.razor#L1-L27) + +### FormComponentRender 分析 +`FormComponentRender` 用于渲染表单内的组件。它的结构与 `ComponentRender` 类似,但使用了 Ant Design Blazor 的 `FormItem` 组件来包裹内部内容,这为表单字段提供了统一的布局和验证支持。标签的显示由 `Component.IsHiddenLabel` 控制。 + +```mermaid +flowchart TD +Start([开始渲染表单组件]) --> CheckContainer{"IsContainer?"} +CheckContainer --> |是| RenderFormContainer[渲染 FormContainerComponentRender] +CheckContainer --> |否| RenderFormItem[渲染 FormItem] +RenderFormItem --> ApplyStyle[应用样式和尺寸] +ApplyStyle --> RenderLabel[渲染标签] +RenderLabel --> RenderFragment[渲染 RenderFragment] +RenderFragment --> End([渲染完成]) +``` + +**Diagram sources** +- [FormComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormComponentRender.razor#L1-L54) + +**Section sources** +- [FormComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormComponentRender.razor#L1-L54) + +## 依赖分析 +主题系统内部组件之间存在明确的依赖关系。`ComponentRender` 依赖于 `ContainerComponentRender` 和 `FormComponentRender` 来处理特定类型的组件。`FormComponentRender` 又依赖于 `FormContainerComponentRender`。`ThemePartLayoutBase` 依赖于 `IMetaAppService` 来获取菜单数据。外部依赖包括 Ant Design Blazor 库(通过命名空间引用)和 ABP 框架(用于模块化)。 + +```mermaid +graph TD +A[AntBlazorThemeModule] --> B[ThemePartLayoutBase] +B --> C[IMetaAppService] +A --> D[ComponentRender] +D --> E[ContainerComponentRender] +D --> F[FormComponentRender] +E --> D +F --> G[FormContainerComponentRender] +G --> F +D --> H[RenderComponent] +``` + +**Diagram sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) +- [ContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ContainerComponentRender.razor) +- [FormComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormComponentRender.razor) +- [FormContainerComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/FormContainerComponentRender.razor) + +**Section sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [ThemePartLayoutBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs) +- [ComponentRender.razor](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor) + +## 性能考虑 +由于渲染是递归进行的,对于深度嵌套或包含大量组件的页面,可能会产生性能开销。建议在 `ComponentSchema` 中合理使用 `IsHiddenLabel` 等属性来减少不必要的 DOM 元素。CSS 样式使用了 Razor 组件的局部作用域,避免了全局样式污染,但应确保样式规则的效率。 + +## 故障排除指南 +- **组件未渲染**:检查 `ComponentSchema` 是否正确传递给 `ComponentRender`,并确认 `Component` 参数不为 null。 +- **样式未生效**:检查 `.razor.css` 文件是否与 Razor 组件位于同一目录,并确认类名拼写正确。 +- **菜单不显示**:确认 `IMetaAppService.GetMenusAsync` 方法能正确返回数据,并检查 `ThemePartLayoutBase` 中的逻辑。 +- **循环依赖错误**:避免在 `ComponentRender` 和其子组件之间创建无限递归的调用。 + +## 结论 +本文档详细解析了低代码平台的主题系统。`AntBlazorThemeModule` 提供了集成点,`ThemePartLayoutBase` 定义了布局基础,而 `ComponentRender` 及其家族组件则实现了基于元数据的动态、递归渲染。通过理解这些组件的协作方式,开发者可以创建自定义主题,覆盖默认行为,并实现丰富的 UI 定制。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\345\205\203\346\225\260\346\215\256\351\251\261\345\212\250\346\270\262\346\237\223\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\345\205\203\346\225\260\346\215\256\351\251\261\345\212\250\346\270\262\346\237\223\346\265\201\347\250\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..c17ba92c48445fd630e34a1159a29ff4bb934ca5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\345\205\203\346\225\260\346\215\256\351\251\261\345\212\250\346\270\262\346\237\223\346\265\201\347\250\213.md" @@ -0,0 +1,254 @@ +# 元数据驱动渲染流程 + + +**本文档引用的文件** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [ComponentFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentFragmentSchema.cs) +- [ComponentFragmentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs) +- [LowCodeComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) +- [LowCodePageComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodePageComponentBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档深入讲解低代码平台中元数据驱动的页面构建流程。重点分析渲染引擎如何基于JSON元数据动态生成Blazor组件树,涵盖从元数据获取、解析、组件实例化到属性绑定和事件注册的完整生命周期。文档旨在为开发者提供清晰的技术实现路径和最佳实践指导。 + +## 项目结构 +项目采用分层架构,主要分为元数据(meta)和源代码(src)两大目录。元数据目录存储应用、页面、菜单和组件的JSON定义,而源代码目录则包含实现渲染逻辑的核心类库。 + +```mermaid +graph TB +subgraph "元数据层" +A[meta/apps] --> |应用定义| B[AppSchema] +C[meta/apps/page] --> |页面定义| D[PageSchema] +E[meta/parts] --> |组件部件| F[ComponentParts] +end +subgraph "代码层" +G[src/Common] --> |基类与元数据模型| H[LowCodeComponentBase] +I[src/RenderEngine] --> |渲染服务| J[MetaAppService] +end +J --> |获取| B +J --> |获取| D +H --> |渲染| K[Blazor组件树] +``` + +**Diagram sources** +- [meta/apps](file://meta/apps) +- [src/Common](file://src/Common) +- [src/RenderEngine](file://src/RenderEngine) + +**Section sources** +- [project_structure](file://project_structure) + +## 核心组件 +核心组件包括`MetaAppService`、`PageSchema`、`ComponentSchema`和`LowCodeDynamicComponentBase`。`MetaAppService`负责从存储层获取元数据,`PageSchema`和`ComponentSchema`定义了页面和组件的数据结构,而`LowCodeDynamicComponentBase`则负责将元数据映射为实际的Blazor组件。 + +**Section sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) + +## 架构概述 +系统采用元数据驱动的架构,通过分离设计时(Design Time)和运行时(Runtime)关注点,实现高度灵活的UI构建。设计时通过设计器生成JSON元数据,运行时由渲染引擎解析元数据并动态构建组件树。 + +```mermaid +sequenceDiagram +participant 前端 as 前端(Blazor) +participant 服务 as MetaAppService +participant 存储 as 存储层 +前端->>服务 : GetPageWithDefineAsync(appId, pageId) +服务->>存储 : GetAsync(appId, pageId) +存储-->>服务 : PageSchema (JSON) +服务->>服务 : 合并AttributeDefine到Fragment +服务-->>前端 : PageSchema (含完整Fragment) +前端->>前端 : 解析Components列表 +前端->>前端 : 动态渲染组件树 +``` + +**Diagram sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [IPageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/IPageDomainService.cs) + +## 详细组件分析 + +### MetaAppService 分析 +`MetaAppService`是渲染引擎的应用服务入口,负责协调元数据的获取和预处理。 + +```mermaid +classDiagram +class MetaAppService { ++GetMenusAsync(appId) IList~MenuSchema~ ++GetPageAsync(appId, pageId) PageSchema ++GetPageWithDefineAsync(appId, pageId) PageSchema +-_menuDomainService IMenuDomainService +-_pageDomainService IPageDomainService +} +class IMenuDomainService { +<> ++GetListAsync(appId) Task~IList~MenuSchema~~ +} +class IPageDomainService { +<> ++GetAsync(appId, pageId) Task~PageSchema~ +} +MetaAppService --> IMenuDomainService : "依赖" +MetaAppService --> IPageDomainService : "依赖" +``` + +**Diagram sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [IMenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/IMenuDomainService.cs) +- [IPageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/IPageDomainService.cs) + +**Section sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) + +### 页面与组件元数据分析 +`PageSchema`和`ComponentSchema`构成了元数据模型的核心,定义了页面和组件的结构。 + +```mermaid +classDiagram +class PageSchemaBase { ++string AppId ++string Id ++string Name ++PageTypeEnum PageType ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList~EventSchema~ Events +} +class PageSchema { ++IList~ComponentSchema~ Components +} +class ComponentSchemaBase { ++string Id ++string Name ++string TypeName +} +class ComponentSchema { ++ComponentFragmentSchema Fragment ++ComponentDataSourceSchema DataSource ++ComponentAttributeDefineGroupSchema[] AttributeDefineGroups ++ComponentSchema[] Childrens ++MergeAttributeDefineToFragment() +} +class ComponentFragmentSchemaBase { ++string TypeName ++string ValueType ++ComponentAttributeFragmentSchema[] Attributes ++string Content +} +class ComponentFragmentSchema { ++ComponentFragmentSchema[] ChildFragments ++bool HasChildren +} +PageSchemaBase <|-- PageSchema +ComponentSchemaBase <|-- ComponentSchema +ComponentFragmentSchemaBase <|-- ComponentFragmentSchema +PageSchema --> ComponentSchema : "包含" +ComponentSchema --> ComponentFragmentSchema : "引用" +ComponentSchema --> ComponentAttributeDefineGroupSchema : "引用" +``` + +**Diagram sources** +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [ComponentFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentFragmentSchema.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) + +**Section sources** +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) + +### 动态组件渲染分析 +`LowCodeDynamicComponentBase`是动态渲染的核心,负责将`ComponentFragmentSchema`中的属性映射到实际的Blazor组件。 + +```mermaid +flowchart TD +Start([开始渲染组件]) --> CheckAttrs["检查Attributes数组"] +CheckAttrs --> AttrsEmpty{"Attributes为空?"} +AttrsEmpty --> |是| End([结束]) +AttrsEmpty --> |否| LoopStart["遍历每个Attribute"] +LoopStart --> GetProp["通过反射获取组件属性"] +GetProp --> PropNull{"属性存在?"} +PropNull --> |否| NextAttr["下一个属性"] +PropNull --> |是| CheckType["检查属性类型"] +CheckType --> IsRenderFragment{"类型为RenderFragment?"} +IsRenderFragment --> |是| RenderFragment["创建RenderFragment委托"] +CheckType --> IsEventCallback{"类型为EventCallback?"} +IsEventCallback --> |是| EventCallback["创建事件回调委托"] +CheckType --> SimpleType["转换为实际类型并设置值"] +RenderFragment --> AddAttr["添加到RenderTreeBuilder"] +EventCallback --> AddAttr +SimpleType --> AddAttr +AddAttr --> NextAttr +NextAttr --> LoopEnd{"遍历完成?"} +LoopEnd --> |否| LoopStart +LoopEnd --> |是| End +``` + +**Diagram sources** +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) +- [ComponentAttributeFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs) + +**Section sources** +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) + +## 依赖分析 +系统各组件间存在清晰的依赖关系,遵循依赖倒置原则。 + +```mermaid +graph LR +A[MetaAppService] --> B[IPageDomainService] +A --> C[IMenuDomainService] +B --> D[PageFileRepository] +C --> E[MenuFileRepository] +F[LowCodeDynamicComponentBase] --> G[ComponentAttributeFragmentSchema] +H[PageSchema] --> I[ComponentSchema] +I --> J[ComponentFragmentSchema] +``` + +**Diagram sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [IPageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/IPageDomainService.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) + +**Section sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) + +## 性能考虑 +1. **元数据合并**:`GetPageWithDefineAsync`在服务端完成`AttributeDefine`到`Fragment`的合并,避免了前端重复计算。 +2. **反射优化**:`LowCodeDynamicComponentBase`中使用`GetProperty`进行属性查找,建议在高频率场景下缓存`PropertyInfo`对象。 +3. **JSON序列化**:使用`JsonPropertyName`特性减少序列化后的数据体积。 +4. **懒加载**:`LazyServiceProvider`确保服务实例按需创建。 + +## 故障排除指南 +1. **组件未渲染**:检查`ComponentSchema`的`TypeName`是否正确,确保组件类型在程序集中可被找到。 +2. **属性绑定失败**:确认`ComponentAttributeFragmentSchema`中的`AttributeName`与目标组件的属性名完全匹配(区分大小写)。 +3. **事件不触发**:验证`AttributeValue`是否指向了正确的、可访问的方法名。 +4. **类型转换错误**:检查`AttributeClrType`是否为有效的.NET类型全名。 + +**Section sources** +- [LowCodeDynamicComponentBase.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) + +## 结论 +该低代码平台通过`MetaAppService`获取结构化的`PageSchema`元数据,并利用`LowCodeDynamicComponentBase`的反射机制,实现了从JSON定义到Blazor UI组件的无缝转换。这种元数据驱动的架构极大地提升了UI构建的灵活性和可维护性,为快速应用开发提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\345\255\230\345\202\250\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\345\255\230\345\202\250\345\256\236\347\216\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..760f0ba0eb5afba030685a95b302cbadfb977fe8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\345\255\230\345\202\250\345\256\236\347\216\260.md" @@ -0,0 +1,386 @@ +# 存储实现 + + +**本文档引用文件** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + + +## 目录 +1. [引言](#引言) +2. [三种存储方式概述](#三种存储方式概述) +3. [JsonFile 存储实现](#jsonfile-存储实现) +4. [RemoteService 存储实现](#remoteservice-存储实现) +5. [EntityFrameworkCore 存储实现](#entityframeworkcore-存储实现) +6. [性能与适用场景对比](#性能与适用场景对比) +7. [配置方法与 RepositoryType 设置](#配置方法与-repositorytype-设置) +8. [扩展新的存储实现](#扩展新的存储实现) + +## 引言 + +本文档旨在详细分析低代码平台中三种核心存储实现方式:**JsonFile**、**RemoteService** 和 **EntityFrameworkCore**。通过深入解析其代码结构、应用场景、配置方式及性能特征,帮助开发者理解如何根据实际需求选择合适的存储策略,并支持未来扩展新的数据源类型。 + +## 三种存储方式概述 + +在当前项目架构中,存在三种主要的元数据与应用数据存储机制: + +- **JsonFile**:基于文件系统的本地存储,从 `meta` 目录读取 JSON 文件作为元数据源。 +- **RemoteService**:通过调用远程 API 接口获取和保存数据,适用于分布式或微服务架构。 +- **EntityFrameworkCore**:使用 EF Core 通过 `DbContext` 访问关系型数据库,支持动态实体映射与复杂查询。 + +这三种方式分别适用于不同环境,具有各自的优缺点和扩展性。 + +## JsonFile 存储实现 + +### 基本原理 + +`JsonFile` 存储实现通过读写本地文件系统中的 JSON 文件来持久化元数据。所有应用的元数据(如应用配置、页面、菜单、数据源等)均以 `.json` 文件形式存储在 `meta/apps` 和 `meta/parts` 目录下。 + +#### 核心类:AppFileRepository + +`AppFileRepository` 是 `IAppRepository` 接口的具体实现,负责从文件系统加载和保存 `AppPartsSchema` 对象。 + +```csharp +public class AppFileRepository : FileRepositoryBase, IAppRepository +{ + private static string appFileName_Format = @"{0}\{1}\{2}.json"; + + public AppFileRepository(IOptions metaOption) : base(metaOption) + { + // 初始化元数据根路径 + } + + public async Task> GetListAsync() + { + List appSchemas = []; + var directories = Directory.GetDirectories(_metaBaseDir); + foreach (var directory in directories) + { + DirectoryInfo dirInfo = new(directory); + var fileName = string.Format(appFileName_Format, _metaBaseDir, dirInfo.Name, dirInfo.Name); + if (!File.Exists(fileName)) continue; + + var appSchemaJson = ReadAllText(fileName); + var appSchema = appSchemaJson.FromJson(); + appSchemas.Add(appSchema); + } + return await Task.FromResult(appSchemas); + } + + public async Task GetAsync(string appId) + { + string fileName = string.Format(appFileName_Format, _metaBaseDir, appId, appId); + var appSchemaJson = ReadAllText(fileName); + var appSchema = appSchemaJson.FromJson(); + return await Task.FromResult(appSchema); + } + + public async Task SaveAsync(AppPartsSchema appSchema) + { + string fileName = string.Format(appFileName_Format, _metaBaseDir, appSchema.Id, appSchema.Id); + string fileDirectory = Path.GetDirectoryName(fileName); + if (!Directory.Exists(fileDirectory)) Directory.CreateDirectory(fileDirectory); + + File.WriteAllText(fileName, appSchema.ToJson(), Encoding.UTF8); + await Task.CompletedTask; + } +} +``` + +#### 基类:FileRepositoryBase + +`FileRepositoryBase` 提供了通用的文件读取功能: + +```csharp +protected static string ReadAllText(string fileName) +{ + if (!File.Exists(fileName)) + throw new FileNotFoundException(fileName); + return File.ReadAllText(fileName, Encoding.UTF8); +} +``` + +### 应用场景 + +- **开发环境**:便于快速迭代和调试,无需数据库依赖。 +- **静态部署**:适合内容不频繁变更的低代码应用。 +- **轻量级系统**:无数据库依赖,部署简单。 + +### 配置路径 + +在 `appsettings.json` 中通过 `Meta` 节点指定元数据路径: + +```json +"Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" +} +``` + +### 优点与局限 + +| 特性 | 说明 | +|------|------| +| **优点** | 部署简单、无需数据库、适合静态内容 | +| **缺点** | 并发写入风险、性能随文件数量增长下降、缺乏事务支持 | + +**Section sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L31) + +## RemoteService 存储实现 + +### 基本原理 + +`RemoteService` 存储实现通过 HTTP 调用远程服务获取或提交数据,适用于跨服务共享元数据的场景。 + +#### 核心类:AppRemoteServiceRepository + +```csharp +public class AppRemoteServiceRepository : RemoteServiceRepositoryBase, IAppRepository +{ + public AppRemoteServiceRepository(IOptions metaOption) + { + } + + public Task GetAsync(string appId) + { + throw new NotImplementedException(); + } + + public Task> GetListAsync() + { + throw new NotImplementedException(); + } + + public Task SaveAsync(AppPartsSchema appSchema) + { + throw new NotImplementedException(); + } +} +``` + +> **注意**:当前实现仅为骨架,尚未完成具体远程调用逻辑。 + +### 配置方式 + +在 `appsettings.json` 中配置远程服务地址: + +```json +"RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:5191" + } +} +``` + +### 应用场景 + +- **微服务架构**:多个服务共享同一元数据源。 +- **集中式管理**:通过统一 API 管理所有低代码应用配置。 +- **云原生部署**:与 Kubernetes、Service Mesh 集成。 + +### 优点与局限 + +| 特性 | 说明 | +|------|------| +| **优点** | 支持分布式、可扩展性强、便于集中管理 | +| **缺点** | 网络延迟、依赖服务可用性、需实现完整 API 客户端 | + +**Section sources** +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs#L1-L34) + +## EntityFrameworkCore 存储实现 + +### 基本原理 + +`EntityFrameworkCore` 实现通过 `DesignEngineDbContext` 访问数据库,支持动态实体映射、软删除、字段精度控制等高级特性。 + +#### 核心类:DesignEngineDbContext + +```csharp +public class DesignEngineDbContext : DbContext +{ + private EntityTypeManager _entityTypeManager; + + public DesignEngineDbContext(DbContextOptions options, + EntityTypeManager entityTypeManager) : base(options) + { + _entityTypeManager = entityTypeManager; + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + var dynamicEntities = _entityTypeManager.LoadDynamicEntities(); + for (var i = 0; i < dynamicEntities.Count(); i++) + { + var dynamicEntity = dynamicEntities[i]; + var entityBuilder = modelBuilder.Entity(dynamicEntity.EntityType) + .ToTable(dynamicEntity.EntityName); + ConfigureProperties(entityBuilder, dynamicEntity, dynamicEntity.EntityType); + entityBuilder.HasKey(dynamicEntity.PrimaryKey); + if (dynamicEntity.EnableSoftDelete) + { + modelBuilder.Entity(dynamicEntity.EntityType, eb => + { + eb.HasQueryFilter(SoftDeleteQueryFilterExpression(dynamicEntity.EntityType)); + }); + } + } + } + + private void ConfigureProperties(EntityTypeBuilder entityBuilder, DynamicEntityInfo dynamicEntity, Type entityType) + { + foreach (var field in dynamicEntity.Fields) + { + PropertyBuilder propertyBuilder = entityBuilder.Property(field.ClrType, field.Name); + if (field.ClrType == typeof(string)) + { + propertyBuilder.HasMaxLength(field.MaxLength ?? 50); + propertyBuilder.IsUnicode(field.IsUnicode ?? true); + } + else if (field.ClrType == typeof(decimal)) + { + propertyBuilder.HasPrecision(field.Precision ?? 12, field.Scale ?? 2); + } + if (!field.IsNullable) propertyBuilder.IsRequired(); + if (field.DefaultValue != null) propertyBuilder.HasDefaultValue(field.DefaultValue); + } + } +} +``` + +### 动态实体支持 + +通过 `EntityTypeManager` 加载运行时定义的实体类型,实现无需编译的表结构变更。 + +### 数据库配置 + +```json +"ConnectionStrings": { + "Default": "Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Trusted_Connection=True;TrustServerCertificate=True" +} +``` + +### 应用场景 + +- **生产环境**:需要高并发、事务支持、数据一致性的场景。 +- **复杂业务系统**:涉及多表关联、复杂查询的应用。 +- **企业级部署**:要求高可用、可监控、可备份的系统。 + +### 优点与局限 + +| 特性 | 说明 | +|------|------| +| **优点** | 强大的 ORM 支持、事务安全、高性能查询、支持复杂模型 | +| **缺点** | 部署复杂、需要数据库维护、学习成本较高 | + +```mermaid +classDiagram +class DesignEngineDbContext { ++string AppId ++Task~bool~ AddAsync(FormEntity) ++Task~bool~ UpdateAsync(FormEntity) ++Task~FormEntity~ GetAsync(string, string) ++Type GetEntityType(string) +-void OnModelCreating(ModelBuilder) +-void ConfigureProperties(EntityTypeBuilder, DynamicEntityInfo, Type) +} +class FormEntity { ++string Name ++FormFieldEntity[] Fields +} +class DynamicEntityInfo { ++Type EntityType ++string EntityName ++string PrimaryKey ++bool EnableSoftDelete ++FieldInfo[] Fields +} +class EntityTypeManager { ++IEnumerable~DynamicEntityInfo~ LoadDynamicEntities() +} +DesignEngineDbContext --> FormEntity : "操作" +DesignEngineDbContext --> DynamicEntityInfo : "构建模型" +DesignEngineDbContext --> EntityTypeManager : "依赖" +``` + +**Diagram sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs#L1-L226) + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs#L1-L226) + +## 性能与适用场景对比 + +| 特性 | JsonFile | RemoteService | EntityFrameworkCore | +|------|----------|---------------|---------------------| +| **读取性能** | 快(小文件) | 中(网络延迟) | 快(索引优化) | +| **写入性能** | 慢(文件锁) | 中(网络延迟) | 快(事务批处理) | +| **并发支持** | 差 | 中(依赖服务) | 强 | +| **扩展性** | 低 | 高 | 中 | +| **部署复杂度** | 低 | 中 | 高 | +| **适用环境** | 开发/测试 | 微服务/云原生 | 生产/企业级 | + +## 配置方法与 RepositoryType 设置 + +虽然当前配置文件中未显式定义 `RepositoryType`,但可通过依赖注入模块选择启用的存储实现。 + +### 启用 JsonFile 存储 + +在模块加载时注册 `DesignEngineJsonFileRepositoryModule`: + +```csharp +services.AddLowCode() + .AddRepository(); +``` + +### 启用 RemoteService 存储 + +注册 `DesignEngineRemoteServiceRepositoryModule`: + +```csharp +services.AddLowCode() + .AddRepository(); +``` + +### 启用 EntityFrameworkCore 存储 + +注册 `DesignEngineEntityFrameworkCoreModule` 并配置数据库连接: + +```csharp +services.AddDbContext(options => + options.UseSqlServer(Configuration.GetConnectionString("Default"))); +``` + +## 扩展新的存储实现 + +要支持新的数据源(如 Redis、MongoDB、YAML 文件等),需遵循以下步骤: + +1. **创建新模块项目**:如 `H.LowCode.DesignEngine.Repository.Redis` +2. **继承基础抽象类**:根据场景继承 `FileRepositoryBase` 或新建 `RedisRepositoryBase` +3. **实现接口**:实现 `IAppRepository`, `IPageRepository` 等接口 +4. **注册模块**:提供 `XXXRepositoryModule` 类用于 DI 注册 +5. **配置切换机制**:通过 `appsettings.json` 中的 `RepositoryType` 字段动态选择实现 + +示例结构: + +```csharp +public class AppRedisRepository : RedisRepositoryBase, IAppRepository +{ + public Task GetAsync(string appId) { ... } + public Task> GetListAsync() { ... } + public Task SaveAsync(AppPartsSchema appSchema) { ... } +} +``` + +通过接口抽象与依赖注入,系统具备良好的可扩展性。 + +**Section sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\225\260\346\215\256\350\256\277\351\227\256\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\225\260\346\215\256\350\256\277\351\227\256\346\234\272\345\210\266.md" new file mode 100644 index 0000000000000000000000000000000000000000..72625969aeb0d8cda4c66ba76e8acfa6cb7409e0 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\225\260\346\215\256\350\256\277\351\227\256\346\234\272\345\210\266.md" @@ -0,0 +1,268 @@ +# 数据访问机制 + + +**本文档引用文件** +- [FormDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/FormDataAppService.cs) +- [TableDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/TableDataAppService.cs) +- [FormDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs) +- [TableDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/TableDataDomainService.cs) +- [IFormDataRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataRepositories/IFormDataRepository.cs) +- [ITableDataRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataRepositories/ITableDataRepository.cs) +- [FormDataDTO.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/FormDataDTO.cs) +- [TableGetListInput.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/TableGetListInput.cs) +- [LowCodeAutoMapperProfile.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/MapperProfiles/LowCodeAutoMapperProfile.cs) +- [FormEntity.cs](file://src/Common/H.LowCode.Entity/Base/FormEntity.cs) + + +## 目录 +1. [简介](#简介) +2. [核心组件概览](#核心组件概览) +3. [数据访问服务分析](#数据访问服务分析) +4. [领域服务与仓储协作机制](#领域服务与仓储协作机制) +5. [DTO对象结构与映射规则](#dto对象结构与映射规则) +6. [典型调用流程与异常处理](#典型调用流程与异常处理) +7. [分页与过滤功能展望](#分页与过滤功能展望) +8. [错误排查指南](#错误排查指南) + +## 简介 +本文档详细阐述低代码平台中数据访问层的设计与实现,重点分析`FormDataAppService`和`TableDataAppService`所提供的API接口及其背后业务逻辑。文档涵盖服务如何通过领域服务(DomainService)协调仓储接口(Repository)完成对表单数据和表格数据的增删改查操作。同时,深入解析数据传输对象(DTO)的结构设计、AutoMapper在实体与DTO之间转换的作用机制,并提供典型使用场景与常见问题解决方案。 + +## 核心组件概览 +系统采用分层架构设计,主要包含以下核心组件: +- **应用服务层(AppService)**:对外暴露API接口,处理请求参数与响应封装 +- **领域服务层(DomainService)**:实现核心业务逻辑,协调多个仓储或服务 +- **仓储接口层(Repository)**:定义数据访问契约,屏蔽底层存储细节 +- **数据传输对象(DTO)**:用于服务间数据传递,避免暴露实体细节 + +```mermaid +graph TB +A[客户端] --> B[FormDataAppService] +A --> C[TableDataAppService] +B --> D[FormDataDomainService] +C --> E[TableDataDomainService] +D --> F[IFormDataRepository] +E --> G[ITableDataRepository] +D --> H[IPageDomainService] +``` + +**图示来源** +- [FormDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/FormDataAppService.cs) +- [FormDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs) +- [IFormDataRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataRepositories/IFormDataRepository.cs) + +## 数据访问服务分析 + +### FormDataAppService 接口实现 +`FormDataAppService`实现了`IFormDataAppService`接口,提供表单数据的获取、保存和删除功能。 + +```csharp +public async Task GetAsync(string appId, string pageId, string id) +{ + var entity = await _formDataDomainService.GetAsync(appId, pageId, id); + var dto = ObjectMapper.Map(entity); + return dto; +} + +public async Task SaveAsync(FormDataDTO dto) +{ + var entity = ObjectMapper.Map(dto); + return await _formDataDomainService.SaveAsync(entity); +} + +public async Task DeleteAsync(string appId, string pageId, string id) +{ + return await _formDataDomainService.DeleteAsync(appId, pageId, id); +} +``` + +该服务通过依赖注入获取`FormDataDomainService`实例,并利用`ObjectMapper`完成`FormEntity`与`FormDataDTO`之间的自动转换。 + +**本节来源** +- [FormDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/FormDataAppService.cs) + +### TableDataAppService 接口实现 +当前`TableDataAppService`的`GetList`方法尚未实现,仅抛出`NotImplementedException`异常。 + +```csharp +public async Task GetList(TableGetListInput input) +{ + throw new NotImplementedException(); +} +``` + +`TableGetListInput`输入参数类目前为空,表明分页、过滤等高级功能尚未定义具体结构。 + +**本节来源** +- [TableDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/TableDataAppService.cs) +- [TableGetListInput.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/TableGetListInput.cs) + +## 领域服务与仓储协作机制 + +### FormDataDomainService 业务逻辑 +`FormDataDomainService`负责处理表单数据的核心业务逻辑: + +1. **获取数据**:根据`appId`和`pageId`查询页面元数据,确定实体名称;若`id`为空则返回默认表单结构,否则从仓储中加载具体数据。 +2. **保存数据**:根据实体是否包含`Id`判断为新增或更新操作。 +3. **删除数据**:同样需先获取页面元数据以确定实体名称,再调用仓储执行删除。 + +```csharp +public async Task GetAsync(string appId, string pageId, string id) +{ + var formPageSchema = await _pageDomainService.GetAsync(appId, pageId); + if (formPageSchema == null) + throw new KeyNotFoundException($"page not found: appId={appId}, pageId={pageId}"); + + string entityName = formPageSchema.DataSource.DataSourceValue; + + if (string.IsNullOrEmpty(id)) + { + // 构建默认表单实体 + } + + var entity = await _formDataRepository.GetAsync(entityName, id); + if (entity == null) + throw new EntityNotFoundException($"Entity {entityName} Not Found: {id}"); + + return entity; +} +``` + +**本节来源** +- [FormDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs) + +### IFormDataRepository 数据访问契约 +`IFormDataRepository`定义了表单数据的基本CRUD操作接口: + +- `Task AddAsync(FormEntity entity)`:新增实体 +- `Task UpdateAsync(FormEntity entity)`:更新实体 +- `Task GetAsync(string entityName, string id)`:根据实体名和ID获取数据 +- `Task DeleteAsync(string entityName, string id)`:根据实体名和ID删除数据 + +**本节来源** +- [IFormDataRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataRepositories/IFormDataRepository.cs) + +## DTO对象结构与映射规则 + +### FormDataDTO 结构解析 +`FormDataDTO`是表单数据的主要传输对象,包含以下属性: + +- `Name`:实体名称 +- `Fields`:字段列表(`FormFieldDTO`类型) +- `ValidationRules`:验证规则列表 + +`FormFieldDTO`中`Value`属性具有特殊处理逻辑:通过`TypeName`动态解析实际类型,并使用`ConvertToRealType`方法进行类型转换,确保数据完整性。 + +```csharp +public object Value +{ + get + { + if (string.IsNullOrEmpty(TypeName)) + return new InvalidDataException(...); + + var type = Type.GetType(TypeName); + var realValue = _value.ConvertToRealType(type); + return realValue; + } +} +``` + +**本节来源** +- [FormDataDTO.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/FormDataDTO.cs) + +### AutoMapper 映射配置 +`LowCodeAutoMapperProfile`定义了实体与DTO之间的双向映射关系: + +```csharp +CreateMap(); +CreateMap(); + +CreateMap(); +CreateMap(); +``` + +此配置使得`ObjectMapper.Map()`方法能够自动完成复杂对象的属性映射,极大简化了数据转换代码。 + +**本节来源** +- [LowCodeAutoMapperProfile.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/MapperProfiles/LowCodeAutoMapperProfile.cs) + +## 典型调用流程与异常处理 + +### 表单数据获取流程 +```mermaid +sequenceDiagram +participant Client as 客户端 +participant AppService as FormDataAppService +participant DomainService as FormDataDomainService +participant Repository as IFormDataRepository +participant PageService as IPageDomainService +Client->>AppService : GetAsync(appId, pageId, id) +AppService->>DomainService : GetAsync(appId, pageId, id) +DomainService->>PageService : GetAsync(appId, pageId) +PageService-->>DomainService : PageSchema +alt id为空 +DomainService->>DomainService : 构建默认表单实体 +else 有id +DomainService->>Repository : GetAsync(entityName, id) +Repository-->>DomainService : FormEntity +end +DomainService-->>AppService : FormEntity +AppService->>AppService : Map to FormDataDTO +AppService-->>Client : FormDataDTO +``` + +**图示来源** +- [FormDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/FormDataAppService.cs) +- [FormDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs) + +### 异常处理机制 +系统在关键节点抛出特定异常: +- `KeyNotFoundException`:页面未找到 +- `EntityNotFoundException`:数据实体未找到 +- `InvalidDataException`:类型解析失败或数据无效 + +这些异常由上层框架统一捕获并转换为HTTP错误响应。 + +**本节来源** +- [FormDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs) +- [FormDataDTO.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/FormDataDTO.cs) + +## 分页与过滤功能展望 +当前`TableDataAppService`尚未实现分页与过滤功能。未来应扩展`TableGetListInput`类,添加如下字段: + +```csharp +public class TableGetListInput +{ + public int Page { get; set; } = 1; + public int PageSize { get; set; } = 10; + public string Filter { get; set; } + public string Sort { get; set; } +} +``` + +同时需完善`ITableDataRepository`接口,支持分页查询方法。 + +**本节来源** +- [TableDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/TableDataAppService.cs) +- [TableGetListInput.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/TableGetListInput.cs) + +## 错误排查指南 + +### 常见问题与解决方案 + +| 问题现象 | 可能原因 | 解决方案 | +|--------|--------|--------| +| 获取表单数据时报“page not found” | appId或pageId错误 | 检查前端传递的参数是否正确 | +| 保存数据失败 | 实体Name为空 | 确保DTO中Name字段已赋值,或检查默认赋值逻辑 | +| Value类型转换异常 | TypeName为空或类型不存在 | 检查组件定义中的ValueType配置 | +| 删除操作失败 | 页面元数据无法加载 | 确认页面配置文件存在且格式正确 | + +### 调试建议 +1. 启用日志记录,查看`FormDataDomainService`和`FormDataRepository`的执行轨迹 +2. 使用调试器跟踪`ObjectMapper.Map`调用,确认DTO与实体映射是否正确 +3. 检查`LazyServiceProvider.GetRequiredService()`是否成功解析依赖 + +**本节来源** +- [FormDataDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs) +- [FormDataDTO.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application.Contracts/DataDTOs/FormDataDTO.cs) +- [LowCodeAutoMapperProfile.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/MapperProfiles/LowCodeAutoMapperProfile.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\270\262\346\237\223\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\270\262\346\237\223\345\274\225\346\223\216.md" new file mode 100644 index 0000000000000000000000000000000000000000..a4fdea217f47d517839f477f17508c77355b8a80 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\270\262\346\237\223\345\274\225\346\223\216.md" @@ -0,0 +1,247 @@ +# 渲染引擎 + + +**本文档引用的文件** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [ComponentFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentFragmentSchema.cs) +- [ComponentAttributeDefineSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineSchema.cs) +- [ComponentDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/DataSourceSchemas/ComponentDataSourceSchema.cs) +- [RenderEngineLowCodeComponentBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/RenderEngineLowCodeComponentBase.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) +- [FormDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/FormDataAppService.cs) +- [TableDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/TableDataAppService.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本技术文档深入解析低代码平台中的**渲染引擎**模块,详细阐述其运行时行为与架构设计。渲染引擎的核心职责是从元数据中读取配置,并动态生成用户界面。其设计强调轻量性与高性能,通过元数据驱动的方式实现灵活的UI构建。本文档将从启动流程、页面渲染机制、主题系统、数据访问等方面全面剖析该模块的实现原理,为开发者提供清晰的技术参考。 + +## 项目结构 +渲染引擎模块采用分层架构设计,各子模块职责清晰,共同协作完成UI的动态渲染。其目录结构体现了典型的领域驱动设计(DDD)模式。 + +```mermaid +graph TB +subgraph "src/RenderEngine" +H.LowCode.RenderEngine["H.LowCode.RenderEngine"] +H.LowCode.RenderEngine.Abstraction["H.LowCode.RenderEngine.Abstraction"] +H.LowCode.RenderEngine.Application["H.LowCode.RenderEngine.Application"] +H.LowCode.RenderEngine.Application.Contracts["H.LowCode.RenderEngine.Application.Contracts"] +H.LowCode.RenderEngine.Domain["H.LowCode.RenderEngine.Domain"] +H.LowCode.RenderEngine.EntityFrameworkCore["H.LowCode.RenderEngine.EntityFrameworkCore"] +H.LowCode.RenderEngine.Host["H.LowCode.RenderEngine.Host"] +H.LowCode.RenderEngine.Host.Client["H.LowCode.RenderEngine.Host.Client"] +H.LowCode.RenderEngine.Repository.JsonFile["H.LowCode.RenderEngine.Repository.JsonFile"] +H.LowCode.RenderEngine.Repository.RemoteService["H.LowCode.RenderEngine.Repository.RemoteService"] +H.LowCode.Themes.AntBlazor["H.LowCode.Themes.AntBlazor"] +end +H.LowCode.RenderEngine.Abstraction --> H.LowCode.RenderEngine.Application +H.LowCode.RenderEngine.Application --> H.LowCode.RenderEngine.Domain +H.LowCode.RenderEngine.Domain --> H.LowCode.RenderEngine.EntityFrameworkCore +H.LowCode.RenderEngine.Domain --> H.LowCode.RenderEngine.Repository.JsonFile +H.LowCode.RenderEngine.Domain --> H.LowCode.RenderEngine.Repository.RemoteService +H.LowCode.RenderEngine.Host.Client --> H.LowCode.RenderEngine.Application +H.LowCode.Themes.AntBlazor --> H.LowCode.RenderEngine.Application +``` + +**Diagram sources** +- [RenderEngineModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine/RenderEngineModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + +**中文说明**: +- **H.LowCode.RenderEngine.Abstraction**:定义了渲染引擎的核心抽象基类,如 `RenderEngineLowCodeComponentBase`,为所有动态组件提供基础能力。 +- **H.LowCode.RenderEngine.Application**:应用服务层,包含 `MetaAppService` 等服务,负责协调领域逻辑,提供API接口。 +- **H.LowCode.RenderEngine.Domain**:领域层,包含核心业务逻辑和领域服务,如 `IPageDomainService` 和 `IMenuDomainService`。 +- **H.LowCode.RenderEngine.EntityFrameworkCore**:数据访问层,基于Entity Framework Core实现,负责与数据库交互。 +- **H.LowCode.RenderEngine.Repository.JsonFile** 和 **RemoteService**:两种元数据存储的实现,分别支持从本地JSON文件或远程服务加载元数据。 +- **H.LowCode.Themes.AntBlazor**:主题模块,实现了基于Ant Design Blazor的UI外观定制。 + +## 核心组件 +渲染引擎的核心组件围绕元数据的加载、解析和渲染展开。 + +**Section sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) + +## 架构概述 +渲染引擎的架构遵循清晰的分层模式,从元数据源到最终UI呈现,数据流和控制流明确。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant MetaAppService as "MetaAppService" +participant PageDomainService as "IPageDomainService" +participant Repository as "Repository" +participant MetaData as "元数据 (JSON)" +Client->>MetaAppService : GetPageWithDefineAsync(appId, pageId) +MetaAppService->>PageDomainService : GetAsync(appId, pageId) +PageDomainService->>Repository : FindAsync(appId, pageId) +Repository->>MetaData : 读取 JSON 文件 +MetaData-->>Repository : PageSchema JSON +Repository-->>PageDomainService : PageSchema 对象 +PageDomainService-->>MetaAppService : PageSchema 对象 +MetaAppService->>MetaAppService : 遍历 Components +loop 每个组件 +MetaAppService->>ComponentSchema : MergeAttributeDefineToFragment() +end +MetaAppService-->>Client : 合并后的 PageSchema +``` + +**Diagram sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) + +**中文说明**: +1. **启动与元数据加载**:渲染引擎启动后,通过 `MetaAppService` 提供的接口,从 `meta/apps` 目录下的JSON文件(或远程服务)加载 `AppSchema`、`PageSchema` 等元数据对象。 +2. **元数据查询**:`MetaAppService` 作为统一的元数据查询入口,封装了对底层 `IAppDomainService`、`IPageDomainService` 等领域服务的调用。 +3. **页面渲染流程**:当需要渲染一个页面时,引擎获取 `PageSchema`,该对象包含一个组件树(`Components`)。引擎会遍历树中的每个 `ComponentSchema`,根据其类型实例化对应的 `LowCodeComponentBase` 派生组件。 +4. **数据绑定与事件**:组件的属性(如文本、样式)通过 `ComponentFragmentSchema` 中的 `Attributes` 进行数据绑定。事件处理逻辑则通过元数据中的 `EventSchema` 进行注册。 +5. **主题定制**:`AntBlazorThemeModule` 等主题模块通过注入特定的CSS和组件渲染逻辑,实现UI外观的统一和定制。 + +## 详细组件分析 + +### 元数据服务分析 +`MetaAppService` 是渲染引擎与元数据之间的桥梁,其核心方法 `GetPageWithDefineAsync` 展示了元数据的处理逻辑。 + +```csharp +public async Task GetPageWithDefineAsync(string appId, string pageId) +{ + var pageSchema = await _pageDomainService.GetAsync(appId, pageId); + + if (pageSchema?.Components != null) + { + foreach (var component in pageSchema.Components) + { + if (component == null) + continue; + + component.MergeAttributeDefineToFragment(); + } + } + + return pageSchema; +} +``` + +此方法在获取页面元数据后,会调用每个组件的 `MergeAttributeDefineToFragment` 方法,将设计时定义的属性(`AttributeDefineGroups`)合并到运行时的渲染片段(`Fragment`)中,确保组件能正确渲染。 + +**Section sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) + +### 页面与组件元数据结构分析 +渲染引擎的元数据结构是其动态性的基础,核心类之间的关系如下: + +```mermaid +classDiagram +class PageSchema { ++IList~ComponentSchema~ Components +} +class ComponentSchema { ++ComponentFragmentSchema Fragment ++ComponentDataSourceSchema DataSource ++ComponentAttributeDefineGroupSchema[] AttributeDefineGroups ++ComponentSchema[] Childrens ++void MergeAttributeDefineToFragment() +} +class ComponentFragmentSchema { ++ComponentFragmentSchema[] ChildFragments ++bool HasChildren +} +class ComponentAttributeDefineSchema { ++string AttributeName ++string AttributeClrType ++object AttributeValue +} +class ComponentDataSourceSchema { ++string DataSourceId ++string DataSourceType +} +PageSchema --> ComponentSchema : "包含" +ComponentSchema --> ComponentFragmentSchema : "拥有" +ComponentSchema --> ComponentDataSourceSchema : "关联" +ComponentSchema --> ComponentAttributeDefineSchema : "定义" +ComponentSchema --> ComponentSchema : "父子" +``` + +**Diagram sources** +- [PageSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) +- [ComponentFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentFragmentSchema.cs) + +**中文说明**: +- **PageSchema**:页面元数据的根对象,包含一个 `Components` 列表,代表页面的组件树。 +- **ComponentSchema**:组件元数据的核心,包含: + - `Fragment`:定义了组件在UI上的渲染形态和属性。 + - `DataSource`:关联了组件所需的数据源(如API、数据库查询)。 + - `AttributeDefineGroups`:设计时定义的属性组,通过 `MergeAttributeDefineToFragment()` 方法合并到 `Fragment` 中。 + - `Childrens`:支持嵌套的子组件,形成树状结构。 +- **ComponentFragmentSchema**:渲染片段,其 `ChildFragments` 属性支持更复杂的嵌套渲染。 +- **ComponentDataSourceSchema**:定义了组件数据源的ID和类型,用于 `TableDataAppService` 或 `FormDataAppService` 与后端API或数据库进行交互,获取真实数据。 + +### 主题系统分析 +主题系统通过 `H.LowCode.Themes.AntBlazor` 模块实现,它提供了一套基于Ant Design Blazor的CSS样式和组件渲染模板(如 `ComponentRender.razor.css`),从而实现UI外观的统一和品牌化定制。 + +**Section sources** +- [AntBlazorThemeModule.cs](file://src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs) + +## 依赖分析 +渲染引擎的依赖关系清晰,体现了低耦合的设计原则。 + +```mermaid +graph TD +A[MetaAppService] --> B[IPageDomainService] +A --> C[IMenuDomainService] +B --> D[PageFileRepository] +B --> E[PageRemoteServiceRepository] +C --> F[MenuFileRepository] +C --> G[MenuRemoteServiceRepository] +D --> H[meta/apps/*.json] +E --> I[Remote API] +J[TableDataAppService] --> K[ITableDataDomainService] +K --> L[TableDataRepository] +L --> M[Database] +``` + +**Diagram sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [TableDataAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/TableDataAppService.cs) + +**中文说明**: +- **内部依赖**:上层模块(Application)依赖下层模块(Domain),Domain层通过依赖注入使用具体的Repository实现。 +- **外部依赖**:数据访问层(EntityFrameworkCore)依赖于数据库,而Repository.JsonFile则依赖于文件系统中的JSON元数据。 + +## 性能考量 +渲染引擎的设计充分考虑了性能: +1. **轻量性**:核心逻辑集中在元数据解析和组件实例化,避免了复杂的运行时计算。 +2. **高效加载**:元数据以JSON格式存储,解析速度快。`FileRepository` 实现了高效的文件读取。 +3. **按需加载**:通常只加载当前页面所需的元数据,减少了内存占用。 +4. **强依赖元数据**:系统的性能和灵活性高度依赖于元数据结构的合理设计。结构清晰、冗余少的元数据能显著提升渲染效率。 + +## 故障排除指南 +- **页面无法渲染**:检查 `meta/apps/[appId]/page/[pageId].json` 文件是否存在且格式正确。确认 `PageSchema` 中的组件ID是否能在 `meta/parts/componentParts` 中找到对应的定义。 +- **组件属性不生效**:检查 `ComponentSchema` 的 `AttributeDefineGroups` 是否正确配置,并确认 `MergeAttributeDefineToFragment()` 方法是否被成功调用。 +- **数据无法加载**:检查 `ComponentDataSourceSchema` 中的 `DataSourceId` 是否正确,并确认 `TableDataAppService` 或 `FormDataAppService` 能否成功连接到后端数据源。 + +**Section sources** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [ComponentSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs) + +## 结论 +渲染引擎是低代码平台的核心执行单元,它通过解析 `meta` 目录下的JSON元数据,动态构建出功能完整的用户界面。其架构设计遵循分层原则,职责分明,通过 `MetaAppService` 统一对外提供元数据查询服务。页面渲染流程高效,能够根据 `PageSchema` 中的组件树实例化组件,并处理数据绑定与事件。主题系统和灵活的数据访问机制(支持本地文件和远程服务)进一步增强了其可定制性和适应性。该引擎的轻量性和高性能使其非常适合快速构建和部署动态应用。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\270\262\346\237\223\345\274\225\346\223\216\346\236\266\346\236\204\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\270\262\346\237\223\345\274\225\346\223\216\346\236\266\346\236\204\350\256\276\350\256\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..47a0cb8867c9c9a71368646dccad21f98b68da59 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\346\270\262\346\237\223\345\274\225\346\223\216/\346\270\262\346\237\223\345\274\225\346\223\216\346\236\266\346\236\204\350\256\276\350\256\241.md" @@ -0,0 +1,268 @@ +# 渲染引擎架构设计 + + +**本文档引用的文件** +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [MenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [IPageRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IPageRepository.cs) +- [IMenuRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IMenuRepository.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MenuFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档旨在全面描述渲染引擎的架构设计,涵盖其分层结构:宿主层(Host)、应用层(Application)、领域层(Domain)和基础设施层(EntityFrameworkCore/Repository)。文档详细说明了各模块的职责划分与依赖关系,特别是基于ABP框架的模块化加载机制下的初始化流程。同时,解释了如何通过依赖注入整合MetaAppService、数据服务与存储实现,并涵盖启动过程中的配置加载、数据库上下文初始化以及元数据服务注册。最后,提供系统上下文图和组件交互图,说明请求从HTTP入口到元数据输出的完整路径。 + +## 项目结构 +渲染引擎采用分层架构设计,各层职责明确,通过ABP模块化机制进行组织和加载。整体结构分为宿主层、应用层、领域层和基础设施层,同时支持多种存储实现方式(如JSON文件和数据库)。 + +```mermaid +graph TB +subgraph "宿主层" +Host[RenderEngineHostModule] +Program[Program.cs] +AppSettings[appsettings.json] +end +subgraph "应用层" +Application[RenderEngineApplicationModule] +MetaAppService[MetaAppService] +end +subgraph "领域层" +Domain[RenderEngineDomainModule] +PageDomainService[PageDomainService] +MenuDomainService[MenuDomainService] +end +subgraph "基础设施层" +Repository[Repository] +DbContext[RenderEngineDbContext] +end +Host --> Application +Application --> Domain +Domain --> Repository +Domain --> DbContext +``` + +**图示来源** +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +**本节来源** +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + +## 核心组件 +渲染引擎的核心组件包括MetaAppService、领域服务(Domain Services)和存储库(Repositories),它们共同协作完成元数据的获取与处理。MetaAppService作为应用服务入口,通过依赖注入调用领域服务,领域服务再调用存储库从JSON文件或数据库中获取原始数据。 + +**本节来源** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [MenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MenuDomainService.cs) + +## 架构概述 +渲染引擎采用典型的分层架构,各层之间通过接口进行解耦,确保高内聚低耦合。宿主层负责应用的启动和模块加载,应用层提供API接口,领域层封装业务逻辑,基础设施层负责数据持久化。 + +```mermaid +graph TD +A[HTTP请求] --> B[MetaAppService] +B --> C[PageDomainService] +C --> D[IPageRepository] +D --> E[PageFileRepository] +E --> F[读取JSON文件] +F --> G[返回PageSchema] +G --> H[返回响应] +B --> I[MenuDomainService] +I --> J[IMenuRepository] +J --> K[MenuFileRepository] +K --> L[读取JSON文件] +L --> M[返回MenuSchema] +M --> H +``` + +**图示来源** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [PageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [MenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MenuFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) + +## 详细组件分析 + +### MetaAppService 分析 +MetaAppService 是渲染引擎的应用服务,负责处理来自前端的元数据请求。它通过LazyServiceProvider获取领域服务的实例,实现了延迟加载和依赖解耦。 + +#### 类图 +```mermaid +classDiagram +class MetaAppService { ++IMenuDomainService _menuDomainService ++IPageDomainService _pageDomainService ++GetMenusAsync(appId) Task~IList~ ++GetPageAsync(appId, pageId) Task~PageSchema~ ++GetPageWithDefineAsync(appId, pageId) Task~PageSchema~ +} +class IMenuDomainService { +<> ++GetListAsync(appId) Task~IList~ ++GetAsync(appId, menuId) Task~MenuSchema~ +} +class IPageDomainService { +<> ++GetAsync(appId, pageId) Task~PageSchema~ +} +MetaAppService --> IMenuDomainService : "依赖" +MetaAppService --> IPageDomainService : "依赖" +``` + +**图示来源** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) +- [IMenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IMenuRepository.cs) +- [IPageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IPageRepository.cs) + +**本节来源** +- [MetaAppService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs) + +### 领域服务分析 +领域服务封装了业务逻辑,PageDomainService和MenuDomainService分别负责页面和菜单的业务处理。它们通过构造函数注入对应的存储库接口,实现了业务逻辑与数据访问的分离。 + +#### 类图 +```mermaid +classDiagram +class PageDomainService { +-IPageRepository _repository ++GetAsync(appId, pageId) Task~PageSchema~ +} +class MenuDomainService { +-IMenuRepository _repository ++GetListAsync(appId) Task~IList~ ++GetAsync(appId, menuId) Task~MenuSchema~ +} +class IPageRepository { +<> ++GetAsync(appId, pageId) Task~PageSchema~ +} +class IMenuRepository { +<> ++GetListAsync(appId) Task~IList~ ++GetAsync(appId, menuId) Task~MenuSchema~ +} +PageDomainService --> IPageRepository : "依赖" +MenuDomainService --> IMenuRepository : "依赖" +``` + +**图示来源** +- [PageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [MenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [IPageRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IPageRepository.cs) +- [IMenuRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IMenuRepository.cs) + +**本节来源** +- [PageDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [MenuDomainService.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MenuDomainService.cs) + +### 存储库分析 +存储库层负责数据的持久化操作,支持JSON文件和数据库两种实现方式。FileRepositoryBase提供了通用的文件读取功能,具体的存储库如PageFileRepository和MenuFileRepository继承该基类并实现特定接口。 + +#### 类图 +```mermaid +classDiagram +class FileRepositoryBase { +#static string _metaBaseDir ++ReadAllText(fileName) string +} +class PageFileRepository { ++GetAsync(appId, pageId) Task~PageSchema~ +} +class MenuFileRepository { ++GetAsync(appId, menuId) Task~MenuSchema~ ++GetListAsync(appId) Task~IList~ ++BuildTreeMenus(menus) IList~MenuSchema~ +} +class IPageRepository { +<> ++GetAsync(appId, pageId) Task~PageSchema~ +} +class IMenuRepository { +<> ++GetListAsync(appId) Task~IList~ ++GetAsync(appId, menuId) Task~MenuSchema~ +} +PageFileRepository --|> FileRepositoryBase +MenuFileRepository --|> FileRepositoryBase +PageFileRepository ..|> IPageRepository +MenuFileRepository ..|> IMenuRepository +``` + +**图示来源** +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MenuFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [IPageRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IPageRepository.cs) +- [IMenuRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaRepositories/IMenuRepository.cs) + +**本节来源** +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [PageFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MenuFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) + +## 依赖分析 +渲染引擎通过ABP框架的依赖注入机制管理组件间的依赖关系。宿主模块RenderEngineHostModule通过[DependsOn]特性声明了对应用层、领域层和基础设施层模块的依赖,确保模块按正确顺序加载。 + +```mermaid +graph TD +A[RenderEngineHostModule] --> B[RenderEngineApplicationModule] +A --> C[RenderEngineDomainModule] +A --> D[RenderEngineEntityFrameworkCoreModule] +A --> E[RenderEngineJsonFileRepositoryModule] +B --> C +C --> D +C --> E +``` + +**图示来源** +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + +**本节来源** +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [RenderEngineApplicationModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/RenderEngineApplicationModule.cs) + +## 性能考虑 +渲染引擎在性能方面进行了多项优化: +1. 使用LazyServiceProvider实现领域服务的延迟加载,减少启动时的资源消耗。 +2. 在数据库上下文RenderEngineDbContext中使用ReadOnlySaveChangesInterceptor拦截器,避免不必要的保存操作。 +3. JSON文件存储库中禁用变更跟踪(IsChangeTrackingEnabled = false),提高读取性能。 +4. 菜单数据在加载后构建成树形结构并排序,减少前端处理开销。 + +## 故障排除指南 +### 常见问题 +1. **无法读取JSON文件**:检查appsettings.json中的Meta.appsFilePath配置路径是否正确,确保文件存在且格式合法。 +2. **依赖注入失败**:确认模块间的[DependsOn]依赖关系是否完整,特别是宿主模块对其他模块的引用。 +3. **数据库连接失败**:检查ConnectionStrings配置,确保数据库服务正常运行。 +4. **菜单显示顺序错误**:确认菜单JSON文件中的Order字段是否正确设置。 + +**本节来源** +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +## 结论 +渲染引擎采用清晰的分层架构和模块化设计,通过ABP框架实现了组件间的松耦合和依赖注入。系统支持多种数据存储方式,具有良好的扩展性和维护性。启动流程通过宿主模块统一管理,配置加载和数据库初始化过程简洁明了。整体架构设计合理,能够有效支持低代码平台的元数据渲染需求。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\347\233\256\345\275\225\347\273\223\346\236\204\350\257\246\350\247\243.md" "b/.qoder/repowiki/zh/content/\347\233\256\345\275\225\347\273\223\346\236\204\350\257\246\350\247\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..e52d41d652463245632bbff87a2c57f0db2be7b6 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\347\233\256\345\275\225\347\273\223\346\236\204\350\257\246\350\247\243.md" @@ -0,0 +1,232 @@ +# 目录结构详解 + + +**本文档引用文件** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [meta](file://meta) +- [Common](file://src/Common) +- [DesignEngine](file://src/DesignEngine) +- [RenderEngine](file://src/RenderEngine) +- [Tools](file://src/Tools) +- [README.md](file://README.md) +- [TODO.md](file://TODO.md) + + +## 目录结构 + +本项目采用模块化分层架构,整体目录结构清晰,职责分明。主要分为 `meta`(元数据)、`src`(源码)和工具类目录,适用于低代码平台的可视化设计与运行时渲染场景。 + +```mermaid +graph TD +A[LowCode项目] --> B[meta] +A --> C[src] +A --> D[Tools] +A --> E[README.md] +A --> F[TODO.md] +A --> G[global.json] +B --> B1[apps] +B --> B2[parts/componentParts/antdesign] +C --> C1[Common] +C --> C2[DesignEngine] +C --> C3[RenderEngine] +C1 --> C1a[H.LowCode.ComponentBase] +C1 --> C1b[H.LowCode.MetaSchema] +C1 --> C1c[H.LowCode.Entity] +C1 --> C1d[H.LowCode.Configuration] +C2 --> C2a[H.LowCode.DesignEngine.Application] +C2 --> C2b[H.LowCode.DesignEngine.Domain] +C2 --> C2c[H.LowCode.DesignEngine.EntityFrameworkCore] +C2 --> C2d[H.LowCode.DesignEngine.Host] +C2 --> C2e[H.LowCode.DesignEngine.Host.Client] +C3 --> C3a[H.LowCode.RenderEngine.Application] +C3 --> C3b[H.LowCode.RenderEngine.Domain] +C3 --> C3c[H.LowCode.RenderEngine.EntityFrameworkCore] +C3 --> C3d[H.LowCode.RenderEngine.Host] +C3 --> C3e[H.LowCode.RenderEngine.Host.Client] +C3 --> C3f[H.LowCode.Themes.AntBlazor] +``` + +**图示来源** +- [项目结构](file://.) + +## meta目录:元数据定义中心 + +`meta` 目录用于存放低代码平台中所有应用和组件的元数据定义,采用 JSON 文件形式存储,实现配置驱动的灵活架构。 + +### 应用元数据(apps) + +该目录下存放具体应用的配置信息,如 `caseapp` 和 `testapp`。每个应用包含以下子目录: + +- **datasource**:定义数据源配置,如 API、SQL 查询等,文件如 `iumn5yg5t.json`。 +- **menu**:菜单结构定义,控制应用导航,文件如 `5omcgxevf.json`。 +- **page**:页面布局与组件配置,描述页面结构,文件如 `0lgu6xpop.json`。 +- **应用主配置**:如 `caseapp.json`,继承自 `AppSchemaBase`,包含应用 ID、名称、图标、版本、发布状态等核心属性。 + +```json +{ + "id": "caseapp", + "n": "案例应用", + "icon": "book", + "v": "1.0.0", + "pub": 1, + "platform": [0] +} +``` + +### 组件部件元数据(parts/componentParts) + +存放可视化设计器中可拖拽的组件物料定义,基于 Ant Design 组件库封装。每个 JSON 文件代表一个可复用的组件模板(如按钮、表单字段),包含属性定义、样式、事件等元信息,支持设计时动态加载与渲染。 + +**本节来源** +- [meta/apps/caseapp](file://meta/apps/caseapp) +- [meta/parts/componentParts/antdesign](file://meta/parts/componentParts/antdesign) + +## Common模块:跨引擎共享基础 + +`src/Common` 模块为整个低代码平台提供通用基础类与元模型定义,被 `DesignEngine` 和 `RenderEngine` 共同引用,确保设计与运行时的一致性。 + +### 核心元数据结构(H.LowCode.MetaSchema) + +该命名空间定义了平台的核心元数据模型,采用基类继承方式组织: + +- **AppSchemaBase.cs**:应用元数据基类,包含名称、图标、版本、发布状态(`PublishStatusEnum`)、支持平台(`SupportPlatformEnum`)等。 +- **PageSchemaBase.cs**:页面元数据基类。 +- **ComponentSchemaBase.cs**:组件元数据基类。 +- **DataSourceSchema.cs**:数据源元数据,支持 API、SQL、选项列表等多种类型。 +- **PropertySchemas**:属性定义,如 `ValidationRuleSchema`(校验规则)、`EventSchema`(事件绑定)、`TableColumnSchema`(表格列配置)。 + +```mermaid +classDiagram +class AppSchemaBase { ++string Id ++string Name ++string Icon ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class PageSchemaBase { ++string Id ++string Name ++PageTypeEnum Type ++ComponentSchemaBase[] Components +} +class ComponentSchemaBase { ++string Id ++string Type ++Dictionary~string, object~ Properties ++EventSchema[] Events +} +class DataSourceSchema { ++string Id ++PageDataSourceTypeEnum Type ++string Config +} +AppSchemaBase --> PageSchemaBase : "包含" +PageSchemaBase --> ComponentSchemaBase : "包含" +ComponentSchemaBase --> DataSourceSchema : "引用" +``` + +**图示来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) + +### 设计与渲染专用元模型 + +- **H.LowCode.MetaSchema.DesignEngine**:专为设计器扩展的元模型,如 `ComponentPartsSchema`、`ComponentPartsAttributeDefineSchema`,用于描述组件物料的可配置项。 +- **H.LowCode.MetaSchema.RenderEngine**:运行时渲染专用模型,如 `AppSchema`、`ComponentSchema`,可能包含优化后的结构。 + +### 基础设施类 + +- **H.LowCode.ComponentBase**:提供 Blazor 组件基类,如 `LowCodeComponentBase`、`LowCodePageComponentBase`,封装通用状态管理与生命周期。 +- **H.LowCode.Entity**:实体管理,包含 `EntityBase` 基类、`EntityFactory` 工厂类及动态实体构建工具。 +- **H.LowCode.Configuration.Options**:配置选项类,如 `MetaOption`、`SiteOption`,用于依赖注入配置。 + +**本节来源** +- [Common](file://src/Common) + +## DesignEngine:可视化设计引擎 + +`DesignEngine` 模块实现低代码平台的可视化设计功能,基于 ABP 框架分层设计,支持服务端与客户端协同。 + +### 分层架构 + +遵循典型的领域驱动设计(DDD)分层: + +- **Application**:应用服务层,如 `PageAppService`、`MenuAppService`,处理业务用例。 +- **Application.Contracts**:应用服务契约,定义接口如 `IPageAppService` 和 DTO。 +- **Domain**:领域层,包含领域服务(`PageDomainService`)和仓储接口(`IPageRepository`)。 +- **EntityFrameworkCore**:数据访问层,实现仓储(`PageFileRepository`)和 `DbContext`。 +- **Model**:数据传输对象(DTO)模型。 + +### 多仓储支持 + +- **Repository.JsonFile**:基于文件系统的仓储实现,直接读写 `meta` 目录下的 JSON 文件,适用于开发与静态部署。 +- **Repository.RemoteService**:远程服务仓储,通过 HTTP 调用后端 API,适用于云部署。 + +### 宿主模块(Host) + +- **H.LowCode.DesignEngine.Host**:服务端宿主,包含 `Program.cs` 和 `appsettings.json`,启动 ASP.NET Core 服务。 +- **H.LowCode.DesignEngine.Host.Client**:客户端宿主,用于 Blazor WebAssembly 模式,包含客户端配置。 + +### 设计器基础组件 + +- **H.LowCode.DesignEngineBase**:提供拖拽组件基类(`DraggableItem`)、状态服务(`DragDropStateService`)等。 +- **H.LowCode.PartsDesignEngine**:组件物料设计专用模块,增强物料管理功能。 + +**本节来源** +- [DesignEngine](file://src/DesignEngine) + +## RenderEngine:运行时渲染引擎 + +`RenderEngine` 模块负责将 `meta` 中的元数据在运行时动态渲染为可交互的 Web 页面。 + +### 核心职责 + +- **MetaAppService**:获取应用、页面、菜单等元数据。 +- **DataAppServices**:处理表单(`FormDataAppService`)和表格(`TableDataAppService`)的数据读写。 + +### 主题支持 + +- **H.LowCode.Themes.AntBlazor**:集成 Ant Design Blazor 组件库,提供 `ComponentRender` 组件渲染器和主题样式。 + +### 宿主与客户端 + +与 `DesignEngine` 类似,包含 `Host`(服务端)和 `Host.Client`(客户端),支持服务端渲染(SSR)和 WebAssembly 模式。 + +**本节来源** +- [RenderEngine](file://src/RenderEngine) + +## Tools:工具模块 + +提供平台维护与迁移工具。 + +### H.LowCode.DbMigrator + +基于 Entity Framework Core 的数据库迁移工具,用于管理 `DesignEngine` 和 `RenderEngine` 的数据库模式。 + +- **MigrationGenerator**:生成迁移脚本。 +- **MigrationServices**:执行迁移逻辑。 +- **Migrations**:存放迁移文件,如 `20250225020741_Initial.cs`。 + +### H.LowCode.MetaMigrator + +元数据迁移工具,用于在不同环境间同步 `meta` 目录的 JSON 配置。当前实现为占位程序。 + +**本节来源** +- [Tools](file://src/Tools) + +## 模块依赖与解耦设计 + +项目通过清晰的依赖关系实现高内聚、低耦合: + +- **Common** 为 `DesignEngine` 和 `RenderEngine` 提供共享契约,二者均依赖 `Common`,但互不依赖。 +- **meta** 作为配置中心,被 `DesignEngine.Repository.JsonFile` 和 `RenderEngine.Repository.JsonFile` 直接读取,实现配置与代码分离。 +- **Host.Client** 模块允许在 SSR 模式下,服务端(Host)与客户端(Host.Client)共享配置(`appsettings.json`),实现无缝集成。 +- 使用接口(如 `IPageRepository`)和依赖注入,可灵活切换 `JsonFile` 与 `RemoteService` 仓储实现。 + +**本节来源** +- [项目结构](file://.) +- [DesignEngine](file://src/DesignEngine) +- [RenderEngine](file://src/RenderEngine) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/DOM\346\223\215\344\275\234\345\267\245\345\205\267\345\207\275\346\225\260.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/DOM\346\223\215\344\275\234\345\267\245\345\205\267\345\207\275\346\225\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..59abfc3141a0ed3a20be9f46ab23c9f9ab85dc4f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/DOM\346\223\215\344\275\234\345\267\245\345\205\267\345\207\275\346\225\260.md" @@ -0,0 +1,349 @@ +# DOM操作工具函数 + + +**本文档引用的文件** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DragDropElementDimensions.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Dtos/DragDropElementDimensions.cs) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [DragDropStateSchema.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L203-L237) + + +## 目录 +1. [简介](#简介) +2. [核心功能概述](#核心功能概述) +3. [elementUtils.js 详细分析](#elementutilsjs-详细分析) +4. [与Blazor的互操作实现](#与blazor的互操作实现) +5. [拖拽状态管理机制](#拖拽状态管理机制) +6. [性能优化策略](#性能优化策略) +7. [使用场景与示例](#使用场景与示例) +8. [结论](#结论) + +## 简介 +本文件详细文档化了 `elementUtils.js` 中提供的JavaScript工具函数,重点分析其在Blazor低代码设计引擎中的作用。这些工具函数解决了Blazor在精确DOM测量方面的局限性,特别是在实现组件拖拽、布局计算和视觉反馈等交互功能时的关键作用。通过JavaScript互操作(JS Interop),前端能够高效获取元素尺寸、应用变换动画并优化拖拽性能。 + +## 核心功能概述 +`elementUtils.js` 是一个轻量级的JavaScript工具库,专为增强Blazor应用中的DOM操作能力而设计。它主要提供以下核心功能: +- **精确DOM测量**:获取元素的精确尺寸、边距和容器信息 +- **高性能变换操作**:通过`transform`属性实现流畅的视觉动画 +- **性能优化工具**:提供节流函数以优化高频事件处理 +- **浏览器特性检测**:检测对3D变换的支持情况 + +这些功能共同支撑了低代码平台中复杂的拖拽交互和实时布局预览。 + +## elementUtils.js 详细分析 + +### getDimensions 方法 +该方法用于获取元素的完整尺寸信息,包括考虑margin的实际尺寸。 + +**参数** +- `element`: 要测量的DOM元素 + +**返回值** +返回一个包含以下属性的对象: +- `width`: 元素的CSS宽度(不包括margin) +- `height`: 元素的CSS高度(不包括margin) +- `actualWidth`: 实际占用宽度(包括左右margin) +- `actualHeight`: 实际占用高度(包括上下margin) +- `containerWidth`: 父容器的宽度 +- `margin`: 包含四个方向margin值的对象 +- `offsetTop`: 元素相对于视口顶部的距离 +- `offsetLeft`: 元素相对于视口左侧的距离 + +```javascript +getDimensions: function (element) { + if (!element) return null; + + const rect = element.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(element); + const containerWidth = element.parentElement ? element.parentElement.getBoundingClientRect().width : 0; + + const margin = { + top: parseFloat(computedStyle.marginTop), + right: parseFloat(computedStyle.marginRight), + bottom: parseFloat(computedStyle.marginBottom), + left: parseFloat(computedStyle.marginLeft) + }; + + return { + width: rect.width, + height: rect.height, + actualWidth: rect.width + margin.left + margin.right, + actualHeight: rect.height + margin.top + margin.bottom, + containerWidth: containerWidth, + margin: margin, + offsetTop: rect.top, + offsetLeft: rect.left + }; +} +``` + +**实现细节** +1. 使用 `getBoundingClientRect()` 获取元素在视口中的位置和尺寸 +2. 通过 `getComputedStyle()` 获取计算后的样式,确保获取的是最终渲染值 +3. 计算包含margin的实际尺寸,这对于布局对齐和碰撞检测至关重要 +4. 同时获取父容器宽度,用于计算相对位置和布局约束 + +**Section sources** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js#L2-L34) + +### getContainerInfo 方法 +获取父容器的尺寸和内边距信息。 + +```javascript +getContainerInfo: function (element) { + if (!element || !element.parentElement) return null; + + const container = element.parentElement; + const containerRect = container.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(container); + + return { + width: containerRect.width, + height: containerRect.height, + padding: { + top: parseFloat(computedStyle.paddingTop), + right: parseFloat(computedStyle.paddingRight), + bottom: parseFloat(computedStyle.paddingBottom), + left: parseFloat(computedStyle.paddingLeft) + } + }; +} +``` + +**Section sources** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js#L36-L53) + +### setTransform 与 clearTransform 方法 +用于高效地设置和清除元素的变换属性。 + +```javascript +setTransform: function (element, transform) { + if (!element) return; + element.style.transform = transform; + element.style.willChange = 'transform'; +}, + +clearTransform: function (element) { + if (!element) return; + element.style.transform = ''; + element.style.willChange = 'auto'; +} +``` + +**性能优化**:通过设置 `willChange: 'transform'`,提示浏览器提前优化该元素的变换性能,通常会触发GPU加速。 + +**Section sources** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js#L55-L68) + +### throttle 方法 +节流函数,用于限制高频事件的执行频率。 + +```javascript +throttle: function (func, limit) { + let inThrottle; + return function() { + const args = arguments; + const context = this; + if (!inThrottle) { + func.apply(context, args); + inThrottle = true; + setTimeout(() => inThrottle = false, limit); + } + } +} +``` + +**应用场景**:在拖拽过程中,`onDragOver` 事件会高频触发,使用节流可以避免性能瓶颈。 + +**Section sources** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js#L70-L83) + +## 与Blazor的互操作实现 + +### JS Interop 调用流程 +Blazor组件通过 `IJSRuntime` 调用JavaScript函数,实现DOM操作。 + +```mermaid +sequenceDiagram +participant Blazor as Blazor组件 +participant JSRuntime as IJSRuntime +participant JS as JavaScript +participant DOM as DOM元素 +Blazor->>JSRuntime : InvokeAsync("elementUtils.getDimensions", elementRef) +JSRuntime->>JS : 执行JavaScript函数 +JS->>DOM : 调用getBoundingClientRect()和getComputedStyle() +DOM-->>JS : 返回尺寸数据 +JS-->>JSRuntime : 返回JavaScript对象 +JSRuntime-->>Blazor : 反序列化为C#对象 +``` + +**Diagram sources** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor#L100-L108) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js#L2-L34) + +### C# 数据结构映射 +JavaScript返回的尺寸数据被映射到C#的DTO对象。 + +```csharp +internal class DragDropElementDimensions +{ + public double Width { get; set; } + public double Height { get; set; } + public double ActualWidth { get; set; } + public double ActualHeight { get; set; } + public double ContainerWidth { get; set; } + public DragDropElementMargin Margin { get; set; } + public double OffsetTop { get; set; } + public double OffsetLeft { get; set; } +} + +internal class DragDropElementMargin +{ + public double Top { get; set; } + public double Right { get; set; } + public double Bottom { get; set; } + public double Left { get; set; } +} +``` + +**Section sources** +- [DragDropElementDimensions.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Dtos/DragDropElementDimensions.cs#L4-L22) + +### 在DraggableItem中的实际应用 +`DraggableItem.razor` 组件在初始化后加载并使用 `elementUtils.js`。 + +```csharp +protected override async Task OnAfterRenderAsync(bool firstRender) +{ + if (firstRender) + { + await JSRuntime.InvokeAsync("import", "./_content/H.LowCode.DesignEngineBase/js/elementUtils.js"); + await UpdateDimensions(); + RegisterEventDispatcher(); + } +} + +private async Task UpdateDimensions() +{ + try + { + dimensions = await JSRuntime.InvokeAsync("elementUtils.getDimensions", itemRef); + } + catch (Exception ex) + { + Console.WriteLine($"Error getting element dimensions: {ex.Message}"); + } +} +``` + +**Section sources** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor#L98-L115) + +## 拖拽状态管理机制 + +### DragDropStateService 服务 +该服务负责管理整个设计面板的拖拽状态。 + +```mermaid +classDiagram +class DragDropStateService { ++GetRootComponent(appId, pageId) ComponentPartsSchema ++SetRootComponent(appId, pageId, rootComponent) void ++GetCurrentDragComponent(appId, pageId) ComponentPartsSchema ++SetCurrentDragComponent(appId, pageId, currentDragComponent) void ++GetLastSelectedComponent(appId, pageId) ComponentPartsSchema ++SetLastSelectedComponent(appId, pageId, lastSelectedComponent) void ++ResetDragStyle(appId, pageId) void +} +class DragDropStateSchema { ++RootComponent ComponentPartsSchema ++CurrentDragComponent ComponentPartsSchema ++LastSelectedComponent ComponentPartsSchema ++LastDragOverComponent ComponentPartsSchema ++LastDragOverTime DateTime +} +DragDropStateService --> DragDropStateSchema : "管理" +``` + +**Diagram sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L7-L237) + +### 状态数据结构 +`DragDropStateSchema` 存储了关键的拖拽状态信息。 + +**关键属性**: +- `CurrentDragComponent`: 当前正在拖拽的组件 +- `LastSelectedComponent`: 最后选中的组件 +- `LastDragOverComponent`: 最后一次拖拽经过的组件 +- `LastDragOverTime`: 最后一次拖拽时间 + +**Section sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L203-L237) + +## 性能优化策略 + +### 视觉反馈优化 +通过CSS变换实现流畅的拖拽动画效果。 + +```css +transition: transform 0.25s cubic-bezier(0.2, 0, 0.2, 1); +transform: translate3d(x, y, 0); +will-change: transform; +``` + +### 防抖与节流 +在 `OnDragOver` 事件中实现更新间隔控制,避免过度渲染。 + +```csharp +private const int UPDATE_INTERVAL_MS = 16; // ~60fps +var now = DateTime.Now; +if ((now - lastUpdateTime).TotalMilliseconds < UPDATE_INTERVAL_MS) + return; +lastUpdateTime = now; +``` + +### GPU加速 +使用 `translate3d` 触发GPU硬件加速,提升动画性能。 + +```javascript +currentDragComponent.DesignState.AnimationTransform = $"translate3d({dragOffsetX}px, {dragOffsetY}px, 0) scale(1.05)"; +``` + +## 使用场景与示例 + +### 计算拖拽元素的绝对坐标 +```csharp +// 在拖拽过程中,获取鼠标相对于画布的坐标 +var dragOffsetX = clientX - initialX; +var dragOffsetY = clientY - initialY; + +// 应用变换 +await JSRuntime.InvokeVoidAsync("elementUtils.setTransform", + currentDragElement, + $"translate3d({dragOffsetX}px, {dragOffsetY}px, 0)"); +``` + +### 实现兄弟组件的让位动画 +```csharp +// 当拖拽元素经过其他组件时,计算需要移动的距离 +var moveDistanceX = dimensions.ActualWidth; +var moveDistanceY = 0; + +// 应用让位变换 +child.DesignState.AnimationTransform = $"translate3d({moveDistanceX}px, {moveDistanceY}px, 0) scale(0.95)"; +``` + +### 响应式布局计算 +```javascript +// 计算每行可容纳的组件数量 +var itemsPerRow = Math.Floor(containerWidth / actualWidth); +``` + +## 结论 +`elementUtils.js` 作为Blazor应用与原生DOM操作之间的桥梁,有效弥补了Blazor在精确DOM测量和高性能动画方面的不足。通过精心设计的JS Interop调用,实现了流畅的拖拽体验和实时的布局反馈。其核心价值在于: +1. **精确测量**:提供包含margin的实际尺寸,解决布局计算难题 +2. **性能优化**:通过变换和节流机制确保交互流畅性 +3. **状态同步**:与C#服务端状态完美配合,实现一致的用户体验 + +该工具库的设计模式为Blazor应用中的复杂交互提供了优秀的实践范例。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222.md" new file mode 100644 index 0000000000000000000000000000000000000000..c4fddc028a3ddb7716f7cb208c020d8413d77630 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222.md" @@ -0,0 +1,296 @@ +# UI组件与交互 + + +**本文档引用的文件** +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.PartsDesignEngine/ComponentPanel/DragItem.razor.css) +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) +- [DraggableContainer.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor.css) +- [DraggableItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [DesignEngineModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine/DesignEngineModule.cs) +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) + + +## 目录 +1. [组件面板与属性设置面板的样式定义](#组件面板与属性设置面板的样式定义) +2. [拖拽状态管理服务](#拖拽状态管理服务) +3. [DOM操作工具函数](#dom操作工具函数) +4. [组件拖拽交互流程](#组件拖拽交互流程) + +## 组件面板与属性设置面板的样式定义 + +### DragItem.razor.css 样式分析 +`DragItem.razor.css` 文件定义了组件面板中可拖拽组件项的视觉样式与布局。该样式应用于 `.dragitem` 类,确保组件在面板中以一致的外观呈现。 + +```css +.dragitem { + float: left; + width: 6.8rem; + height: 2.2rem; + margin: 4px; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + color: #333; + background-color: #f5f7fa; +} + +.dragitem:hover { + border: #409eff dashed 1px; + color: #409eff; +} +``` + +**样式说明:** +- **布局与尺寸**:使用 `float: left` 实现组件项的横向排列,固定宽度 `6.8rem` 和高度 `2.2rem`,并设置 `4px` 的外边距,形成网格化布局。 +- **交互反馈**:默认光标为 `pointer`,当鼠标悬停时,边框变为蓝色虚线(`#409eff dashed 1px`),文字颜色也变为蓝色,提供清晰的视觉反馈,提示用户该元素可被操作。 + +此样式文件在两个路径下存在,分别位于 `H.LowCode.DesignEngine` 和 `H.LowCode.PartsDesignEngine` 模块中,表明该样式被多个设计引擎模块复用。 + +**Section sources** +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.PartsDesignEngine/ComponentPanel/DragItem.razor.css) + +### PageSetting.razor.css 样式分析 +`PageSetting.razor.css` 文件定义了页面属性设置面板中各个设置项的样式。 + +```css +.pagesetting-item { + margin: 5px 15px 20px 10px; +} +``` + +**样式说明:** +- **布局**:为每个设置项设置了不均匀的外边距(上5px、右15px、下20px、左10px),这种设计可能旨在创建一种非对称但有节奏的视觉层次,使设置面板的布局更具可读性。 + +**Section sources** +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) + +### DraggableItem.razor.css 样式分析 +`DraggableItem.razor.css` 文件定义了在设计画布上可拖拽组件的详细样式,包括选中、悬停、拖拽过程中的各种视觉状态。 + +```css +.draggableitem { + position: relative; + display: flex; + height: 100%; + margin: 1px; + border: #ffffff solid 2px; + background-color: #ffffff; + transform: translate3d(0, 0, 0); + backface-visibility: hidden; + perspective: 1000px; + transition: all 0.2s ease-out; + cursor: grab; +} + +.draggableitem-selected { + outline: #1890ff solid 2px; + box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15); +} + +.draggableitem-dragging { + cursor: grabbing; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); + z-index: 9999; +} + +.draggableitem-drag-over { + background-color: rgba(24, 144, 255, 0.05); + border-color: #1890ff; + border-style: dashed; +} +``` + +**样式说明:** +- **基础状态**:`.draggableitem` 使用 `translate3d` 启用硬件加速,`backface-visibility` 和 `perspective` 优化3D变换性能,`transition` 提供平滑的动画过渡。 +- **选中状态**:`.draggableitem-selected` 通过蓝色实线轮廓和阴影突出显示当前选中的组件。 +- **拖拽状态**:`.draggableitem-dragging` 在拖拽时改变光标为 `grabbing`,增加阴影深度,并将 `z-index` 提升至9999,确保其位于最顶层。 +- **目标区域反馈**:`.draggableitem-drag-over` 在组件被拖拽到其上方时,改变背景色和边框为蓝色虚线,直观地指示放置位置。 + +**Section sources** +- [DraggableItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css) + +## 拖拽状态管理服务 + +### DragDropStateService 核心功能 +`DragDropStateService` 是一个核心服务,负责管理整个拖拽过程中的所有状态。它被注册为单例服务,确保在整个应用生命周期内状态的一致性。 + +```csharp +public class DragDropStateService +{ + private IDictionary schemaStates = new Dictionary(); + + public ComponentPartsSchema GetCurrentDragComponent(string appId, string pageId) + { + var stateSchema = GetStateSchema(appId, pageId); + return stateSchema?.CurrentDragComponent; + } + + public void SetCurrentDragComponent(string appId, string pageId, ComponentPartsSchema currentDragComponent) + { + SetStateSchema(appId, pageId, (stateSchema) => { + stateSchema.CurrentDragComponent = currentDragComponent; + }); + } + + // ... 其他状态的获取和设置方法 +} +``` + +**状态管理说明:** +- **状态存储**:使用 `schemaStates` 字典,以 `appId-pageId` 作为键来存储每个页面的独立状态对象 `DragDropStateSchema`。 +- **关键状态**: + - `CurrentDragComponent`:存储当前正在被拖拽的组件。 + - `LastDragOverComponent`:存储上一个被悬停的组件,用于在拖拽离开时清除其视觉反馈。 + - `LastSelectedComponent`:存储最后被选中的组件,用于实现组件的选中逻辑。 + - `RootComponent`:存储页面的根组件,是整个组件树的起点。 + +### 服务注入与生命周期协同 +`DragDropStateService` 通过依赖注入(DI)容器在 `DesignEngineModule.cs` 和 `PartsDesignEngineModule.cs` 中被注册为单例。 + +```csharp +// DesignEngineModule.cs +public override void ConfigureServices(ServiceConfigurationContext context) +{ + context.Services.AddAntDesign(); + context.Services.AddSingleton(typeof(DragDropStateService)); +} +``` + +**生命周期协同:** +- **注入**:任何需要访问拖拽状态的Blazor组件都可以通过 `[Inject]` 属性注入 `DragDropStateService`。 +- **状态同步**:当组件的 `OnInitialized` 或 `OnParametersSet` 生命周期方法被调用时,组件可以从服务中读取当前状态并更新自身UI。当用户进行拖拽操作时,组件调用服务的 `Set` 方法更新状态,服务内部的逻辑会确保状态的正确性。 +- **重置**:提供了 `ResetComponent` 和 `ResetDragStyle` 等方法,用于在特定操作(如取消选择)后清理状态和样式。 + +**Section sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [DesignEngineModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine/DesignEngineModule.cs) +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) + +## DOM操作工具函数 + +### elementUtils.js 功能分析 +`elementUtils.js` 是一个JavaScript模块,提供了在Blazor应用中与DOM进行交互的工具函数,主要用于精确计算拖拽过程中的坐标和尺寸。 + +```javascript +window.elementUtils = { + getDimensions: function (element) { + if (!element) return null; + const rect = element.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(element); + const margin = { + top: parseFloat(computedStyle.marginTop), + right: parseFloat(computedStyle.marginRight), + bottom: parseFloat(computedStyle.marginBottom), + left: parseFloat(computedStyle.marginLeft) + }; + return { + width: rect.width, + height: rect.height, + actualWidth: rect.width + margin.left + margin.right, + actualHeight: rect.height + margin.top + margin.bottom, + offsetTop: rect.top, + offsetLeft: rect.left + }; + }, + + setTransform: function (element, transform) { + if (!element) return; + element.style.transform = transform; + element.style.willChange = 'transform'; + }, + + throttle: function (func, limit) { + let inThrottle; + return function() { + const args = arguments; + const context = this; + if (!inThrottle) { + func.apply(context, args); + inThrottle = true; + setTimeout(() => inThrottle = false, limit); + } + } + } +}; +``` + +**函数说明:** +- **`getDimensions`**:获取元素的精确尺寸,包括 `offsetTop` 和 `offsetLeft`(相对于视口的位置),以及计算了 `margin` 的实际尺寸。这对于判断拖拽元素在画布中的位置至关重要。 +- **`setTransform`**:直接操作元素的 `transform` CSS属性,用于实现拖拽时的平滑移动动画。设置 `willChange: 'transform'` 可以提示浏览器提前优化该属性的渲染。 +- **`throttle`**:节流函数,用于限制高频率事件(如 `mousemove`)的处理频率,防止因频繁的DOM操作导致性能下降。 + +**Section sources** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) + +## 组件拖拽交互流程 + +### 完整交互流程图解 +以下流程图描述了从组件拖拽开始到释放生成新页面元素的完整过程。 + +```mermaid +sequenceDiagram +participant 组件面板 as 组件面板 +participant DragDropStateService as DragDropStateService +participant 设计画布 as 设计画布 +participant elementUtils as elementUtils.js +组件面板->>DragDropStateService : 开始拖拽 (MouseDown) +DragDropStateService->>DragDropStateService : SetCurrentDragComponent(组件) +DragDropStateService->>设计画布 : 触发状态变更通知 +设计画布->>设计画布 : OnStateHasChanged() +设计画布->>设计画布 : 应用 .draggableitem-dragging 样式 +设计画布->>elementUtils : getDimensions(拖拽元素) +elementUtils-->>设计画布 : 返回尺寸和位置 +loop 拖拽中 (MouseMove) +设计画布->>elementUtils : throttle(getDimensions, 16) +elementUtils-->>设计画布 : 返回当前位置 +设计画布->>DragDropStateService : SetLastDragOverComponent(目标容器) +DragDropStateService->>设计画布 : 触发状态变更通知 +设计画布->>设计画布 : 应用 .draggableitem-drag-over 样式到目标 +设计画布->>设计画布 : 计算放置位置并调整其他组件 +end +设计画布->>DragDropStateService : 结束拖拽 (MouseUp) +DragDropStateService->>DragDropStateService : SetLastDropComponent(目标容器) +DragDropStateService->>DragDropStateService : 将组件添加到目标容器的Childrens +DragDropStateService->>DragDropStateService : ResetDragStyle() +DragDropStateService->>设计画布 : 触发状态变更通知 +设计画布->>设计画布 : OnStateHasChanged() +设计画布->>设计画布 : 移除所有拖拽相关样式,更新UI +``` + +**Diagram sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [DraggableItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css) + +### 流程详细说明 +1. **拖拽开始**: + - 用户在组件面板中点击一个组件(`MouseDown` 事件)。 + - 事件处理程序调用 `DragDropStateService` 的 `SetCurrentDragComponent` 方法,将该组件标记为当前拖拽项。 + - 服务内部状态更新,并通知所有监听该状态的组件(如设计画布)进行刷新。 + - 设计画布组件检测到 `CurrentDragComponent` 不为空,为该组件应用 `.draggableitem-dragging` 样式,并使用 `elementUtils.getDimensions` 获取其初始位置。 + +2. **拖拽中**: + - 用户移动鼠标(`MouseMove` 事件),此事件被节流(`throttle`)以优化性能。 + - 设计画布持续获取鼠标位置,并通过 `elementUtils.getDimensions` 计算出鼠标指针相对于各个可放置容器的位置。 + - 当鼠标悬停在一个有效的容器上时,调用 `SetLastDragOverComponent` 更新服务状态。 + - 服务通知设计画布,画布为该容器应用 `.draggableitem-drag-over` 样式,提供视觉反馈。同时,系统会计算新组件的插入位置,并可能为其他组件应用 `.draggableitem-moving` 样式来“让位”。 + +3. **拖拽结束**: + - 用户松开鼠标(`MouseUp` 事件)。 + - 事件处理程序获取 `LastDragOverComponent` 作为目标容器。 + - 调用 `DragDropStateService` 的方法,将 `CurrentDragComponent` 作为子组件添加到目标容器的 `Childrens` 列表中。 + - 调用 `ResetDragStyle` 清理所有与拖拽相关的临时状态和样式。 + - 服务再次通知UI,设计画布重新渲染,显示出新添加的组件。 + +此流程通过 `DragDropStateService` 统一管理状态,`elementUtils.js` 精确处理DOM,以及CSS样式提供即时的视觉反馈,共同实现了流畅的低代码拖拽构建体验。 + +**Section sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [DraggableItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css) +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\344\272\244\344\272\222\345\256\214\346\225\264\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\344\272\244\344\272\222\345\256\214\346\225\264\346\265\201\347\250\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..0d434f97156a3ad1c58a71f7e4af057580823a4b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\344\272\244\344\272\222\345\256\214\346\225\264\346\265\201\347\250\213.md" @@ -0,0 +1,681 @@ +# 拖拽交互完整流程 + + +**本文档引用文件** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentDesignStateSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentDesignStateSchema.cs) +- [ComponentSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) + + +## 目录 +1. [交互流程概述](#交互流程概述) +2. [核心组件与服务](#核心组件与服务) +3. [拖拽状态管理机制](#拖拽状态管理机制) +4. [拖拽交互时序分析](#拖拽交互时序分析) +5. [视觉反馈与CSS类切换](#视觉反馈与css类切换) +6. [位置判断与JavaScript工具函数](#位置判断与javascript工具函数) +7. [页面元数据生成](#页面元数据生成) +8. [错误处理机制](#错误处理机制) +9. [关键代码片段](#关键代码片段) + +## 交互流程概述 + +低代码平台的拖拽交互流程从用户在组件面板点击并拖拽组件开始,到在设计画布上释放生成新元素结束。整个过程涉及多个组件、服务和工具函数的协同工作,确保用户体验流畅且数据状态一致。 + +该流程按时间序列可分为以下几个关键阶段: +1. **拖拽开始(OnPointerDown)**:用户点击组件面板中的组件,触发拖拽开始事件。 +2. **状态更新(DragDropStateService)**:拖拽状态服务记录当前拖拽的组件及其状态。 +3. **视觉反馈(CSS类切换)**:通过动态切换CSS类实现拖拽过程中的视觉反馈效果。 +4. **位置判断(elementUtils.js)**:持续调用JavaScript工具函数进行元素位置判断。 +5. **元素生成(OnDrop)**:在画布上释放时,生成页面元数据并更新应用模式(AppSchema)。 + +此流程确保了用户在设计界面中能够直观地构建页面结构,同时保持底层数据模型的同步更新。 + +## 核心组件与服务 + +拖拽交互流程涉及多个核心组件和服务,它们共同协作完成整个交互过程。 + +### 组件面板(ComponentPanel) +组件面板是拖拽交互的入口点,展示所有可用的可拖拽组件。每个组件以`DragItem`形式呈现,支持拖拽和点击操作。 + +```mermaid +classDiagram +class DragItem { ++ComponentPartsSchema Component +-OnDragStart() +-OnClick() +-AddComponentToDesignPanel(bool isOnClick) +} +class ComponentPanel { +-IList _componentPartsList +-LoadComponentPartsAsync() Task~IList~ComponentPartsSchema~~ +} +DragItem --> ComponentPanel : "包含在" +``` + +**图示来源** +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [ComponentPanel.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/ComponentPanel.razor) + +### 设计面板(DesignPanel) +设计面板是拖拽的目标区域,包含一个可拖拽容器(DraggableContainer),用于接收并排列拖拽进来的组件。 + +```mermaid +classDiagram +class DesignPanel { ++ComponentPartsSchema _rootComponent +-LoadRootComponent() ComponentPartsSchema +-OnInitializedAsync() Task +} +class DraggableContainer { ++ComponentPartsSchema ContainerComponent ++bool IsRootContainer +-OnDrop() +-DragDropHandler(ComponentPartsSchema) +} +class DraggableItem { ++ComponentPartsSchema Component ++bool IsInRootContainer +-OnDragStart(DragEventArgs) +-OnDragEnter(DragEventArgs) +-OnDragOver(DragEventArgs) +-OnDragLeave() +-OnDrop() +} +DesignPanel --> DraggableContainer : "包含" +DraggableContainer --> DraggableItem : "包含多个" +``` + +**图示来源** +- [DesignPanel.razor](file://src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) + +### 拖拽状态服务(DragDropStateService) +`DragDropStateService`是拖拽交互的核心状态管理服务,负责维护拖拽过程中的各种状态信息。 + +```mermaid +classDiagram +class DragDropStateService { +-IDictionary~string, DragDropStateSchema~ schemaStates ++GetRootComponent(string appId, string pageId) ComponentPartsSchema ++SetRootComponent(string appId, string pageId, ComponentPartsSchema) ++GetCurrentDragComponent(string appId, string pageId) ComponentPartsSchema ++SetCurrentDragComponent(string appId, string pageId, ComponentPartsSchema) ++GetLastDragOverComponent(string appId, string pageId) ComponentPartsSchema ++SetLastDragOverComponent(string appId, string pageId, ComponentPartsSchema) ++ResetDragStyle(string appId, string pageId) void +} +class DragDropStateSchema { ++ComponentPartsSchema RootComponent ++ComponentPartsSchema LastSelectedComponent ++ComponentPartsSchema CurrentDragComponent ++ComponentPartsSchema LastDragOverComponent ++ComponentPartsSchema LastDropComponent ++DateTime LastDragOverTime +} +DragDropStateService --> DragDropStateSchema : "包含" +``` + +**图示来源** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) + +## 拖拽状态管理机制 + +`DragDropStateService`通过`DragDropStateSchema`对象为每个应用-页面组合维护独立的状态上下文。这种设计确保了多页面编辑时的状态隔离。 + +### 状态存储结构 +状态服务使用字典`schemaStates`以`{appId}-{pageId}`为键存储状态,避免了全局状态污染。 + +```csharp +private IDictionary schemaStates = new Dictionary(); +``` + +### 状态获取与设置 +通过`GetStateSchema`和`SetStateSchema`方法实现状态的安全访问和更新: + +```csharp +private DragDropStateSchema GetStateSchema(string appId, string pageId) +{ + string key = $"{appId}-{pageId}"; + if (schemaStates.TryGetValue(key, out DragDropStateSchema schema)) + return schema; + return null; +} + +private void SetStateSchema(string appId, string pageId, Action action) +{ + string key = $"{appId}-{pageId}"; + if (schemaStates.TryGetValue(key, out DragDropStateSchema stateSchema)) + action(stateSchema); + else + { + stateSchema = new(); + action(stateSchema); + schemaStates[key] = stateSchema; + } +} +``` + +### 关键状态属性 +`DragDropStateSchema`包含以下关键状态属性: + +| 属性名 | 类型 | 说明 | +|--------|------|------| +| `RootComponent` | `ComponentPartsSchema` | 根组件,包含所有子组件 | +| `LastSelectedComponent` | `ComponentPartsSchema` | 最后选中的组件 | +| `CurrentDragComponent` | `ComponentPartsSchema` | 当前正在拖拽的组件 | +| `LastDragOverComponent` | `ComponentPartsSchema` | 最后一次拖拽经过的组件 | +| `LastDropComponent` | `ComponentPartsSchema` | 最后一次放置的组件 | +| `LastDragOverTime` | `DateTime` | 最后一次拖拽经过的时间 | + +**本节来源** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) + +## 拖拽交互时序分析 + +以下是拖拽交互的完整时序流程,展示了各组件与服务之间的调用顺序和数据流向。 + +```mermaid +sequenceDiagram +participant 用户 as "用户" +participant DragItem as "DragItem" +participant DragDropStateService as "DragDropStateService" +participant DraggableItem as "DraggableItem" +participant DraggableContainer as "DraggableContainer" +participant elementUtils as "elementUtils.js" +用户->>DragItem : 点击组件 +DragItem->>DragItem : OnClick() +DragItem->>DragDropStateService : SetCurrentDragComponent() +DragItem->>BlazorEventDispatcher : 发布 designengine.dragitem.onclick 事件 +BlazorEventDispatcher->>DraggableContainer : 订阅事件并调用 DragDropHandler() +DraggableContainer->>DraggableContainer : DragDropHandler() +DraggableContainer->>DragDropStateService : GetLastDragOverComponent() +DraggableContainer->>DraggableContainer : DragItem_Add() +DraggableContainer->>DragDropStateService : ResetDragStyle() +DraggableContainer->>DraggableContainer : StateHasChanged() +用户->>DragItem : 开始拖拽 +DragItem->>DragItem : OnDragStart() +DragItem->>DragDropStateService : SetCurrentDragComponent() +DragItem->>DraggableItem : 触发 ondragstart 事件 +loop 持续位置判断 +DraggableItem->>DraggableItem : OnDragOver() +DraggableItem->>elementUtils : getDimensions() +DraggableItem->>DragDropStateService : SetLastDragOverComponent() +end +用户->>DraggableContainer : 释放拖拽 +DraggableContainer->>DraggableContainer : OnDrop() +DraggableContainer->>DragDropStateService : GetCurrentDragComponent() +DraggableContainer->>DraggableContainer : DragDropHandler() +DraggableContainer->>DragDropStateService : ResetDragStyle() +DraggableContainer->>DraggableContainer : ResetAllAnimationStates() +DraggableContainer->>DraggableContainer : StateHasChanged() +``` + +**图示来源** +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) + +## 视觉反馈与CSS类切换 + +拖拽过程中的视觉反馈通过动态修改组件的CSS类和内联样式实现,提供直观的用户交互体验。 + +### CSS类映射 +`DraggableItem`组件使用`ClassMapper`动态管理CSS类: + +```csharp +private void SetClassMap() +{ + DraggableItemClassMapper.Clear() + .If("draggableitem-selected", () => Component.DesignState.IsSelected) + .If("draggableitem-component", () => Component.IsContainer == false) + .If("draggableitem-container", () => Component.IsContainer); + + DraggableItemBoxClassMapper.Clear() + .If("draggableitem-box-layout", () => Component.IsContainer) + .If("draggableitem-animating", () => Component.DesignState.IsAnimating); +} +``` + +### 内联样式动态更新 +组件的内联样式根据拖拽状态实时更新: + +```html +
+``` + +### 拖拽状态样式 +不同拖拽状态对应不同的视觉效果: + +| 状态 | 样式变化 | 说明 | +|------|---------|------| +| 开始拖拽 | `opacity: 0.8`, `z-index: 9999` | 降低透明度,提升层级 | +| 拖拽经过 | `box-shadow: 0 8px 24px rgba(0,0,0,0.15)` | 添加阴影效果 | +| 选中状态 | 边框高亮,显示操作图标 | 显示删除、复制等操作按钮 | +| 动画进行中 | `transition: transform 0.25s cubic-bezier(0.2, 0, 0.2, 1)` | 平滑动画效果 | + +**本节来源** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [ComponentDesignStateSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentDesignStateSchema.cs) + +## 位置判断与JavaScript工具函数 + +拖拽过程中的位置判断依赖于JavaScript工具函数`elementUtils.js`,通过Blazor的JS互操作实现高性能的位置计算。 + +### elementUtils.js功能 +`elementUtils.js`提供了以下核心功能: + +```javascript +window.elementUtils = { + // 获取元素尺寸信息(包含margin) + getDimensions: function (element) { + if (!element) return null; + + const rect = element.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(element); + const containerWidth = element.parentElement ? element.parentElement.getBoundingClientRect().width : 0; + + const margin = { + top: parseFloat(computedStyle.marginTop), + right: parseFloat(computedStyle.marginRight), + bottom: parseFloat(computedStyle.marginBottom), + left: parseFloat(computedStyle.marginLeft) + }; + + return { + width: rect.width, + height: rect.height, + actualWidth: rect.width + margin.left + margin.right, + actualHeight: rect.height + margin.top + margin.bottom, + containerWidth: containerWidth, + margin: margin, + offsetTop: rect.top, + offsetLeft: rect.left + }; + }, + + // 获取容器信息 + getContainerInfo: function (element) { + if (!element || !element.parentElement) return null; + + const container = element.parentElement; + const containerRect = container.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(container); + + return { + width: containerRect.width, + height: containerRect.height, + padding: { + top: parseFloat(computedStyle.paddingTop), + right: parseFloat(computedStyle.paddingRight), + bottom: parseFloat(computedStyle.paddingBottom), + left: parseFloat(computedStyle.paddingLeft) + } + }; + }, + + // 设置元素的transform属性(优化性能) + setTransform: function (element, transform) { + if (!element) return; + element.style.transform = transform; + element.style.willChange = 'transform'; + }, + + // 节流函数,用于优化拖拽性能 + throttle: function (func, limit) { + let inThrottle; + return function() { + const args = arguments; + const context = this; + if (!inThrottle) { + func.apply(context, args); + inThrottle = true; + setTimeout(() => inThrottle = false, limit); + } + } + } +}; +``` + +### Blazor中的调用 +在`DraggableItem.razor`中通过`IJSRuntime`调用JavaScript函数: + +```csharp +protected override async Task OnAfterRenderAsync(bool firstRender) +{ + if (firstRender) + { + await JSRuntime.InvokeAsync("import", "./_content/H.LowCode.DesignEngineBase/js/elementUtils.js"); + await UpdateDimensions(); + } +} + +private async Task UpdateDimensions() +{ + try + { + dimensions = await JSRuntime.InvokeAsync("elementUtils.getDimensions", itemRef); + } + catch (Exception ex) + { + Console.WriteLine($"Error getting element dimensions: {ex.Message}"); + } +} +``` + +### 防抖机制 +为了提升性能,拖拽过程中的位置更新采用了防抖机制: + +```csharp +private void OnDragOver(DragEventArgs dragEventArgs) +{ + var now = DateTime.Now; + if ((now - lastUpdateTime).TotalMilliseconds < UPDATE_INTERVAL_MS) + return; + + lastUpdateTime = now; + // 处理拖拽逻辑 +} +``` + +**本节来源** +- [elementUtils.js](file://src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) + +## 页面元数据生成 + +当用户在画布上释放拖拽的组件时,系统会生成相应的页面元数据并更新应用模式。 + +### 组件数据结构 +`ComponentPartsSchema`是组件的核心数据结构,包含设计时和运行时所需的所有信息: + +```csharp +public class ComponentPartsSchema : ComponentSchemaBase +{ + [JsonPropertyName("partsId")] + public string PartsId { get; set; }; + + [JsonPropertyName("libid")] + public string LibraryId { get; set; } + + [JsonPropertyName("cn")] + public string ComponentName { get; set; } + + [JsonPropertyName("ct")] + public int ComponentType { get; set; } + + [JsonPropertyName("frag")] + public ComponentPartsFragmentSchema Fragment { get; set; } + + [JsonPropertyName("ds")] + public ComponentPartsDataSourceSchema DataSource { get; set; } = new(); + + [JsonPropertyName("attrdefgroups")] + public IEnumerable AttributeDefineGroups { get; set; } = []; + + [JsonPropertyName("childs")] + public IList Childrens { get; set; } = []; + + [JsonIgnore] + public ComponentDesignStateSchema DesignState { get; set; } = new(); + + [JsonIgnore] + public Action Refresh { get; set; } + + public ComponentPartsSchema DeepClone() + { + // 深拷贝实现 + } +} +``` + +### 深拷贝机制 +新添加的组件通过`DeepClone`方法创建副本,确保每个实例都有唯一的ID: + +```csharp +public ComponentPartsSchema DeepClone() +{ + ComponentPartsSchema newComponent = ObjectExtension.DeepClone(this); + newComponent.Id = ShortIdGenerator.Generate(); + newComponent.ParentId = string.Empty; + newComponent.Name = $"{newComponent.ComponentName}_{Random.Shared.Next(100, 999)}"; + newComponent.DesignState.IsSelected = false; + newComponent.Refresh = Refresh; + DeepCloneRecursive(newComponent, this); + return newComponent; +} +``` + +### 元数据更新流程 +1. 创建组件副本 +2. 设置父级ID +3. 添加到目标容器的子组件列表 +4. 更新UI状态 + +```csharp +private void DragItem_Add(ComponentPartsSchema containerComponent, ComponentPartsSchema currentDragComponent, ComponentPartsSchema dragOverComponent, bool isSelected = false) +{ + currentDragComponent.ParentId = containerComponent.Id; + currentDragComponent.DesignState.IsDroppedFromComponentPanel = false; + + if (isSelected) + { + currentDragComponent.DesignState.IsSelected = isSelected; + DragDropStateService.SetLastSelectedComponent(PageCascading.AppId, PageCascading.PageId, currentDragComponent); + } + currentDragComponent.Refresh = StateHasChanged; + + if (dragOverComponent != null) + { + containerComponent.Childrens.InsertBefore(dragOverComponent, currentDragComponent); + } + else + { + containerComponent.Childrens.Add(currentDragComponent); + } +} +``` + +**本节来源** +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) + +## 错误处理机制 + +系统在拖拽交互过程中实现了多层次的错误处理机制,确保用户体验的稳定性和数据的完整性。 + +### 空值检查 +在关键操作前进行空值检查,防止空引用异常: + +```csharp +private void Init() +{ + if (Component == null) + throw new NullReferenceException(nameof(Component)); +} + +private void LoadRootComponent() +{ + var rootComponent = DragDropStateService.GetRootComponent(PageCascading.AppId, PageCascading.PageId); + if (rootComponent == null) + { + rootComponent = new ComponentPartsSchema(); + rootComponent.Name = "root"; + rootComponent.Refresh = StateHasChanged; + } + return rootComponent; +} +``` + +### JavaScript互操作异常处理 +在调用JavaScript函数时捕获异常,避免前端崩溃: + +```csharp +private async Task UpdateDimensions() +{ + try + { + dimensions = await JSRuntime.InvokeAsync("elementUtils.getDimensions", itemRef); + } + catch (Exception ex) + { + Console.WriteLine($"Error getting element dimensions: {ex.Message}"); + } +} +``` + +### 状态重置机制 +提供专门的状态重置方法,确保异常情况下的状态一致性: + +```csharp +public void ResetDragStyle(string appId, string pageId) +{ + var stateSchema = GetStateSchema(appId, pageId); + if (stateSchema == null) return; + + if (stateSchema.CurrentDragComponent != null) + { + stateSchema.CurrentDragComponent.DesignState.AnimationTransform = string.Empty; + stateSchema.CurrentDragComponent.DesignState.IsAnimating = false; + } + + if (stateSchema.LastSelectedComponent != null) + { + stateSchema.LastSelectedComponent.DesignState.IsSelected = false; + stateSchema.LastSelectedComponent.RefreshState(); + } + + if (stateSchema.LastDragOverComponent != null) + { + stateSchema.LastDragOverComponent.DesignState.DragEffectStyle = string.Empty; + stateSchema.LastDragOverComponent.DesignState.AnimationTransform = string.Empty; + stateSchema.LastDragOverComponent.DesignState.IsAnimating = false; + } +} +``` + +### 事件订阅管理 +实现`IAsyncDisposable`接口,确保事件订阅的正确清理: + +```csharp +public async ValueTask DisposeAsync() +{ + if (IsInRootContainer) + { + BlazorEventDispatcher.Unsubscribe("designengine.pagesetting.pagelayout.onchange", OnPageLayoutChange); + } +} +``` + +**本节来源** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) + +## 关键代码片段 + +### 拖拽开始处理 +```csharp +private void OnDragStart(DragEventArgs dragEventArgs) +{ + isDragging = true; + initialX = dragEventArgs.ClientX; + initialY = dragEventArgs.ClientY; + lastDragX = initialX; + lastDragY = initialY; + lastUpdateTime = DateTime.Now; + + Component.DesignState.DragEffectStyle = "box-shadow: 0 8px 24px rgba(0,0,0,0.15); transform-origin: center;"; + DragDropStateService.SetCurrentDragComponent(PageCascading.AppId, PageCascading.PageId, Component); + ResetAllAnimationStates(); +} +``` + +### 拖拽释放处理 +```csharp +private void OnDrop() +{ + var currentDragComponent = DragDropStateService.GetCurrentDragComponent(PageCascading.AppId, PageCascading.PageId); + DragDropHandler(currentDragComponent); + DragDropStateService.ResetDragStyle(PageCascading.AppId, PageCascading.PageId); + ResetAllAnimationStates(); +} +``` + +### 拖拽处理核心逻辑 +```csharp +private void DragDropHandler(ComponentPartsSchema currentDragComponent) +{ + var dragOverComponent = DragDropStateService.GetLastDragOverComponent(PageCascading.AppId, PageCascading.PageId); + + if (currentDragComponent.DesignState.IsDroppedFromComponentPanel) + { + DragItem_Add(ContainerComponent, currentDragComponent, dragOverComponent); + } + else + { + bool isInnerContainer = ContainerComponent.Childrens.Any(t => t.Id == currentDragComponent.Id); + if (isInnerContainer) + { + DraggableItem_Sorting(ContainerComponent, currentDragComponent, dragOverComponent); + } + else + { + DragItem_Move(ContainerComponent, currentDragComponent, dragOverComponent); + } + } + + StateHasChanged(); + DragDropStateService.SetLastDragOverComponent(PageCascading.AppId, PageCascading.PageId, null); +} +``` + +### 组件添加逻辑 +```csharp +private void DragItem_Add(ComponentPartsSchema containerComponent, ComponentPartsSchema currentDragComponent, ComponentPartsSchema dragOverComponent, bool isSelected = false) +{ + currentDragComponent.ParentId = containerComponent.Id; + currentDragComponent.DesignState.IsDroppedFromComponentPanel = false; + + if (isSelected) + { + currentDragComponent.DesignState.IsSelected = isSelected; + DragDropStateService.SetLastSelectedComponent(PageCascading.AppId, PageCascading.PageId, currentDragComponent); + } + currentDragComponent.Refresh = StateHasChanged; + + if (dragOverComponent != null) + { + containerComponent.Childrens.InsertBefore(dragOverComponent, currentDragComponent); + } + else + { + containerComponent.Childrens.Add(currentDragComponent); + } +} +``` + +**本节来源** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\347\212\266\346\200\201\347\256\241\347\220\206\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\347\212\266\346\200\201\347\256\241\347\220\206\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..6c33645d4e6982a54efb9d10fa2565015ee9e207 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\347\212\266\346\200\201\347\256\241\347\220\206\346\234\215\345\212\241.md" @@ -0,0 +1,249 @@ +# 拖拽状态管理服务 + + +**本文档引用的文件** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [DesignPage.razor](file://src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor) +- [DesignPanel.razor](file://src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor) +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) + + +## 目录 +1. [引言](#引言) +2. [核心属性与状态管理](#核心属性与状态管理) +3. [服务初始化与依赖注入](#服务初始化与依赖注入) +4. [拖拽事件处理流程](#拖拽事件处理流程) +5. [状态变更通知机制](#状态变更通知机制) +6. [状态重置与异常恢复](#状态重置与异常恢复) +7. [并发操作处理](#并发操作处理) +8. [最佳实践与代码示例](#最佳实践与代码示例) + +## 引言 +拖拽状态管理服务(DragDropStateService)是Blazor低代码设计器中的核心全局状态容器,负责在多个可拖拽组件之间协调和共享拖拽相关的状态信息。该服务通过依赖注入机制被所有相关的UI组件(如DraggableItem、DraggableContainer等)所使用,确保了跨组件状态的一致性和同步性。本文档将深入解析该服务的设计与实现,详细说明其如何管理拖拽状态、处理事件以及与其他组件协同工作。 + +## 核心属性与状态管理 + +### DragDropStateSchema 核心属性 +`DragDropStateSchema` 类是拖拽状态服务的数据模型,定义了所有需要在应用中共享的核心状态属性。 + +```mermaid +classDiagram +class DragDropStateSchema { ++ComponentPartsSchema RootComponent ++PagePartsSchema Page ++ComponentPartsSchema LastSelectedComponent ++ComponentPartsSchema CurrentDragComponent ++ComponentPartsSchema LastDragOverComponent ++ComponentPartsSchema LastDropComponent ++DateTime LastDragOverTime +} +``` + +**Diagram sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L203-L237) + +**Section sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L203-L237) + +#### 属性详解 +- **RootComponent**: 存储当前页面的根组件对象,作为所有可拖拽组件的父容器,是构建组件树结构的基础。 +- **Page**: 存储当前页面的元数据信息,如页面ID、名称和布局等。 +- **LastSelectedComponent**: 记录最后一次被选中的组件,即使该组件失去焦点,此属性仍保留其引用,用于实现“最后选中”逻辑。 +- **CurrentDragComponent**: 标识当前正在被拖拽的组件对象,是拖拽操作的核心状态。 +- **LastDragOverComponent**: 记录鼠标指针最后一次悬停在其上方的组件,用于实现放置时的视觉反馈和逻辑判断。 +- **LastDropComponent**: 记录最后一次成功放置的组件,可用于撤销操作或日志记录。 +- **LastDragOverTime**: 记录最后一次拖拽到某个组件上方的时间戳,可用于处理拖拽延迟或防抖逻辑。 + +## 服务初始化与依赖注入 + +### 服务注册与生命周期 +`DragDropStateService` 是一个通过依赖注入(DI)容器管理的单例服务。它在应用启动时被注册,确保在整个应用生命周期内只有一个实例存在,从而保证了状态的全局唯一性。 + +### 组件初始化流程 +多个关键组件在初始化时会与 `DragDropStateService` 进行交互,建立其状态上下文。 + +```mermaid +sequenceDiagram +participant DesignPage as DesignPage.razor +participant DesignPanel as DesignPanel.razor +participant StateService as DragDropStateService +participant ComponentPanel as ComponentPanel.razor +DesignPage->>StateService : SetPage(AppId, pageSchema) +DesignPage->>DesignPanel : 传递 Components 列表 +DesignPanel->>StateService : GetRootComponent(AppId, PageId) +DesignPanel->>StateService : SetRootComponent(AppId, PageId, rootComponent) +ComponentPanel->>StateService : SetCurrentDragComponent(AppId, PageId, component) +``` + +**Diagram sources** +- [DesignPage.razor](file://src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor#L79-L84) +- [DesignPanel.razor](file://src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor#L30-L35) +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor#L42) + +**Section sources** +- [DesignPage.razor](file://src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor#L79-L84) +- [DesignPanel.razor](file://src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor#L30-L35) +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor#L42) + +#### 初始化步骤 +1. **页面加载 (DesignPage)**: 当 `DesignPage` 组件初始化时,它会从后端服务加载页面元数据 (`PagePartsSchema`),然后调用 `DragDropStateService.SetPage()` 将页面信息存储到全局状态中。 +2. **面板构建 (DesignPanel)**: `DesignPanel` 组件在初始化时,首先尝试从 `DragDropStateService` 获取根组件。如果不存在,则创建一个新的根组件,并通过 `SetRootComponent()` 方法将其注册到全局状态。这确保了所有拖拽操作都基于同一个组件树。 +3. **拖拽开始 (ComponentPanel)**: 当用户从组件面板 (`ComponentPanel`) 拖拽一个新组件时,`DragItem` 组件会创建该组件的深拷贝,并立即通过 `SetCurrentDragComponent()` 方法将其设置为当前拖拽对象,从而启动拖拽流程。 + +## 拖拽事件处理流程 + +### 事件处理器集成 +`DragDropStateService` 与 `DraggableItem` 和 `DraggableContainer` 组件的原生拖拽事件(`OnDragStart`, `OnDragOver`, `OnDrop`)紧密集成。 + +```mermaid +flowchart TD +A[OnDragStart] --> B[设置 CurrentDragComponent] +B --> C[添加拖拽视觉反馈] +C --> D[OnDragOver] +D --> E{是否悬停在新组件上?} +E --> |是| F[更新 LastDragOverComponent] +E --> |否| G[触发兄弟组件让位动画] +F --> G +G --> H[OnDrop] +H --> I[执行 DragDropHandler] +I --> J[重置全局状态] +``` + +**Diagram sources** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor#L178-L185) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor#L70-L74) + +**Section sources** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor#L178-L185) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor#L70-L74) + +#### 详细流程 +1. **OnDragStart**: 在 `DraggableItem` 的 `OnDragStart` 事件中,服务被调用以设置 `CurrentDragComponent`。这标志着拖拽操作的开始,并为被拖拽的组件添加了阴影等视觉反馈。 +2. **OnDragOver**: 在 `DraggableContainer` 的 `OnDragOver` 事件中,服务被用来获取 `CurrentDragComponent` 和 `LastDragOverComponent`。通过比较,可以判断鼠标是否悬停在了一个新的目标容器上。如果是,则更新 `LastDragOverComponent` 并触发兄弟组件的“让位”动画,为放置腾出空间。 +3. **OnDrop**: 当在 `DraggableContainer` 上释放时,`OnDrop` 事件被触发。`DragDropHandler` 方法会根据 `CurrentDragComponent` 的来源(是来自组件面板还是页面内部)执行不同的逻辑(新增、排序或移动),并在操作完成后调用 `ResetDragStyle()` 来清理状态。 + +## 状态变更通知机制 + +### SetStateSchema 方法 +服务内部通过 `SetStateSchema` 方法来安全地修改状态,这是实现状态变更通知的核心。 + +```csharp +private void SetStateSchema(string appId, string pageId, Action action) +{ + string key = $"{appId}-{pageId}"; + + if (schemaStates.TryGetValue(key, out DragDropStateSchema stateSchema)) + action(stateSchema); + else + { + stateSchema = new(); + action(stateSchema); + schemaStates[key] = stateSchema; + } +} +``` + +**Section sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L110-L128) + +#### 机制分析 +- **键值存储**: 状态以字典 `schemaStates` 的形式存储,键由 `appId` 和 `pageId` 拼接而成,实现了多页面、多应用的隔离。 +- **原子性操作**: `SetStateSchema` 接收一个 `Action` 委托。如果指定键的状态已存在,则直接在现有对象上执行操作;否则,创建一个新对象,执行操作后存入字典。这种方式确保了状态修改的原子性。 +- **直接引用修改**: 由于 `DragDropStateSchema` 是引用类型,`SetStateSchema` 内部对 `stateSchema` 对象的修改会直接反映到字典中存储的实例上。当其他组件通过 `GetCurrentDragComponent()` 等方法获取该对象时,它们拿到的是同一个引用,因此能立即看到最新的状态变化,实现了“通知”效果。 + +## 状态重置与异常恢复 + +### 重置方法 +服务提供了两个关键的重置方法,用于清理状态和恢复UI。 + +```mermaid +classDiagram +class DragDropStateService { ++void ResetComponent(string appId, string pageId) ++void ResetDragStyle(string appId, string pageId) +} +``` + +**Diagram sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L148-L185) + +**Section sources** +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs#L148-L185) + +#### 方法详解 +- **ResetComponent**: 此方法将 `LastSelectedComponent`、`CurrentDragComponent` 和 `LastDragOverComponent` 三个核心引用属性重置为 `default`(即 `null`)。这通常在组件销毁或页面切换时调用,用于彻底清除特定页面的拖拽上下文。 +- **ResetDragStyle**: 这是一个更精细的重置方法,专门用于UI清理。它会: + 1. 清除 `CurrentDragComponent` 的 `AnimationTransform` 和 `IsAnimating` 状态。 + 2. 如果 `LastSelectedComponent` 存在,则将其 `IsSelected` 设为 `false` 并刷新其状态。 + 3. 清除 `LastDragOverComponent` 的 `DragEffectStyle` 和动画状态。 + 4. 遍历根组件下的所有子组件,重置它们的动画状态。 + 该方法在 `OnDragEnd` 和 `OnDrop` 事件的末尾被调用,确保拖拽操作结束后,所有相关的视觉反馈都被清除。 + +## 并发操作处理 + +### 线程安全考量 +在Blazor WebAssembly应用中,所有代码通常在单个UI线程上执行,因此 `DragDropStateService` 的字典操作(`TryGetValue`, `Add`)在默认情况下是线程安全的,无需额外的锁机制。 + +### 防抖与性能优化 +虽然服务本身不直接处理并发,但与之集成的UI组件实现了防抖机制来优化性能。 + +```csharp +private const int UPDATE_INTERVAL_MS = 16; // 约60fps的更新频率 +private DateTime lastUpdateTime = DateTime.MinValue; + +private void OnDragOver(DragEventArgs dragEventArgs) +{ + var now = DateTime.Now; + if ((now - lastUpdateTime).TotalMilliseconds < UPDATE_INTERVAL_MS) + return; + lastUpdateTime = now; + // ... 处理逻辑 +} +``` + +**Section sources** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor#L199-L205) + +此代码片段展示了 `DraggableItem` 组件如何通过限制 `OnDragOver` 事件的处理频率(约每16毫秒一次)来防止因鼠标快速移动而产生的过多状态更新,从而避免了不必要的UI重渲染。 + +## 最佳实践与代码示例 + +### 状态重置最佳实践 +在组件的 `Dispose` 方法中调用 `ResetComponent` 是一个良好的实践,可以防止内存泄漏。 + +```csharp +public void Dispose() +{ + DragDropStateService.ResetComponent(PageCascading.AppId, PageCascading.PageId); +} +``` + +**Section sources** +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor#L254) + +### 异常恢复代码示例 +以下是一个在 `OnDragEnd` 事件中进行异常恢复的完整示例,它确保了无论拖拽过程是否正常结束,UI状态都能被正确清理。 + +```csharp +private void OnDragEnd(DragEventArgs e) +{ + isDragging = false; + // ... 重置本地变量 + + // 清理所有拖动相关的样式和状态 + Component.DesignState.DragEffectStyle = string.Empty; + Component.DesignState.AnimationTransform = string.Empty; + Component.DesignState.IsAnimating = false; + + // 重置所有组件的动画状态 + ResetAllAnimationStates(); + + // 使用DragDropStateService的重置方法确保状态一致性 + DragDropStateService.ResetDragStyle(PageCascading.AppId, PageCascading.PageId); +} +``` + +**Section sources** +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor#L220-L237) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\351\241\271\350\247\206\350\247\211\350\256\276\350\256\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\351\241\271\350\247\206\350\247\211\350\256\276\350\256\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..f024aad315aa2edcdff23e76ec7dfd59af944ffc --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\346\213\226\346\213\275\351\241\271\350\247\206\350\247\211\350\256\276\350\256\241.md" @@ -0,0 +1,208 @@ +# 拖拽项视觉设计 + + +**本文档中引用的文件** +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [DraggableItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [ComponentItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/ComponentItem.razor) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构分析](#项目结构分析) +3. [核心组件分析](#核心组件分析) +4. [DragItem.razor.css 样式详解](#dragitemrazorcss-样式详解) +5. [DraggableItem 组件实现机制](#draggableitem-组件实现机制) +6. [组件绑定与数据模型](#组件绑定与数据模型) +7. [拖拽交互逻辑分析](#拖拽交互逻辑分析) +8. [响应式设计与高分辨率适配](#响应式设计与高分辨率适配) +9. [结论](#结论) + +## 引言 +本文档详细说明了在低代码设计引擎中,`DragItem.razor.css` 文件定义的 CSS 类如何控制组件面板中可拖拽项的外观与布局。通过深入分析样式规则对边框、阴影、过渡动画、悬停效果的实现机制,并结合 Blazor 组件模板分析其与 `DraggableItem` 组件的绑定关系,全面阐述了拖拽项的视觉设计体系。文档还提供了实际样式应用示例,展示了不同组件类型在拖拽面板中的视觉差异化呈现,并探讨了响应式设计考量及在高分辨率屏幕下的适配策略。 + +## 项目结构分析 +项目采用分层架构设计,主要分为 `Common`、`DesignEngine` 和 `RenderEngine` 三大模块。`DesignEngine` 模块负责设计时的用户界面和交互逻辑,其中 `H.LowCode.DesignEngine` 和 `H.LowCode.PartsDesignEngine` 子模块分别处理主设计面板和部件设计面板的可拖拽项。`DragItem.razor.css` 文件位于 `ComponentPanel` 目录下,是控制组件面板中可拖拽项视觉表现的核心样式文件。 + +```mermaid +graph TB +subgraph "DesignEngine" +DP[DesignEngine] +PDE[PartsDesignEngine] +DEB[DesignEngineBase] +end +subgraph "Common" +CM[MetaSchema.DesignEngine] +CB[ComponentBase] +end +DP --> DEB +PDE --> DEB +DEB --> CM +DEB --> CB +``` + +**Diagram sources** +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) + +## 核心组件分析 +系统中的核心可拖拽组件包括 `DragItem`、`DraggableItem` 和 `DraggableContainer`。`DragItem` 是组件面板中的可拖拽项,用于将组件添加到设计面板;`DraggableItem` 是设计面板中已放置的可拖拽组件实例;`DraggableContainer` 是用于容纳其他组件的容器。这些组件通过 `DragDropStateService` 服务进行状态管理和事件通信,形成了完整的拖拽交互体系。 + +**Section sources** +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) + +## DragItem.razor.css 样式详解 +`DragItem.razor.css` 文件定义了 `.dragitem` 类,该类控制了组件面板中可拖拽项的基本外观和交互效果。 + +### 基础布局与外观 +`.dragitem` 类通过以下属性定义了可拖拽项的基础样式: +- **浮动布局**:`float: left` 使多个可拖拽项在面板中水平排列。 +- **尺寸控制**:`width: 6.8rem; height: 2.2rem` 定义了项的固定尺寸,确保视觉一致性。 +- **居中对齐**:`display: flex; justify-content: center; align-items: center` 实现了内容在项内的水平和垂直居中。 +- **视觉样式**:`color: #333; background-color: #f5f7fa` 定义了默认的文字颜色和背景色,提供清晰的视觉层次。 + +### 悬停效果 +`.dragitem:hover` 选择器定义了鼠标悬停时的视觉反馈: +- **边框变化**:`border: #409eff dashed 1px` 将边框变为蓝色虚线,明确指示该项可交互。 +- **文字变色**:`color: #409eff` 将文字颜色变为蓝色,增强视觉反馈,提升用户体验。 + +```mermaid +classDiagram +class DragItemStyle { ++float : left ++width : 6.8rem ++height : 2.2rem ++margin : 4px ++cursor : pointer ++display : flex ++justify-content : center ++align-items : center ++color : #333 ++background-color : #f5f7fa +} +class DragItemHoverStyle { ++border : #409eff dashed 1px ++color : #409eff +} +DragItemStyle <|-- DragItemHoverStyle : "hover" +``` + +**Diagram sources** +- [DragItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css) + +## DraggableItem 组件实现机制 +`DraggableItem` 组件是设计面板中可拖拽项的核心实现,其样式和行为由 `DraggableItem.razor.css` 文件定义。 + +### 外层容器样式 +`.draggableitem-box` 类定义了外层容器的样式: +- **固定高度**:`height: 85px` 为容器提供统一的高度基准。 +- **边框与过渡**:`border: #f0f2f5 solid 2px` 定义了浅灰色边框,`transition: all 0.25s cubic-bezier(0.2, 0, 0.2, 1)` 为所有属性变化添加平滑的过渡动画。 +- **3D 变换优化**:`backface-visibility: hidden; transform-style: preserve-3d` 优化了 3D 变换的性能。 + +### 内层项样式 +`.draggableitem` 类定义了内层可拖拽项的样式: +- **相对定位**:`position: relative` 允许内部元素进行绝对定位。 +- **光标样式**:`cursor: grab` 在鼠标悬停时显示抓取光标,直观地提示用户可以拖拽。 +- **过渡效果**:`transition: all 0.2s ease-out` 为状态变化提供流畅的动画。 + +### 交互状态样式 +组件定义了多种交互状态的样式类: +- **选中状态**:`.draggableitem-selected` 添加蓝色实线轮廓和阴影,明确指示当前选中项。 +- **拖拽中状态**:`.draggableitem-dragging` 提升 `z-index` 至 9999,确保拖拽项位于最上层,并增加阴影深度。 +- **拖拽目标状态**:`.draggableitem-drag-over` 改变背景色和边框样式,清晰地指示可放置区域。 +- **让位动画状态**:`.draggableitem-moving` 降低透明度,视觉上表示该组件正在为拖拽项让位。 + +```mermaid +stateDiagram-v2 +[*] --> Normal +Normal --> Selected : "点击" +Selected --> Dragging : "开始拖拽" +Dragging --> DragOver : "拖拽到目标上" +DragOver --> Normal : "拖拽结束" +Dragging --> Moving : "触发让位动画" +Moving --> Normal : "动画结束" +class Normal draggableitem +class Selected draggableitem-selected +class Dragging draggableitem-dragging +class DragOver draggableitem-drag-over +class Moving draggableitem-moving +``` + +**Diagram sources** +- [DraggableItem.razor.css](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css) + +## 组件绑定与数据模型 +`DragItem` 和 `DraggableItem` 组件通过 `ComponentPartsSchema` 数据模型与后端逻辑进行绑定。 + +### 数据模型结构 +`ComponentPartsSchema` 类是可拖拽项的核心数据模型,其关键属性包括: +- **标识信息**:`ComponentId`、`ComponentName`、`Label` 用于唯一标识和显示组件。 +- **类型信息**:`ComponentType` 区分原子组件和组合组件,`IsContainer` 标记是否为容器。 +- **设计状态**:`DesignState` 属性(`[JsonIgnore]`)存储设计时的临时状态,如 `IsSelected`、`IsAnimating` 等,这些状态不持久化。 + +### 组件绑定机制 +在 `DragItem.razor` 中,通过 `[Parameter] public ComponentPartsSchema Component { get; set; }` 将数据模型注入组件。组件的显示内容 `@Component.Label` 直接绑定到模型的 `Label` 属性。当用户点击或拖拽时,组件会调用 `DragDropStateService` 服务,将 `Component` 的深拷贝(通过 `DeepClone()` 方法)传递给设计面板,实现了数据的解耦和安全传递。 + +**Section sources** +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) + +## 拖拽交互逻辑分析 +系统的拖拽交互逻辑通过 Blazor 事件和 `DragDropStateService` 服务协同实现。 + +### 事件流分析 +```mermaid +sequenceDiagram +participant User as "用户" +participant DragItem as "DragItem" +participant Service as "DragDropStateService" +participant DraggableItem as "DraggableItem" +participant Container as "DraggableContainer" +User->>DragItem : 点击或拖拽 +DragItem->>Service : SetCurrentDragComponent() +Service-->>DragItem : 设置当前拖拽组件 +User->>DraggableItem : 拖拽到目标区域 +DraggableItem->>Service : SetLastDragOverComponent() +Service-->>DraggableItem : 记录最后拖拽到的组件 +User->>Container : 释放拖拽 +Container->>Service : OnDrop() +Service->>Container : 执行 DragDropHandler +Container->>Container : 添加或移动组件 +Container->>Service : ResetDragStyle() +Service-->>Container : 重置所有状态 +``` + +**Diagram sources** +- [DragItem.razor](file://src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor) +- [DraggableItem.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor) +- [DraggableContainer.razor](file://src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) + +### 实际应用示例 +不同类型的组件在拖拽面板中通过 `ComponentItem` 组件进行差异化呈现: +- **表单组件**:显示为带有输入框图标的项,背景色为浅蓝色。 +- **容器组件**:显示为带有网格图标的项,背景色为浅灰色,尺寸更大。 +- **按钮组件**:显示为带有手形图标的项,背景色为浅绿色。 + +这种视觉差异化帮助用户快速识别组件类型,提升设计效率。 + +## 响应式设计与高分辨率适配 +系统通过多种机制实现响应式设计和高分辨率适配。 + +### 响应式布局 +`DraggableItem` 组件的宽度通过计算动态设置:`width: @((Component.Style.ItemWidth > 4 ? Component.Style.ItemWidth : (IsInRootContainer ? 24/PageCascading.PageLayout : 24)) /24 * 100)%`。该表达式根据 `PageLayout`(如 12 或 24 列)动态计算宽度百分比,确保在不同屏幕尺寸下都能合理布局。 + +### 高分辨率适配 +- **GPU 加速**:大量使用 `transform: translate3d()` 和 `backface-visibility: hidden`,触发 GPU 硬件加速,确保在高分辨率屏幕上动画流畅。 +- **防抖机制**:在 `OnDragOver` 事件中使用 `UPDATE_INTERVAL_MS` 常量(约 16ms)限制更新频率,防止在高刷新率屏幕上产生性能瓶颈。 +- **清晰的视觉反馈**:使用 `box-shadow` 和 `rgba` 颜色值,在高 PPI 屏幕上提供细腻的视觉层次。 + +## 结论 +本文档全面分析了低代码平台中拖拽项的视觉设计体系。`DragItem.razor.css` 通过简洁的 CSS 规则定义了组件面板中可拖拽项的基础样式和悬停效果。`DraggableItem` 组件利用丰富的 CSS 类和 Blazor 事件,实现了复杂的拖拽交互、动画效果和状态管理。通过 `ComponentPartsSchema` 数据模型,实现了组件与数据的紧密绑定。整个系统采用响应式设计,并通过 GPU 加速等技术确保在高分辨率屏幕上的流畅体验。这一设计模式为构建直观、高效的低代码设计界面提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\351\241\265\351\235\242\345\261\236\346\200\247\350\256\276\347\275\256\347\225\214\351\235\242.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\351\241\265\351\235\242\345\261\236\346\200\247\350\256\276\347\275\256\347\225\214\351\235\242.md" new file mode 100644 index 0000000000000000000000000000000000000000..bbe17b1c05f5ba8baedc796c1d3592d413afa46e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/UI\347\273\204\344\273\266\344\270\216\344\272\244\344\272\222/\351\241\265\351\235\242\345\261\236\346\200\247\350\256\276\347\275\256\347\225\214\351\235\242.md" @@ -0,0 +1,234 @@ +# 页面属性设置界面 + + +**本文档引用的文件** +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [EventTargetTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/EventTargetTypeEnum.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [designengine.css](file://src/DesignEngine/H.LowCode.DesignEngine/wwwroot/designengine.css) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入解析 `PageSetting.razor.css` 在页面属性配置面板中的作用,说明其定义的布局结构、表单控件样式、标签对齐方式及响应式断点设置。结合 `SettingPanel` 组件分析 CSS 类如何与 Blazor 的 `EditForm`、`InputText` 等组件协同工作,实现动态属性编辑界面。展示页面背景色、尺寸、边距等配置项的 UI 呈现逻辑,并解释主题变量的使用方式以支持未来主题扩展。 + +## 项目结构 +项目采用模块化分层架构,主要分为 `meta`(元数据)、`src`(源码)和工具模块。`src` 目录下包含 `Common`(通用组件)、`DesignEngine`(设计引擎)、`RenderEngine`(渲染引擎)等核心模块。页面属性设置功能位于 `DesignEngine` 模块的 `SettingPanel` 组件中,通过 `PageSetting.razor` 和 `PageSetting.razor.css` 实现。 + +```mermaid +graph TB +subgraph "DesignEngine" +PageSetting[PageSetting.razor] +PageSettingCSS[PageSetting.razor.css] +designengineCSS[designengine.css] +end +subgraph "Common" +PagePropertySchema[PagePropertySchema.cs] +PageDataSourceSchema[PageDataSourceSchema.cs] +PageTypeEnum[PageTypeEnum.cs] +EventSchema[EventSchema.cs] +EventTargetTypeEnum[EventTargetTypeEnum.cs] +PagePartsSchema[PagePartsSchema.cs] +end +PageSetting --> PageSettingCSS +PageSetting --> designengineCSS +PageSetting --> PagePropertySchema +PageSetting --> PageDataSourceSchema +PageSetting --> PageTypeEnum +PageSetting --> EventSchema +PageSetting --> PagePartsSchema +``` + +**图示来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) +- [designengine.css](file://src/DesignEngine/H.LowCode.DesignEngine/wwwroot/designengine.css) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [EventTargetTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/EventTargetTypeEnum.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) + +**本节来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) + +## 核心组件 +`PageSetting.razor` 是页面属性配置面板的核心组件,它使用 Blazor 框架构建,通过绑定 `PagePartsSchema` 模型实现对页面属性的动态编辑。其对应的 CSS 文件 `PageSetting.razor.css` 定义了 `.pagesetting-item` 类,用于统一配置项的外边距,确保 UI 布局的一致性。 + +**本节来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) + +## 架构概览 +系统采用前后端分离架构,`DesignEngine` 负责可视化设计,`RenderEngine` 负责运行时渲染。`PageSetting` 组件作为 `DesignEngine` 的一部分,通过 `DragDropStateService` 获取当前编辑的 `PagePartsSchema` 实例,并利用 Blazor 的数据绑定机制 (`@bind-Value`) 将 UI 操作实时同步到模型中。 + +```mermaid +sequenceDiagram +participant UI as "UI (PageSetting.razor)" +participant Component as "PageSetting 组件" +participant Service as "DragDropStateService" +participant Model as "PagePartsSchema" +UI->>Component : 用户更改布局 +Component->>Model : 更新 Page.PageProperty.PageLayout +Component->>Service : 发布 "designengine.pagesetting.pagelayout.onchange" 事件 +Service->>Model : 通知其他组件布局已更改 +Model-->>Component : 返回新布局 +Component-->>UI : 重新渲染界面 +``` + +**图示来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [DragDropStateService.cs](file://src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) + +## 详细组件分析 + +### PageSetting 组件分析 +`PageSetting` 组件根据 `Page` 模型的状态动态渲染不同的配置项。其核心功能包括布局选择、数据源配置、自定义样式编辑和事件管理。 + +#### 布局与样式结构 +组件使用 `div` 容器和 `label` 标签构建表单项,通过 `pagesetting-item` CSS 类控制外边距。Ant Design Blazor 的 `RadioGroup`、`Input`、`TextArea` 等组件用于提供用户交互。 + +```mermaid +classDiagram +class PageSetting { ++Page : PagePartsSchema ++OnLayoutChange(pageLayout : int) : void ++OnStyleChange(customStyle : string) : void ++ShowEventModal() : void ++OnEventConfirm() : void +} +class PagePartsSchema { ++PageProperty : PagePropertySchema ++DataSource : PageDataSourceSchema ++PageType : PageTypeEnum ++Events : IList~EventSchema~ ++SupportEvents : string[] +} +class PagePropertySchema { ++PageLayout : int ++TitleWidth : string ++DefaultStyle : string ++CustomStyle : string +} +class PageDataSourceSchema { ++DataSourceType : PageDataSourceTypeEnum ++DataSourceValue : string +} +class EventSchema { ++EventName : string ++EventHandlerType : EventTargetTypeEnum ++EventCustomScript : string +} +PageSetting --> PagePartsSchema : "使用" +PagePartsSchema --> PagePropertySchema : "包含" +PagePartsSchema --> PageDataSourceSchema : "包含" +PagePartsSchema --> EventSchema : "包含" +``` + +**图示来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) + +#### 条件渲染逻辑 +组件使用 Razor 语法进行条件渲染。当 `Page.PageType` 为 `Form` 时,显示数据源配置区域。根据 `DataSourceType` 的不同,动态显示“表”或“API”输入框。 + +```mermaid +flowchart TD +Start([开始]) --> CheckPage{"Page != null?"} +CheckPage --> |是| CheckForm{"Page.PageType == Form?"} +CheckForm --> |是| ShowDataSource["显示数据源配置"] +CheckForm --> |否| SkipDataSource["跳过"] +ShowDataSource --> CheckDB{"DataSourceType == DB?"} +CheckDB --> |是| ShowTableInput["显示表输入框"] +CheckDB --> |否| CheckAPI{"DataSourceType == API?"} +CheckAPI --> |是| ShowAPISection["显示API配置"] +CheckAPI --> |否| End +SkipDataSource --> ShowOther["显示其他配置"] +ShowTableInput --> ShowOther +ShowAPISection --> ShowOther +ShowOther --> ShowEvent["显示事件配置"] +ShowEvent --> End([结束]) +``` + +**图示来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) + +**本节来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) + +## 依赖分析 +`PageSetting` 组件依赖于多个核心模型和样式文件。`PagePartsSchema` 作为数据模型,聚合了页面的所有配置信息。`PagePropertySchema` 和 `PageDataSourceSchema` 提供了具体的属性定义。`designengine.css` 提供了全局样式覆盖,确保组件在 `settingpanel` 容器中正确显示。 + +```mermaid +graph TD +PageSettingCSS --> designengineCSS +PageSetting --> PageSettingCSS +PageSetting --> designengineCSS +PageSetting --> PagePartsSchema +PagePartsSchema --> PagePropertySchema +PagePartsSchema --> PageDataSourceSchema +PagePartsSchema --> EventSchema +PagePartsSchema --> PageTypeEnum +``` + +**图示来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) +- [designengine.css](file://src/DesignEngine/H.LowCode.DesignEngine/wwwroot/designengine.css) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [PagePropertySchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs) +- [PageDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) + +**本节来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) +- [PageSetting.razor.css](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css) +- [designengine.css](file://src/DesignEngine/H.LowCode.DesignEngine/wwwroot/designengine.css) + +## 性能考量 +组件的性能主要受数据绑定和事件发布的影响。`OnLayoutChange` 方法通过 `BlazorEventDispatcher` 发布事件,避免了直接操作 DOM,保证了响应式更新的效率。`TextArea` 的 `OnChange` 事件在用户输入时触发,应考虑防抖处理以优化性能。 + +## 故障排除指南 +- **问题:配置项未保存** + - 检查 `@bind-Value` 是否正确绑定到 `Page` 模型的属性。 + - 确认 `Page` 模型是否为引用类型且在父组件中正确传递。 +- **问题:UI 样式错乱** + - 检查 `designengine.css` 是否被正确加载。 + - 确认 `settingpanel` 容器的高度是否设置为 100%。 +- **问题:事件配置模态框不显示** + - 检查 `_eventVisible` 变量的绑定是否正确。 + - 确认 `Modal` 组件的 `Width` 属性是否设置合理。 + +**本节来源** +- [PageSetting.razor](file://src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor) + +## 结论 +`PageSetting.razor.css` 通过定义 `.pagesetting-item` 类,为页面属性配置面板提供了统一的布局间距。`PageSetting.razor` 组件巧妙地结合 Blazor 的数据绑定和条件渲染,实现了动态、响应式的属性编辑界面。通过 `PagePropertySchema` 和 `PageDataSourceSchema` 等模型,系统将复杂的页面配置逻辑抽象为清晰的数据结构,为未来的主题扩展和功能迭代奠定了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/Entity Framework Core\344\273\223\345\202\250\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/Entity Framework Core\344\273\223\345\202\250\345\256\236\347\216\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..80096483c4eaf89ee5f430758745f004167cbf51 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/Entity Framework Core\344\273\223\345\202\250\345\256\236\347\216\260.md" @@ -0,0 +1,294 @@ +# Entity Framework Core仓储实现 + + +**本文档引用的文件** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) +- [TableDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/TableDataRepository.cs) +- [EntityTypeManager.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityManager/EntityTypeManager.cs) +- [ReadOnlySaveChangesInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/ReadOnlySaveChangesInterceptor.cs) +- [QueryWithNoLockDbCommandInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/QueryWithNoLockDbCommandInterceptor.cs) +- [IFormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/DataRepositories/IFormDataRepository.cs) +- [EntityBase.cs](file://src/Common/H.LowCode.Entity/Base/EntityBase.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档详细解析基于Entity Framework Core的数据库仓储实现,重点阐述`FormDataRepository`和`TableDataRepository`如何通过`DesignEngineDbContext`访问关系型数据库,实现表单与表格数据的增删改查(CRUD)操作。文档将深入分析`DbContext`的实体映射配置、查询优化策略(如使用`NoLock`提示)以及通过`EntityTypeManager`动态管理实体类型的机制。同时,将探讨`ReadOnlySaveChangesInterceptor`等扩展组件在保障数据一致性方面的作用。最后,对比JSON文件存储,说明EF Core在事务支持、并发控制和复杂查询方面的优势,以及相应的配置与迁移管理方法。 + +## 项目结构 +本项目采用分层架构,主要分为`Common`、`DesignEngine`和`RenderEngine`三大模块。`Common`模块存放跨领域共享的实体、配置和基础类。`DesignEngine`和`RenderEngine`分别负责设计时和运行时的功能,两者都实现了基于EF Core的数据访问层。`DesignEngine.EntityFrameworkCore`项目是分析的核心,它包含了`DesignEngineDbContext`、仓储实现、实体类型管理器和EF Core拦截器等关键组件。 + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) + +## 核心组件 +核心组件包括`DesignEngineDbContext`、`FormDataRepository`、`TableDataRepository`、`EntityTypeManager`以及`ReadOnlySaveChangesInterceptor`和`QueryWithNoLockDbCommandInterceptor`两个拦截器。`DesignEngineDbContext`是EF Core的数据库上下文,负责管理实体的生命周期和数据库连接。`FormDataRepository`和`TableDataRepository`是具体的仓储实现,为上层业务逻辑提供数据访问接口。`EntityTypeManager`负责在运行时动态创建和管理实体类型。拦截器则用于在数据保存和查询执行前进行干预,以实现特定的业务规则和性能优化。 + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) +- [TableDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/TableDataRepository.cs) +- [EntityTypeManager.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityManager/EntityTypeManager.cs) +- [ReadOnlySaveChangesInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/ReadOnlySaveChangesInterceptor.cs) +- [QueryWithNoLockDbCommandInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/QueryWithNoLockDbCommandInterceptor.cs) + +## 架构概述 +系统采用经典的领域驱动设计(DDD)分层架构,分为表现层、应用层、领域层和基础设施层。在基础设施层,`DesignEngineDbContext`作为EF Core的入口,通过仓储模式(Repository Pattern)为领域层提供数据访问服务。`EntityTypeManager`利用反射和动态程序集技术,在运行时根据元数据配置动态生成实体类,实现了高度的灵活性。EF Core拦截器则提供了非侵入式的横切关注点(如只读保护和查询优化)实现方式。 + +```mermaid +graph TB +subgraph "表现层" +UI[用户界面] +end +subgraph "应用层" +AppService[应用服务] +end +subgraph "领域层" +DomainService[领域服务] +Repository[仓储接口] +end +subgraph "基础设施层" +EFCore[Entity Framework Core] +DbContext[DesignEngineDbContext] +RepositoryImpl[仓储实现] +EntityTypeManager[EntityTypeManager] +Interceptors[拦截器] +end +UI --> AppService +AppService --> DomainService +DomainService --> Repository +Repository --> RepositoryImpl +RepositoryImpl --> DbContext +DbContext --> EFCore +DbContext --> EntityTypeManager +DbContext --> Interceptors +``` + +**Diagram sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) +- [EntityTypeManager.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityManager/EntityTypeManager.cs) + +## 详细组件分析 + +### DesignEngineDbContext 分析 +`DesignEngineDbContext`是整个数据访问层的核心。它继承自`DbContext`,并重写了`OnModelCreating`和`OnConfiguring`方法。 + +#### OnModelCreating 方法 +该方法在模型创建时被调用,负责配置实体与数据库表的映射关系。其核心逻辑是通过`EntityTypeManager`加载所有动态实体(`LoadDynamicEntities`),然后为每个实体执行以下配置: +1. **表映射**:使用`ToTable`方法将实体类型映射到指定的表名。 +2. **属性映射**:调用`ConfigureProperties`方法,根据`DynamicEntityInfo`中的字段信息,为每个属性配置数据类型、长度、精度、是否可空、默认值和注释。 +3. **主键配置**:使用`HasKey`方法指定主键字段。 +4. **查询过滤器**:如果实体启用了软删除(`EnableSoftDelete`),则添加一个查询过滤器`HasQueryFilter`,自动在所有查询中添加`IsDeleted = 0`的条件,实现逻辑删除。 + +```mermaid +classDiagram +class DesignEngineDbContext { ++string AppId ++Task AddAsync(FormEntity formEntity) ++Task UpdateAsync(FormEntity formEntity) ++Task GetAsync(string tableName, string id) ++int SaveChangesAsync(FormEntity formEntity) ++Type GetEntityType(string tableName) +-void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +-void OnModelCreating(ModelBuilder modelBuilder) +-void ConfigureProperties(EntityTypeBuilder entityBuilder, DynamicEntityInfo dynamicEntity, Type entityType) +-LambdaExpression SoftDeleteQueryFilterExpression(Type entityClrType) +} +class DbContext { +<> +} +class DynamicEntityInfo { ++string EntityName ++Type EntityType ++string PrimaryKey ++bool EnableSoftDelete ++IReadOnlyList Fields +} +class DynamicEntityField { ++string Name ++Type ClrType ++bool IsNullable ++int? MaxLength ++int? Precision ++int? Scale ++object DefaultValue ++string Comment +} +DesignEngineDbContext --|> DbContext : 继承 +DesignEngineDbContext --> DynamicEntityInfo : 使用 +DesignEngineDbContext --> DynamicEntityField : 使用 +``` + +**Diagram sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +#### OnConfiguring 方法 +该方法在上下文配置时被调用,用于设置数据库连接和注册服务。关键配置包括: +1. **注册拦截器**:添加了`ReadOnlySaveChangesInterceptor`和`QueryWithNoLockDbCommandInterceptor`。 +2. **替换验证服务**:使用`CustomizeRelationalModelValidator`来处理可能的表重复注册问题。 + +### FormDataRepository 分析 +`FormDataRepository`实现了`IFormDataRepository`接口,是`FormEntity`数据访问的具体实现。 + +#### 接口契约 +`IFormDataRepository`定义了对表单数据的基本CRUD操作: +- `Task AddAsync(FormEntity entity)`:异步添加新实体。 +- `Task UpdateAsync(FormEntity entity)`:异步更新现有实体。 +- `Task GetAsync(string entityName, string id)`:根据实体名和ID异步获取实体。 +- `Task DeleteAsync(string entityName, string id)`:根据实体名和ID异步删除实体。 + +#### 实现分析 +`FormDataRepository`的实现非常简洁,它通过依赖注入获取`DesignEngineDbContext`实例,并将大部分操作委托给`DbContext`。 +- `AddAsync`和`GetAsync`方法直接调用了`DbContext`中对应的`AddAsync`和`GetAsync`方法。 +- `UpdateAsync`和`DeleteAsync`方法尚未实现(`NotImplementedException`),这表明该功能可能仍在开发中或由其他机制处理。 + +```mermaid +classDiagram +class FormDataRepository { +-DesignEngineDbContext _dbContext ++bool? IsChangeTrackingEnabled ++FormDataRepository(DesignEngineDbContext dbContext) ++Task AddAsync(FormEntity entity) ++Task GetAsync(string tableName, string id) ++Task UpdateAsync(FormEntity entity) ++Task DeleteAsync(string entityName, string id) +} +class IFormDataRepository { +<> ++Task AddAsync(FormEntity entity) ++Task UpdateAsync(FormEntity entity) ++Task GetAsync(string entityName, string id) ++Task DeleteAsync(string entityName, string id) +} +class FormEntity { ++string Name ++List Fields +} +class FormFieldEntity { ++string Name ++string TypeName ++object Value +} +FormDataRepository --> IFormDataRepository : 实现 +FormDataRepository --> DesignEngineDbContext : 依赖 +FormDataRepository --> FormEntity : 使用 +FormDataRepository --> FormFieldEntity : 使用 +``` + +**Diagram sources** +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) +- [IFormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/DataRepositories/IFormDataRepository.cs) + +### EntityTypeManager 分析 +`EntityTypeManager`是实现动态实体的关键组件。它在运行时根据元数据(如JSON配置文件)动态创建.NET类型。 + +#### 工作流程 +1. **初始化程序集**:`InitDynamicAssembly`方法创建一个名为`H.LowCode.DynamicEntity`的动态程序集和模块,所有动态生成的实体类都将定义于此。 +2. **加载元数据**:通过`IDataSourceDomainService`从`caseapp`应用中获取所有实体的元数据(字段、主键、是否启用软删除等)。 +3. **创建实体类型**:对于每个元数据实体,调用`EntityFactory.CreateEntityType`方法,在动态模块中创建一个新的`Type`。该方法会为每个字段定义属性。 +4. **缓存信息**:将创建的`Type`和元数据信息封装成`DynamicEntityInfo`对象,并缓存起来,避免重复创建。 + +#### 与DbContext的集成 +`DesignEngineDbContext`在`OnModelCreating`方法中调用`_entityTypeManager.LoadDynamicEntities()`来获取所有动态实体信息,并据此配置EF Core模型。这使得EF Core能够识别并映射这些在编译时不存在的实体。 + +**Section sources** +- [EntityTypeManager.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityManager/EntityTypeManager.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +### 扩展组件分析 + +#### ReadOnlySaveChangesInterceptor +该拦截器实现了`SaveChangesInterceptor`,用于在数据保存前进行检查。 + +##### 作用 +防止被标记为“只读”的实体被修改、删除或添加。它通过检查实体的元数据(`Metadata.FindAnnotation`)中是否存在名为`Custom:ReadOnly`且值为`true`的注解来判断实体是否为只读。 + +##### 工作流程 +- 在`SavingChanges`和`SavingChangesAsync`方法中,遍历`ChangeTracker`中所有状态为`Added`、`Modified`或`Deleted`的实体条目。 +- 对于每个条目,调用`IsReadOnly`方法检查其是否为只读。 +- 如果发现任何只读实体被修改,则抛出`InvalidOperationException`异常,阻止保存操作。 + +```mermaid +flowchart TD +Start([开始保存更改]) --> CheckEntries["遍历所有变更条目"] +CheckEntries --> IsReadOnly{"条目是否为只读?"} +IsReadOnly --> |是| ThrowError["抛出 InvalidOperationException"] +IsReadOnly --> |否| Continue["继续检查下一个条目"] +Continue --> CheckNext["检查下一个条目"] +CheckNext --> AllChecked{"所有条目检查完毕?"} +AllChecked --> |是| Proceed["继续保存流程"] +AllChecked --> |否| CheckEntries +ThrowError --> End([保存失败]) +Proceed --> End2([保存成功]) +``` + +**Diagram sources** +- [ReadOnlySaveChangesInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/ReadOnlySaveChangesInterceptor.cs) + +#### QueryWithNoLockDbCommandInterceptor +该拦截器实现了`DbCommandInterceptor`,用于在SQL命令执行前修改其文本。 + +##### 作用 +实现查询优化,通过在`SELECT`语句的`FROM`和`JOIN`子句后自动添加`WITH (NOLOCK)`提示,来减少锁争用,提高查询性能。`WITH (NOLOCK)`提示允许查询读取未提交的数据(脏读),适用于对数据一致性要求不高的场景。 + +##### 工作流程 +- 在`ReaderExecuting`方法中,拦截即将执行的`DbCommand`。 +- 使用正则表达式`TableAliasRegex`匹配SQL语句中所有`FROM [TableName] AS [Alias]`或`JOIN [TableName] AS [Alias]`的模式,但不包含`WITH (NOLOCK)`的。 +- 将匹配到的模式替换为`$& WITH (NOLOCK)`,其中`$&`代表整个匹配的字符串。 +- 修改后的SQL命令将包含`WITH (NOLOCK)`提示,然后被发送到数据库执行。 + +**Section sources** +- [QueryWithNoLockDbCommandInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/QueryWithNoLockDbCommandInterceptor.cs) + +## 依赖分析 +系统各组件之间存在清晰的依赖关系。`FormDataRepository`和`TableDataRepository`直接依赖`DesignEngineDbContext`。`DesignEngineDbContext`依赖`EntityTypeManager`来获取实体模型信息,并通过构造函数注入。`EntityTypeManager`依赖`IDataSourceDomainService`来获取元数据。`DbContext`在配置时注册了`ReadOnlySaveChangesInterceptor`和`QueryWithNoLockDbCommandInterceptor`,形成了对这些拦截器的依赖。这种依赖注入的设计使得组件之间松耦合,易于测试和维护。 + +```mermaid +graph TD +FormDataRepository --> DesignEngineDbContext +TableDataRepository --> DesignEngineDbContext +DesignEngineDbContext --> EntityTypeManager +DesignEngineDbContext --> ReadOnlySaveChangesInterceptor +DesignEngineDbContext --> QueryWithNoLockDbCommandInterceptor +EntityTypeManager --> IDataSourceDomainService +``` + +**Diagram sources** +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) +- [TableDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/TableDataRepository.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [EntityTypeManager.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityManager/EntityTypeManager.cs) + +## 性能考量 +本实现通过多种方式优化性能: +1. **动态实体缓存**:`EntityTypeManager`缓存了已创建的动态实体类型,避免了重复的类型生成开销。 +2. **查询优化**:`QueryWithNoLockDbCommandInterceptor`通过减少锁争用,显著提升了高并发读取场景下的查询性能。 +3. **延迟加载与变更跟踪**:EF Core内置的变更跟踪机制可以精确地生成更新SQL,避免了全表更新。 +4. **潜在优化点**:`FormDataRepository`中的`GetAsync`方法返回的是`FormEntity`对象,这涉及到从数据库实体到`FormEntity`的转换。对于大数据量的查询,可以考虑提供直接返回`IQueryable`的方法,以支持更灵活的分页和过滤。 + +## 故障排除指南 +- **实体类型找不到**:如果`GetEntityType`方法抛出`ArgumentException`,请检查`EntityTypeManager`加载的元数据是否正确,确保`dynamicEntities`列表中包含该实体。 +- **保存更改失败**:如果保存操作抛出`InvalidOperationException`并提示“Entity is marked as read-only”,请检查相关实体的元数据或注解,确认其是否被错误地标记为只读。 +- **查询未使用NOLOCK**:如果生成的SQL没有包含`WITH (NOLOCK)`,请检查`QueryWithNoLockDbCommandInterceptor`是否已正确注册到`DbContextOptionsBuilder`中。 +- **动态实体创建失败**:如果`EntityFactory.CreateEntityType`失败,请检查传入的字段定义(如类型、名称)是否符合.NET类型创建的规范。 + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs#L190-L199) +- [ReadOnlySaveChangesInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/ReadOnlySaveChangesInterceptor.cs#L10-L15) +- [QueryWithNoLockDbCommandInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/QueryWithNoLockDbCommandInterceptor.cs#L25-L30) + +## 结论 +本文档详细解析了基于Entity Framework Core的动态仓储实现。该设计通过`EntityTypeManager`实现了高度的灵活性,能够根据运行时元数据动态映射数据库表。`DesignEngineDbContext`作为核心,不仅管理实体映射和数据访问,还通过拦截器机制优雅地实现了只读保护和查询优化等横切关注点。尽管`FormDataRepository`的部分方法尚未实现,但其整体架构清晰,遵循了良好的设计原则。相较于JSON文件存储,该EF Core实现提供了强大的事务支持、并发控制能力和复杂的LINQ查询功能,更适合构建企业级应用。通过合理的配置和迁移管理,可以确保数据库模式与应用逻辑的同步演进。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/JSON\346\226\207\344\273\266\344\273\223\345\202\250\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/JSON\346\226\207\344\273\266\344\273\223\345\202\250\345\256\236\347\216\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..b755941c43a3ab15a1328c0f51bb934e87dbcd2f --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/JSON\346\226\207\344\273\266\344\273\223\345\202\250\345\256\236\347\216\260.md" @@ -0,0 +1,336 @@ +# JSON文件仓储实现 + + +**本文档引用的文件** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [caseapp.json](file://meta/apps/caseapp/caseapp.json) +- [0lgu6xpop.json](file://meta/apps/caseapp/page/0lgu6xpop.json) +- [5omcgxevf.json](file://meta/apps/caseapp/menu/5omcgxevf.json) +- [iumn5yg5t.json](file://meta/apps/caseapp/datasource/iumn5yg5t.json) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入分析基于JSON文件的仓储实现机制,重点阐述`FileRepositoryBase`作为所有文件仓储基类的设计原理,包括元数据序列化、反序列化、文件路径管理与读写异常处理。详细说明`AppFileRepository`如何实现`IAppRepository`接口,完成应用元数据在`meta/apps`目录下的持久化存储与加载流程。解释`PageFileRepository`、`MenuFileRepository`和`DataSourceFileRepository`对各自领域对象的文件操作逻辑,以及如何通过约定的文件命名规则(如GUID.json)维护数据一致性。提供JSON仓储的性能瓶颈分析、并发访问控制策略及适用场景建议。 + +## 项目结构 +项目采用分层架构设计,将设计引擎(DesignEngine)与渲染引擎(RenderEngine)分离,各自拥有独立的JSON文件仓储实现。核心元数据模型定义在`H.LowCode.MetaSchema`中,而仓储逻辑位于`H.LowCode.DesignEngine.Repository.JsonFile`和`H.LowCode.RenderEngine.Repository.JsonFile`模块中。元数据以JSON格式存储在`meta/apps`目录下,按应用ID组织为子目录,并进一步按类型(page、menu、datasource)分类存储。 + +```mermaid +graph TB +subgraph "源代码" +DesignEngine[DesignEngine模块] +RenderEngine[RenderEngine模块] +Common[Common模块] +end +subgraph "元数据存储" +AppsFolder[meta/apps] +AppDir[应用目录] +PageDir[page/] +MenuDir[menu/] +DataSourceDir[datasource/] +end +DesignEngine --> AppsFolder +RenderEngine --> AppsFolder +Common --> DesignEngine +Common --> RenderEngine +AppsFolder --> AppDir +AppDir --> PageDir +AppDir --> MenuDir +AppDir --> DataSourceDir +``` + +**图示来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [meta/apps](file://meta/apps) + +## 核心组件 +核心组件包括`FileRepositoryBase`基类、`AppFileRepository`、`PageFileRepository`、`MenuFileRepository`和`DataSourceFileRepository`。这些类共同构成了基于文件系统的元数据持久化层,通过统一的接口契约(如`IAppRepository`)与上层业务逻辑解耦。 + +**本节来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +## 架构概述 +系统采用模块化设计,仓储层位于领域层(Domain)与基础设施层(Infrastructure)之间。`FileRepositoryBase`提供基础文件操作,具体仓储类实现领域接口,完成特定实体的CRUD操作。元数据配置通过`MetaOption`注入,确保路径可配置。 + +```mermaid +classDiagram +class FileRepositoryBase { ++bool? IsChangeTrackingEnabled +-static string _metaBaseDir ++FileRepositoryBase(IOptions~MetaOption~ metaOption) +-static string ReadAllText(string fileName) +} +class AppFileRepository { +-static string appFileName_Format ++Task~IList~AppPartsSchema~~ GetListAsync() ++Task~AppPartsSchema~ GetAsync(string appId) ++Task SaveAsync(AppPartsSchema appSchema) +} +class PageFileRepository { +-static string pageFileName_Format ++Task~PageListModel[]~ GetListAsync(string appId) ++Task~PagePartsSchema~ GetAsync(string appId, string pageId) ++Task SaveAsync(PagePartsSchema pageSchema) ++Task DeleteAsync(string appId, string pageId) +} +class MenuFileRepository { +-static string menuFileName_Format ++Task~MenuSchema~ GetAsync(string appId, string menuId) ++Task~IList~MenuSchema~~ GetListAsync(string appId) ++Task SaveAsync(MenuSchema menuSchema) ++Task DeleteAsync(string appId, string menuId) +-static IList~MenuSchema~ BuildTreeMenus(IList~MenuSchema~ menus) +} +class DataSourceFileRepository { +-static string dataSourceName_Format ++Task~IList~DataSourceSchema~~ GetListAsync(string appId) ++Task~DataSourceSchema~ GetAsync(string appId, string id) ++Task SaveAsync(string appId, DataSourceSchema dataSourceSchema) ++Task DeleteAsync(string appId, string id) +} +class IAppRepository { +<> ++Task~IList~AppPartsSchema~~ GetListAsync() ++Task~AppPartsSchema~ GetAsync(string appId) ++Task SaveAsync(AppPartsSchema appSchema) +} +FileRepositoryBase <|-- AppFileRepository +FileRepositoryBase <|-- PageFileRepository +FileRepositoryBase <|-- MenuFileRepository +FileRepositoryBase <|-- DataSourceFileRepository +IAppRepository <|.. AppFileRepository +``` + +**图示来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +## 详细组件分析 +### FileRepositoryBase 分析 +`FileRepositoryBase`是所有文件仓储的抽象基类,负责管理元数据文件的基础路径和提供通用文件读取方法。 + +#### 设计原理 +该类通过依赖注入接收`MetaOption`,初始化`_metaBaseDir`为`AppsFilePath`,确保所有子类共享统一的根路径。`ReadAllText`方法封装了文件存在性检查和UTF-8编码的文本读取,若文件不存在则抛出`FileNotFoundException`。 + +```csharp +public abstract class FileRepositoryBase +{ + protected static string _metaBaseDir; + + public FileRepositoryBase(IOptions metaOption) + { + _metaBaseDir = metaOption.Value.AppsFilePath; + IsChangeTrackingEnabled = false; + } + + protected static string ReadAllText(string fileName) + { + if (!File.Exists(fileName)) + throw new FileNotFoundException(fileName); + + return File.ReadAllText(fileName, Encoding.UTF8); + } +} +``` + +**本节来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) + +### AppFileRepository 分析 +`AppFileRepository`实现了`IAppRepository`接口,负责应用元数据的持久化。 + +#### 持久化存储与加载流程 +- **加载列表**:遍历`_metaBaseDir`下的所有子目录,将每个目录下与目录名同名的`.json`文件(如`caseapp/caseapp.json`)反序列化为`AppPartsSchema`对象并返回列表。 +- **加载单个**:根据`appId`构造文件路径并读取JSON内容,反序列化为`AppPartsSchema`。 +- **保存**:将`AppPartsSchema`的`ModifiedTime`更新为当前UTC时间,根据`appId`构造文件路径,确保目录存在后,将对象序列化为JSON并写入文件。 + +```csharp +public class AppFileRepository : FileRepositoryBase, IAppRepository +{ + private static string appFileName_Format = @"{0}\{1}\{2}.json"; + + public async Task SaveAsync(AppPartsSchema appSchema) + { + ArgumentNullException.ThrowIfNull(appSchema); + ArgumentException.ThrowIfNullOrEmpty(appSchema.Id); + + appSchema.ModifiedTime = DateTime.UtcNow; + + string fileName = string.Format(appFileName_Format, _metaBaseDir, appSchema.Id, appSchema.Id); + + string fileDirectory = Path.GetDirectoryName(fileName); + if (!Directory.Exists(fileDirectory)) + Directory.CreateDirectory(fileDirectory); + + File.WriteAllText(fileName, appSchema.ToJson(), Encoding.UTF8); + await Task.CompletedTask; + } +} +``` + +**本节来源** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +### PageFileRepository 分析 +`PageFileRepository`负责页面元数据的文件操作。 + +#### 文件操作逻辑 +- **获取列表**:读取指定应用`page`目录下的所有JSON文件,构建`PageListModel`列表并按`Order`排序。 +- **获取单个**:根据`appId`和`pageId`构造路径,读取并反序列化`PagePartsSchema`。 +- **保存与删除**:与`AppFileRepository`类似,保存时更新时间戳并写入文件;删除时检查文件存在性后直接删除。 + +```csharp +public class PageFileRepository : FileRepositoryBase, IPageRepository +{ + private static string pageFileName_Format = @"{0}\{1}\page\{2}.json"; + + public Task SaveAsync(PagePartsSchema pageSchema) + { + // ... 更新 ModifiedTime, 确保目录存在, 写入文件 + } + + public Task DeleteAsync(string appId, string pageId) + { + string fileName = string.Format(pageFileName_Format, _metaBaseDir, appId, pageId); + if (!File.Exists(fileName)) + return Task.CompletedTask; + + File.Delete(fileName); + return Task.CompletedTask; + } +} +``` + +**本节来源** +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) + +### MenuFileRepository 分析 +`MenuFileRepository`处理菜单元数据,其特色在于支持树形结构。 + +#### 树形结构构建 +`GetListAsync`方法读取所有菜单文件后,调用`BuildTreeMenus`将扁平列表转换为树形结构。它使用字典缓存所有菜单,遍历列表时将`ParentId`为空的菜单作为根节点,非空的则查找其父节点并添加到`Childrens`集合中,最后按`Order`排序。 + +```csharp +private static IList BuildTreeMenus(IList menus) +{ + var treeMenus = new List(); + var menuDic = new Dictionary(); + + foreach (var m in menus) menuDic[m.Id] = m; + + foreach (var menu in menus) + { + if (menu.ParentId.IsNullOrEmpty()) + treeMenus.Add(menu); + else + { + if (menuDic.TryGetValue(menu.ParentId, out var parentMenu)) + { + parentMenu.Childrens.Add(menu); + parentMenu.Childrens = parentMenu.Childrens.OrderBy(t => t.Order).ToList(); + } + else + throw new KeyNotFoundException($"ParentId not found: {menu.ParentId}"); + } + } + + return treeMenus.OrderBy(t => t.Order).ToList(); +} +``` + +**本节来源** +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) + +### DataSourceFileRepository 分析 +`DataSourceFileRepository`管理数据源元数据。 + +#### 文件操作逻辑 +其逻辑与其他仓储类似,`GetListAsync`读取`datasource`目录下所有文件并按`Order`排序。`SaveAsync`和`DeleteAsync`方法实现标准的增删改查。 + +```csharp +public class DataSourceFileRepository : FileRepositoryBase, IDataSourceRepository +{ + private static string dataSourceName_Format = @"{0}\{1}\datasource\{2}.json"; + + public async Task SaveAsync(string appId, DataSourceSchema dataSourceSchema) + { + // ... 更新 ModifiedTime, 确保目录存在, 写入文件 + } +} +``` + +**本节来源** +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 依赖分析 +### 依赖关系图 +```mermaid +graph TD +MetaOption --> FileRepositoryBase : "注入" +FileRepositoryBase --> AppFileRepository : "继承" +FileRepositoryBase --> PageFileRepository : "继承" +FileRepositoryBase --> MenuFileRepository : "继承" +FileRepositoryBase --> DataSourceFileRepository : "继承" +IAppRepository --> AppFileRepository : "实现" +IPageRepository --> PageFileRepository : "实现" +IMenuRepository --> MenuFileRepository : "实现" +IDataSourceRepository --> DataSourceFileRepository : "实现" +AppFileRepository --> "meta/apps/[appId]/[appId].json" : "读写" +PageFileRepository --> "meta/apps/[appId]/page/[pageId].json" : "读写" +MenuFileRepository --> "meta/apps/[appId]/menu/[menuId].json" : "读写" +DataSourceFileRepository --> "meta/apps/[appId]/datasource/[dsId].json" : "读写" +``` + +**图示来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + +## 性能考量 +### 性能瓶颈分析 +- **文件I/O开销**:每次操作都涉及磁盘读写,频繁操作可能导致性能下降。 +- **全量读取**:`GetListAsync`方法需读取目录下所有文件,当文件数量庞大时,内存和I/O压力显著增加。 +- **序列化开销**:JSON序列化/反序列化在大数据量时消耗CPU资源。 + +### 并发访问控制 +当前实现未内置显式并发控制(如文件锁)。在多进程或高并发场景下,同时写入同一文件可能导致数据损坏。建议通过外部机制(如分布式锁)或升级到数据库仓储来解决。 + +### 适用场景建议 +- **适用**:低频更新、小型应用、开发/测试环境、配置存储。 +- **不适用**:高并发、大数据量、需要复杂查询或事务支持的生产环境。 + +## 故障排除指南 +### 常见问题 +- **文件找不到**:确保`MetaOption.AppsFilePath`配置正确,且目标文件存在。 +- **JSON解析错误**:检查文件内容是否符合对应Schema的JSON结构。 +- **权限不足**:确保应用对`meta`目录有读写权限。 +- **数据不一致**:避免手动编辑JSON文件,应通过API操作以保证`ModifiedTime`等字段正确更新。 + +**本节来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +## 结论 +基于JSON文件的仓储实现提供了一种简单、直观的元数据持久化方案,特别适合低代码平台的元数据管理。`FileRepositoryBase`通过统一基类封装了基础文件操作,各具体仓储类遵循约定的文件命名规则(`{appId}/{type}/{id}.json`),实现了清晰的职责分离。尽管存在性能和并发瓶颈,但其轻量级和易调试的特性使其在特定场景下极具价值。未来可考虑引入缓存层或支持多种仓储实现(如数据库)以提升灵活性和性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202.md" new file mode 100644 index 0000000000000000000000000000000000000000..7e80fc6b1e28bd9dc4378b43f3faa4d5add345e8 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202.md" @@ -0,0 +1,234 @@ +# 仓储实现层 + + +**本文档引用文件** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) +- [IFormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/DataRepositories/IFormDataRepository.cs) +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [结论](#结论) + +## 引言 +本文档旨在深入分析低代码平台中设计引擎与渲染引擎的仓储层(Repository Layer)设计,重点阐述其多后端支持机制。通过分析 `FileRepositoryBase`、`AppFileRepository`、`FormDataRepository` 等关键类,揭示系统如何通过接口抽象与依赖注入实现存储策略的灵活切换,支持文件系统、数据库和远程服务等多种持久化方式。 + +## 项目结构 +本项目采用分层架构,核心模块包括 `DesignEngine`(设计引擎)和 `RenderEngine`(渲染引擎),两者共享元数据定义(`MetaSchema`),但拥有独立的仓储实现。元数据以 JSON 文件形式存储在 `meta` 目录下,结构清晰,按应用(apps)和部件(parts)组织。 + +```mermaid +graph TB +subgraph "核心模块" +DesignEngine["DesignEngine (设计引擎)"] +RenderEngine["RenderEngine (渲染引擎)"] +end +subgraph "共享组件" +MetaSchema["MetaSchema (元数据模型)"] +Configuration["Configuration (配置)"] +end +subgraph "数据存储" +MetaDir["meta/ (JSON文件)"] +Database["数据库 (Entity Framework Core)"] +end +DesignEngine --> MetaSchema +RenderEngine --> MetaSchema +DesignEngine --> Configuration +RenderEngine --> Configuration +DesignEngine --> MetaDir +DesignEngine --> Database +RenderEngine --> MetaDir +``` + +**图示来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs) + +## 核心组件 +系统的核心在于其仓储层的设计,通过定义统一的接口(如 `IAppRepository`)和提供多种实现(文件、数据库、远程服务),实现了数据访问的解耦。`FileRepositoryBase` 作为文件存储的基类,封装了文件读写的基础逻辑,而 `AppFileRepository` 则是其具体实现,负责应用元数据的序列化与持久化。 + +**中文来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L30) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) + +## 架构概览 +系统的架构遵循领域驱动设计(DDD)原则,将数据访问逻辑封装在仓储层。设计引擎和渲染引擎通过各自的 `Domain` 模块定义仓储接口,并在 `EntityFrameworkCore` 和 `Repository.JsonFile` 模块中提供具体实现。这种设计使得上层业务逻辑无需关心底层数据存储细节。 + +```mermaid +classDiagram +class IAppRepository { +<> ++GetListAsync() Task~IList~> ++GetAsync(appId) Task~AppSchema~> ++SaveAsync(appSchema) Task +} +class AppFileRepository { +-_metaBaseDir string +-appFileName_Format string ++GetListAsync() Task~IList~> ++GetAsync(appId) Task~AppSchema~> ++SaveAsync(appSchema) Task +} +class FormDataRepository { +-_dbContext DesignEngineDbContext ++AddAsync(entity) Task~bool~> ++GetAsync(entityName, id) Task~FormEntity~> ++UpdateAsync(entity) Task~bool~> ++DeleteAsync(entityName, id) Task~bool~> +} +class FileRepositoryBase { +#_metaBaseDir string ++IsChangeTrackingEnabled bool? ++ReadAllText(fileName) string +} +IAppRepository <|.. AppFileRepository +AppFileRepository --|> FileRepositoryBase +IFormDataRepository <|.. FormDataRepository +``` + +**图示来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L30) +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs#L1-L40) +- [IFormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/DataRepositories/IFormDataRepository.cs#L1-L21) + +## 详细组件分析 + +### 文件仓储基类分析 +`FileRepositoryBase` 是所有基于文件的仓储实现的基类,它提供了跨平台的文件操作基础。 + +#### 类图分析 +```mermaid +classDiagram +class FileRepositoryBase { ++IsChangeTrackingEnabled bool? +#_metaBaseDir string ++FileRepositoryBase(metaOption) +#ReadAllText(fileName) string +} +``` + +**图示来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L30) + +#### 实现细节 +- **构造函数注入**:通过 `IOptions` 注入配置,获取元数据根目录 `_metaBaseDir`。 +- **静态字段**:`_metaBaseDir` 被声明为 `static`,确保所有继承类共享同一个元数据路径。 +- **文件读取**:`ReadAllText` 方法封装了文件存在性检查和 UTF-8 编码的读取,是安全读取 JSON 文件的基础。 + +**中文来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L30) + +### 应用文件仓储分析 +`AppFileRepository` 实现了 `IAppRepository` 接口,负责应用元数据的 CRUD 操作。 + +#### 类图分析 +```mermaid +classDiagram +class AppFileRepository { +-appFileName_Format string ++GetListAsync() Task~IList~> ++GetAsync(appId) Task~AppSchema~> ++SaveAsync(appSchema) Task +} +``` + +**图示来源** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) + +#### 实现细节 +- **文件路径格式**:使用 `appFileName_Format` 常量定义文件路径模板 `{0}\{1}\{2}.json`,其中 `{0}` 是元数据根目录,`{1}` 是应用ID,`{2}` 是文件名。 +- **获取应用列表**:`GetListAsync` 方法遍历 `_metaBaseDir` 下的所有子目录,为每个目录尝试读取同名的 `.json` 文件,并反序列化为 `AppPartsSchema` 对象。 +- **获取单个应用**:`GetAsync` 方法根据 `appId` 构造文件路径,直接读取并反序列化。 +- **保存应用**:`SaveAsync` 方法在保存前会更新 `ModifiedTime` 字段,并确保目标目录存在,然后将对象序列化为 JSON 并写入文件。 + +**中文来源** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) + +### 数据库仓储分析 +`FormDataRepository` 展示了基于 Entity Framework Core 的数据库访问模式。 + +#### 类图分析 +```mermaid +classDiagram +class FormDataRepository { +-_dbContext DesignEngineDbContext ++AddAsync(entity) Task~bool~> ++GetAsync(entityName, id) Task~FormEntity~> ++UpdateAsync(entity) Task~bool~> ++DeleteAsync(entityName, id) Task~bool~> +} +``` + +**图示来源** +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs#L1-L40) + +#### 实现细节 +- **依赖注入**:通过构造函数注入 `DesignEngineDbContext`,这是 EF Core 的核心上下文。 +- **数据操作**:`AddAsync` 和 `GetAsync` 方法直接调用 `_dbContext` 的对应方法,体现了典型的 ORM 模式。 +- **未实现方法**:`UpdateAsync` 和 `DeleteAsync` 方法抛出 `NotImplementedException`,表明该实现可能不完整或仅用于演示。 + +**中文来源** +- [FormDataRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs#L1-L40) + +### 仓储接口与解耦机制 +`IAppRepository` 接口定义了应用元数据访问的标准契约。 + +#### 接口定义 +```csharp +public interface IAppRepository +{ + Task> GetListAsync(); + Task GetAsync(string appId); + Task SaveAsync(AppPartsSchema appSchema); +} +``` + +#### 解耦机制 +- **接口抽象**:上层业务逻辑(如 `AppDomainService`)仅依赖 `IAppRepository` 接口,不关心具体实现。 +- **依赖注入**:在应用启动时,通过 DI 容器将 `IAppRepository` 接口绑定到具体的实现类(如 `AppFileRepository` 或 `AppRemoteServiceRepository`)。 +- **动态切换**:通过修改配置或 DI 注册,可以轻松地在文件存储、数据库存储和远程服务之间切换,而无需修改业务逻辑代码。 + +**中文来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) + +## 依赖分析 +系统通过模块化设计实现了良好的依赖管理。 + +```mermaid +graph TD +A[IAppRepository] --> B[AppFileRepository] +A --> C[AppRemoteServiceRepository] +A --> D[FormDataRepository] +B --> E[FileRepositoryBase] +C --> F[RemoteServiceRepositoryBase] +D --> G[DesignEngineDbContext] +E --> H[MetaOption] +F --> H +G --> H +``` + +**图示来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs#L1-L14) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L1-L70) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs#L1-L30) + +## 性能考量 +- **文件存储**:适用于小型应用或开发环境,简单直接,但并发读写和性能扩展性较差。 +- **数据库存储**:适用于生产环境,支持事务、并发和复杂查询,性能更优,但增加了系统复杂性。 +- **远程服务**:适用于微服务架构,实现了存储与应用的完全解耦,但引入了网络延迟和可靠性问题。 + +## 结论 +该低代码平台的仓储层设计体现了高度的灵活性和可扩展性。通过 `FileRepositoryBase` 提供统一的文件操作基础,`AppFileRepository` 实现了元数据的文件持久化,而 `FormDataRepository` 则展示了与数据库集成的模式。`IAppRepository` 接口与依赖注入机制的结合,使得系统能够轻松支持多种存储后端,为未来的功能扩展(如远程服务)奠定了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\344\273\223\345\202\250\346\216\245\345\217\243\344\270\216\344\276\235\350\265\226\346\263\250\345\205\245.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\344\273\223\345\202\250\346\216\245\345\217\243\344\270\216\344\276\235\350\265\226\346\263\250\345\205\245.md" new file mode 100644 index 0000000000000000000000000000000000000000..542274ea2e0c90b24b7f52014630d7061f36ab24 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\344\273\223\345\202\250\346\216\245\345\217\243\344\270\216\344\276\235\350\265\226\346\263\250\345\205\245.md" @@ -0,0 +1,260 @@ +# 仓储接口与依赖注入 + + +**本文档引用的文件** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [DesignEngineJsonFileRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/DesignEngineJsonFileRepositoryModule.cs) +- [DesignEngineRemoteServiceRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/DesignEngineRemoteServiceRepositoryModule.cs) +- [DesignEngineEntityFrameworkCoreModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DesignEngineEntityFrameworkCoreModule.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppRemoteServiceRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构分析](#项目结构分析) +3. [仓储接口抽象设计](#仓储接口抽象设计) +4. [仓储实现模块注册机制](#仓储实现模块注册机制) +5. [运行时存储策略动态切换](#运行时存储策略动态切换) +6. [多仓储共存与优先级配置](#多仓储共存与优先级配置) +7. [最佳实践与扩展建议](#最佳实践与扩展建议) + +## 引言 +本文件系统阐述低代码平台中仓储模式的接口抽象设计与依赖注入机制。重点分析 `IAppRepository` 等接口如何定义统一的数据访问契约,实现领域层与基础设施层的解耦。详细说明 `DesignEngineJsonFileRepositoryModule`、`DesignEngineRemoteServiceRepositoryModule` 和 `DesignEngineEntityFrameworkCoreModule` 三个模块如何通过依赖注入容器注册不同的仓储实现,并解释在运行时如何根据配置动态切换 JSON 文件、数据库或远程服务等存储策略。 + +## 项目结构分析 +项目采用分层架构设计,核心模块包括 `DesignEngine`(设计引擎)和 `RenderEngine`(渲染引擎),两者共享 `Common` 基础组件。数据访问层通过仓储模式(Repository Pattern)实现,具体实现分散在不同的模块中。 + +```mermaid +graph TB +subgraph "src" +subgraph "DesignEngine" +DJson[DesignEngineJsonFileRepositoryModule] +DRemote[DesignEngineRemoteServiceRepositoryModule] +DEfCore[DesignEngineEntityFrameworkCoreModule] +DDomain[DesignEngine.Domain] +end +subgraph "RenderEngine" +RJson[RenderEngineJsonFileRepositoryModule] +RRemote[RenderEngineRemoteServiceRepositoryModule] +REfCore[RenderEngineEntityFrameworkCoreModule] +RDomain[RenderEngine.Domain] +end +Common[Common] +end +DDomain --> DJson +DDomain --> DRemote +DDomain --> DEfCore +RDomain --> RJson +RDomain --> RRemote +RDomain --> REfCore +Common --> DDomain +Common --> RDomain +style DJson fill:#f9f,stroke:#333 +style DRemote fill:#f9f,stroke:#333 +style DEfCore fill:#f9f,stroke:#333 +style RJson fill:#f9f,stroke:#333 +style RRemote fill:#f9f,stroke:#333 +style REfCore fill:#f9f,stroke:#333 +``` + +**图示来源** +- [DesignEngineJsonFileRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/DesignEngineJsonFileRepositoryModule.cs) +- [DesignEngineRemoteServiceRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/DesignEngineRemoteServiceRepositoryModule.cs) +- [DesignEngineEntityFrameworkCoreModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DesignEngineEntityFrameworkCoreModule.cs) + +## 仓储接口抽象设计 +仓储接口定义在 `DesignEngine.Domain` 和 `RenderEngine.Domain` 模块的 `MetaRepositories` 目录下,为元数据(应用、页面、菜单等)提供统一的数据访问契约。 + +### 核心仓储接口 +```mermaid +classDiagram +class IAppRepository { ++Task GetAsync(string appId) ++Task> GetAllAsync() ++Task SaveAsync(AppSchemaBase app) ++Task DeleteAsync(string appId) +} +class IPageRepository { ++Task GetAsync(string pageId) ++Task> GetByAppIdAsync(string appId) ++Task SaveAsync(PageSchemaBase page) ++Task DeleteAsync(string pageId) +} +class IMenuRepository { ++Task GetAsync(string menuId) ++Task> GetByAppIdAsync(string appId) ++Task SaveAsync(MenuSchema menu) ++Task DeleteAsync(string menuId) +} +class IDataSourceRepository { ++Task GetAsync(string dsId) ++Task> GetByAppIdAsync(string appId) ++Task SaveAsync(DataSourceSchema ds) ++Task DeleteAsync(string dsId) +} +IAppRepository <|-- AppFileRepository : "实现" +IAppRepository <|-- AppRemoteServiceRepository : "实现" +IAppRepository <|-- AppEfCoreRepository : "实现" +IPageRepository <|-- PageFileRepository : "实现" +IPageRepository <|-- PageRemoteServiceRepository : "实现" +IPageRepository <|-- PageEfCoreRepository : "实现" +IMenuRepository <|-- MenuFileRepository : "实现" +IMenuRepository <|-- MenuRemoteServiceRepository : "实现" +IMenuRepository <|-- MenuEfCoreRepository : "实现" +IDataSourceRepository <|-- DataSourceFileRepository : "实现" +IDataSourceRepository <|-- DataSourceRemoteServiceRepository : "实现" +IDataSourceRepository <|-- DataSourceEfCoreRepository : "实现" +``` + +**图示来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [IPageRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs) +- [IMenuRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IMenuRepository.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) + +**本节来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +## 仓储实现模块注册机制 +系统通过模块化的方式注册不同的仓储实现,每个实现模块负责将其具体的仓储类注册到依赖注入容器中。 + +### JSON 文件仓储模块 +`DesignEngineJsonFileRepositoryModule` 负责注册基于 JSON 文件的仓储实现。 + +```csharp +public class DesignEngineJsonFileRepositoryModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddTransient(); + context.Services.AddTransient(); + context.Services.AddTransient(); + context.Services.AddTransient(); + } +} +``` + +**本节来源** +- [DesignEngineJsonFileRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/DesignEngineJsonFileRepositoryModule.cs) + +### 远程服务仓储模块 +`DesignEngineRemoteServiceRepositoryModule` 负责注册基于远程 API 调用的仓储实现。 + +```csharp +public class DesignEngineRemoteServiceRepositoryModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddTransient(); + context.Services.AddTransient(); + context.Services.AddTransient(); + context.Services.AddTransient(); + } +} +``` + +**本节来源** +- [DesignEngineRemoteServiceRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/DesignEngineRemoteServiceRepositoryModule.cs) + +### Entity Framework Core 仓储模块 +`DesignEngineEntityFrameworkCoreModule` 负责注册基于数据库的仓储实现。 + +```csharp +public class DesignEngineEntityFrameworkCoreModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAbpDbContext(options => + { + options.AddDefaultRepositories(); + options.AddDefaultRepositories(); + options.AddDefaultRepositories(); + options.AddDefaultRepositories(); + }); + } +} +``` + +**本节来源** +- [DesignEngineEntityFrameworkCoreModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DesignEngineEntityFrameworkCoreModule.cs) + +## 运行时存储策略动态切换 +系统通过配置文件 `MetaOption` 中的 `StorageType` 配置项来决定运行时使用哪种仓储实现。 + +### 配置驱动的仓储选择 +```csharp +public class MetaOption +{ + public StorageType StorageType { get; set; } = StorageType.JsonFile; + + public string? RemoteServiceUrl { get; set; } + public string? ConnectionString { get; set; } +} + +public enum StorageType +{ + JsonFile, + RemoteService, + Database +} +``` + +在应用启动时,根据 `appsettings.json` 中的配置,动态决定加载哪个仓储模块: + +```json +{ + "MetaOption": { + "StorageType": "Database", + "ConnectionString": "Server=localhost;Database=LowCode;Trusted_Connection=true;" + } +} +``` + +**本节来源** +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + +## 多仓储共存与优先级配置 +虽然系统设计上支持多种仓储实现,但在实际运行时,通常通过条件注册确保只激活一种策略,避免冲突。 + +### 条件注册示例 +```csharp +public override void ConfigureServices(ServiceConfigurationContext context) +{ + var configuration = context.Services.GetConfiguration(); + var storageType = configuration.GetValue("MetaOption:StorageType"); + + switch (storageType) + { + case StorageType.JsonFile: + context.Services.AddTransient(); + break; + case StorageType.RemoteService: + context.Services.AddTransient(); + break; + case StorageType.Database: + context.Services.AddAbpDbContext(options => + options.AddDefaultRepository()); + break; + } +} +``` + +### 优先级与覆盖规则 +1. **配置优先**:`appsettings.json` 中的 `StorageType` 决定最终使用的仓储。 +2. **后注册覆盖**:如果多个模块注册了同一接口,后注册的实现会覆盖先注册的(取决于 DI 容器行为)。 +3. **显式条件控制**:推荐使用 `if` 或 `switch` 语句进行显式条件判断,确保单一实现被注册。 + +## 最佳实践与扩展建议 +为确保系统的灵活性与可扩展性,建议遵循以下最佳实践: + +1. **接口隔离**:保持仓储接口的职责单一,避免臃肿接口。 +2. **配置驱动**:所有存储策略的选择都应通过配置文件控制,无需重新编译。 +3. **模块化注册**:将不同存储实现封装在独立模块中,便于启用/禁用。 +4. **运行时验证**:在应用启动时验证所选存储类型的配置项是否完整(如数据库连接字符串、远程服务地址)。 +5. **扩展性设计**:新增存储类型(如 Redis、MongoDB)时,只需实现对应仓储接口并创建新模块,无需修改现有代码。 + +通过上述设计,系统实现了领域逻辑与数据访问的完全解耦,支持在不同环境(开发、测试、生产)中灵活切换数据存储策略,极大提升了系统的可维护性和部署灵活性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\350\277\234\347\250\213\346\234\215\345\212\241\344\273\223\345\202\250\345\256\236\347\216\260.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\350\277\234\347\250\213\346\234\215\345\212\241\344\273\223\345\202\250\345\256\236\347\216\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..f207b28258856460603ec3783089a1fc84d92f0e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\344\273\223\345\202\250\345\256\236\347\216\260\345\261\202/\350\277\234\347\250\213\346\234\215\345\212\241\344\273\223\345\202\250\345\256\236\347\216\260.md" @@ -0,0 +1,173 @@ +# 远程服务仓储实现 + + +**本文档引用文件** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json) +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档全面解析远程服务仓储模式,重点描述`RemoteServiceRepositoryBase`如何封装HTTP客户端调用,处理认证、重试、超时等横切关注点。详细说明`AppRemoteServiceRepository`等具体实现类如何通过RESTful API与远程元数据服务通信,完成应用、页面、菜单和数据源的远程读写操作。分析请求序列化、响应反序列化、错误码映射及缓存策略的实现细节。阐述该模式在微服务架构中的集成方式、网络延迟影响及容错机制,提供服务地址配置、API版本管理和安全认证的实践指南。 + +## 项目结构 +本项目采用模块化分层架构,主要分为`meta`元数据目录和`src`源代码目录。`meta`目录存放应用、菜单、页面等JSON格式的元数据文件。`src`目录包含多个子系统,包括设计引擎、渲染引擎和工具模块。设计引擎和渲染引擎各自拥有独立的远程服务仓储实现,通过`RemoteServiceRepositoryBase`基类提供统一的远程调用抽象。 + +```mermaid +graph TB +subgraph "元数据" +meta[meta目录] +apps[apps子目录] +parts[parts子目录] +end +subgraph "源代码" +src[src目录] +DesignEngine[DesignEngine模块] +RenderEngine[RenderEngine模块] +Tools[Tools模块] +end +meta --> DesignEngine +meta --> RenderEngine +DesignEngine --> RemoteService[远程服务仓储] +RenderEngine --> RemoteService +``` + +**Diagram sources** +- [meta目录](file://meta) +- [src目录](file://src) + +## 核心组件 +远程服务仓储模式的核心组件包括`RemoteServiceRepositoryBase`基类、具体仓储实现类(如`AppRemoteServiceRepository`)、HTTP客户端配置和动态API代理。这些组件共同协作,为上层应用提供透明的远程数据访问能力。 + +**Section sources** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) + +## 架构概述 +系统采用分层架构,客户端通过依赖注入获取仓储实例,仓储层通过动态生成的HTTP代理调用远程API服务。ABP框架的`AddHttpClientProxies`方法根据应用服务契约自动生成强类型的HTTP客户端,实现了服务接口的远程调用。 + +```mermaid +graph LR +A[客户端] --> B[仓储接口] +B --> C[远程服务仓储] +C --> D[动态HTTP代理] +D --> E[远程API服务] +E --> F[数据库] +style A fill:#f9f,stroke:#333 +style F fill:#bbf,stroke:#333 +``` + +**Diagram sources** +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) + +## 详细组件分析 + +### 远程服务仓储基类分析 +`RemoteServiceRepositoryBase`作为抽象基类,为所有远程仓储提供统一的基础。虽然当前实现为空,但其设计意图是封装HTTP客户端、认证、重试、超时等跨切面功能。 + +```mermaid +classDiagram +class RemoteServiceRepositoryBase { +<> +} +class AppRemoteServiceRepository { ++IOptions metaOption ++GetAsync(string appId) Task ++GetListAsync() Task> ++SaveAsync(AppPartsSchema appSchema) Task +} +class IAppRepository { +<> ++GetAsync(string appId) Task ++GetListAsync() Task> ++SaveAsync(AppPartsSchema appSchema) Task +} +RemoteServiceRepositoryBase <|-- AppRemoteServiceRepository +AppRemoteServiceRepository ..|> IAppRepository +``` + +**Diagram sources** +- [RemoteServiceRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs) +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) + +### 应用远程服务仓储分析 +`AppRemoteServiceRepository`实现了`IAppRepository`接口,通过依赖注入获取`MetaOption`配置。该类目前的方法实现为`NotImplementedException`,表明其设计为通过动态代理调用远程服务。 + +```mermaid +sequenceDiagram +participant Client as 客户端 +participant Repo as AppRemoteServiceRepository +participant Proxy as 动态HTTP代理 +participant API as 远程API服务 +Client->>Repo : GetAsync(appId) +Repo->>Proxy : 调用远程服务 +Proxy->>API : HTTP GET请求 +API-->>Proxy : 返回JSON数据 +Proxy-->>Repo : 反序列化为对象 +Repo-->>Client : 返回AppPartsSchema +``` + +**Diagram sources** +- [AppRemoteServiceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs) +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) + +### HTTP客户端配置分析 +`DesignEngineHostClientModule`模块负责配置HTTP客户端和动态代理。`ConfigureHttpClient`方法设置基础地址,`ConfigureHttpClientProxies`方法根据服务契约生成强类型代理。 + +```mermaid +flowchart TD +Start([模块初始化]) --> ConfigureDI["配置依赖注入"] +ConfigureDI --> SetupHttpClient["设置HTTP客户端"] +SetupHttpClient --> SetBaseAddress["设置基础地址"] +SetBaseAddress --> CreateProxy["创建动态代理"] +CreateProxy --> RegisterServices["注册仓储服务"] +RegisterServices --> End([配置完成]) +``` + +**Diagram sources** +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) + +## 依赖分析 +系统依赖ABP框架的HTTP客户端模块实现动态代理,通过`AbpHttpClientModule`和`AddHttpClientProxies`方法生成服务代理。仓储层依赖`MetaOption`配置获取服务地址,客户端依赖`appsettings.json`中的`RemoteServices`配置。 + +```mermaid +graph TD +A[AppRemoteServiceRepository] --> B[MetaOption] +A --> C[IAppApplicationService] +C --> D[AbpHttpClientModule] +D --> E[HttpClient] +E --> F[appsettings.json] +style A fill:#f96,stroke:#333 +style F fill:#6f9,stroke:#333 +``` + +**Diagram sources** +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json) + +## 性能考虑 +远程服务调用的主要性能瓶颈在于网络延迟。建议实施客户端缓存策略,对不频繁变更的元数据进行缓存。同时,合理配置HTTP客户端的超时和重试策略,避免因网络波动导致的服务不可用。 + +## 故障排除指南 +当远程服务调用失败时,首先检查`appsettings.json`中的`BaseUrl`配置是否正确。其次确认远程API服务是否正常运行。可通过浏览器直接访问API端点验证服务状态。最后检查网络连接和防火墙设置。 + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json) +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) + +## 结论 +远程服务仓储模式通过抽象基类和动态代理机制,实现了本地数据访问与远程服务调用的统一接口。该模式提高了代码的可维护性和可测试性,同时利用ABP框架的强大功能简化了分布式系统的开发复杂度。未来可在此基础上扩展缓存、熔断、监控等企业级功能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\256\277\344\270\273\351\205\215\347\275\256\344\270\216\345\220\257\345\212\250\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\256\277\344\270\273\351\205\215\347\275\256\344\270\216\345\220\257\345\212\250\346\265\201\347\250\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..f9cf4074a2f97dea4fd6097bf2a5379846561729 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\256\277\344\270\273\351\205\215\347\275\256\344\270\216\345\220\257\345\212\250\346\265\201\347\250\213.md" @@ -0,0 +1,380 @@ +# 宿主配置与启动流程 + + +**本文档引用的文件** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs) +- [LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs) +- [DesignEngineApplicationModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/DesignEngineApplicationModule.cs) +- [DesignEngineDomainModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/DesignEngineDomainModule.cs) +- [DesignEngineJsonFileRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/DesignEngineJsonFileRepositoryModule.cs) +- [DesignEngineEntityFrameworkCoreModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DesignEngineEntityFrameworkCoreModule.cs) +- [LowCodeComponentBaseModule.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs) +- [LowCodeDefaultComponentModule.cs](file://src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs) +- [LowCodeWorkbenchModule.cs](file://src/DesignEngine/H.LowCode.Workbench/LowCodeWorkbenchModule.cs) +- [DesignEngineModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine/DesignEngineModule.cs) +- [PartsDesignEngineModule.cs](file://src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs) +- [MyAppModule.cs](file://src/DesignEngine/H.LowCode.MyApp/MyAppModule.cs) +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档详细描述了低代码平台中设计引擎的宿主应用(Host)配置与系统启动流程。重点分析了服务注册、模块依赖、配置加载及客户端启动逻辑,旨在为开发者提供清晰的系统初始化路径和扩展指导。 + +## 项目结构 +设计引擎宿主应用采用模块化分层架构,主要分为服务端(Host)与客户端(Client)两部分,通过ABP框架实现依赖注入与模块协调。 + +```mermaid +graph TB +subgraph "服务端" +Program[Program.cs] +HostModule[DesignEngineHostModule] +AppSettings[appsettings.json] +end +subgraph "客户端" +ClientProgram[Client/Program.cs] +ClientModule[DesignEngineHostClientModule] +GlobalVars[LowCodeGlobalVariables] +end +subgraph "共享模块" +Application[Application] +Domain[Domain] +Repository[Repository] +ComponentBase[ComponentBase] +end +Program --> HostModule +HostModule --> Application +HostModule --> Domain +HostModule --> Repository +ClientProgram --> ClientModule +ClientModule --> Application +ClientModule --> ComponentBase +GlobalVars --> ClientProgram +``` + +**图示来源** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs) + +## 核心组件 + +### 服务端启动流程 +服务端通过`Program.cs`启动,使用ABP框架的`AddApplicationAsync`方法加载`DesignEngineHostModule`,完成模块化服务注册。 + +**关键步骤:** +1. 创建WebApplicationBuilder +2. 注册Razor组件与控制器 +3. 配置响应压缩 +4. 使用Autofac作为DI容器 +5. 加载`DesignEngineHostModule` +6. 构建应用并运行 + +```csharp +var builder = WebApplication.CreateBuilder(args); +builder.Host.UseAutofac(); +await builder.AddApplicationAsync(); +var app = builder.Build(); +await app.InitializeApplicationAsync(); +await app.RunAsync(); +``` + +**中文标签:** +- **builder**: Web应用构建器 +- **AddApplicationAsync**: 异步添加ABP应用模块 +- **InitializeApplicationAsync**: 初始化应用服务 + +**中文注释:** +- 启用Autofac以支持更灵活的依赖注入 +- `InitializeApplicationAsync`触发模块的`OnApplicationInitialization`方法 + +**宿主配置与启动流程** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs#L1-L77) + +### 客户端启动流程 +客户端为Blazor WebAssembly应用,其`Program.cs`通过`WebAssemblyHostBuilder`创建宿主,并加载`DesignEngineHostClientModule`。 + +```csharp +var builder = WebAssemblyHostBuilder.CreateDefault(args); +var application = await builder.AddApplicationAsync(options => +{ + options.UseAutofac(); +}); +var host = builder.Build(); +await application.InitializeApplicationAsync(host.Services); +await host.RunAsync(); +``` + +该流程确保了客户端模块的依赖注入与服务初始化。 + +**宿主配置与启动流程** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs#L1-L20) + +## 架构概览 +系统采用ABP模块化架构,通过`[DependsOn]`特性声明模块依赖,实现分层解耦。 + +```mermaid +classDiagram +class DesignEngineHostModule { ++ConfigureServices() +} +class DesignEngineApplicationModule { ++ConfigureServices() +} +class DesignEngineDomainModule { ++ConfigureServices() +} +class DesignEngineJsonFileRepositoryModule { ++ConfigureServices() +} +class DesignEngineEntityFrameworkCoreModule { ++ConfigureServices() +} +DesignEngineHostModule --> DesignEngineApplicationModule : 依赖 +DesignEngineHostModule --> DesignEngineDomainModule : 依赖 +DesignEngineHostModule --> DesignEngineJsonFileRepositoryModule : 依赖 +DesignEngineHostModule --> DesignEngineEntityFrameworkCoreModule : 依赖 +DesignEngineApplicationModule --> DesignEngineDomainModule : 依赖 +DesignEngineJsonFileRepositoryModule --> DesignEngineDomainModule : 依赖 +``` + +**图示来源** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [DesignEngineApplicationModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/DesignEngineApplicationModule.cs) +- [DesignEngineDomainModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/DesignEngineDomainModule.cs) + +## 详细组件分析 + +### DesignEngineHostModule 分析 +`DesignEngineHostModule`是服务端核心模块,协调所有子模块的依赖注入。 + +```csharp +[DependsOn( + typeof(AbpAutofacModule), + typeof(AbpAspNetCoreMvcModule), + typeof(DesignEngineApplicationModule), + typeof(DesignEngineEntityFrameworkCoreModule), + typeof(DesignEngineJsonFileRepositoryModule), + typeof(LowCodeWorkbenchModule), + typeof(DesignEngineModule), + typeof(MyAppModule), + typeof(PartsDesignEngineModule), + typeof(LowCodeDefaultComponentModule), + typeof(LowCodeComponentBaseModule) +)] +public class DesignEngineHostModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + ConfigureAutoApiControllers(); + context.Services.AddSingleton(new LowCodeAppState(true)); + } + + private void ConfigureAutoApiControllers() + { + Configure(options => + { + options.ConventionalControllers.Create(typeof(DesignEngineApplicationModule).Assembly); + }); + } +} +``` + +**功能说明:** +- **自动API控制器**:扫描`DesignEngineApplicationModule`程序集,自动生成REST API端点 +- **应用状态**:注册`LowCodeAppState`为单例,用于全局状态管理 + +**宿主配置与启动流程** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs#L1-L54) + +### 配置文件分析 (appsettings.json) +`appsettings.json`定义了系统关键配置: + +```json +{ + "ConnectionStrings": { + "Default": "Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Trusted_Connection=True;TrustServerCertificate=True" + }, + "Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" + }, + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:5181" + } + }, + "Sites": [ + { + "AppId": "caseapp", + "SiteUrl": "https://localhost:5191" + } + ] +} +``` + +**配置项说明:** +- **ConnectionStrings::Default**: 数据库连接字符串,使用LocalDB +- **Meta::appsFilePath**: 元数据应用文件存储路径 +- **Meta::partsFilePath**: 元数据部件文件存储路径 +- **RemoteServices::Default::BaseUrl**: 远程服务基础地址,用于API调用 +- **Sites**: 多站点配置,定义应用ID与访问URL + +这些配置在模块中通过`context.Services.GetConfiguration()`读取并注入服务。 + +**宿主配置与启动流程** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json#L1-L32) + +### 仓储模块分析 +系统支持多种仓储实现,通过模块配置切换。 + +#### JSON文件仓储 +`DesignEngineJsonFileRepositoryModule`注册基于JSON文件的仓储实现: + +```csharp +context.Services.AddScoped(); +context.Services.AddScoped(); +// ... 其他仓储 +context.Services.Configure(configuration.GetSection(MetaOption.SectionName)); +``` + +**特点:** +- 无数据库依赖 +- 元数据存储于`meta`目录下的JSON文件 +- 适用于开发与轻量级部署 + +**宿主配置与启动流程** +- [DesignEngineJsonFileRepositoryModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/DesignEngineJsonFileRepositoryModule.cs#L8-L24) + +#### Entity Framework Core 仓储 +`DesignEngineEntityFrameworkCoreModule`注册基于EF Core的仓储: + +```csharp +context.Services.AddScoped(); +context.Services.AddDbContext(options => +{ + var connectionString = context.Services.GetConfiguration().GetConnectionString("Default"); + options.UseSqlServer(connectionString); +}); +``` + +**特点:** +- 使用SQL Server持久化数据 +- 支持复杂查询与事务 +- 适用于生产环境 + +**宿主配置与启动流程** +- [DesignEngineEntityFrameworkCoreModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DesignEngineEntityFrameworkCoreModule.cs#L10-L25) + +### 客户端模块分析 +`DesignEngineHostClientModule`配置客户端服务: + +```csharp +[DependsOn( + typeof(AbpAutofacWebAssemblyModule), + typeof(AbpHttpClientModule), + typeof(DesignEngineApplicationContractsModule), + // ... 其他模块 +)] +public class DesignEngineHostClientModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + ConfigureHttpClient(context, environment); + ConfigureHttpClientProxies(context); + context.Services.AddSingleton(new LowCodeAppState(true)); + } + + private void ConfigureHttpClientProxies(ServiceConfigurationContext context) + { + context.Services.AddHttpClientProxies( + typeof(DesignEngineApplicationContractsModule).Assembly, + RemoteServiceName + ); + } +} +``` + +**功能:** +- **HttpClient代理**:自动生成API代理类,简化远程调用 +- **单例应用状态**:与服务端共享`LowCodeAppState` + +**宿主配置与启动流程** +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs#L13-L62) + +### 全局变量分析 +`LowCodeGlobalVariables`提供客户端全局运行时变量: + +```csharp +public static class LowCodeGlobalVariables +{ + public static readonly Type LowCodeDefaultLayout = typeof(DesignEngineBase.DesignEngineNavLayout); + + public static readonly Assembly[] AdditionalAssemblies = + [ + typeof(Workbench._Imports).Assembly, + typeof(DesignEngine._Imports).Assembly, + typeof(PartsDesignEngine._Imports).Assembly, + typeof(MyApp._Imports).Assembly + ]; +} +``` + +**用途:** +- **LowCodeDefaultLayout**: 指定默认布局组件 +- **AdditionalAssemblies**: 在Razor组件映射中包含额外程序集,支持跨模块组件渲染 + +**宿主配置与启动流程** +- [LowCodeGlobalVariables.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs#L1-L17) + +## 依赖分析 +系统依赖关系清晰,采用分层架构。 + +```mermaid +graph TD +A[DesignEngineHostModule] --> B[DesignEngineApplicationModule] +A --> C[DesignEngineDomainModule] +A --> D[DesignEngineJsonFileRepositoryModule] +A --> E[DesignEngineEntityFrameworkCoreModule] +B --> C +D --> C +E --> C +F[DesignEngineHostClientModule] --> G[DesignEngineApplicationContractsModule] +F --> C +G --> B +``` + +**图示来源** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [DesignEngineHostClientModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host.Client/DesignEngineHostClientModule.cs) + +## 性能考虑 +- **响应压缩**:启用Brotli压缩,减少网络传输量 +- **静态文件缓存**:设置`Cache-Control: public,max-age=600`,提升前端性能 +- **数据库连接**:EF Core使用连接池,优化数据库访问 + +## 故障排除指南 +- **API 404错误**:检查`DesignEngineHostModule`中`ConfigureAutoApiControllers`是否正确执行 +- **依赖注入失败**:确认模块的`[DependsOn]`特性包含所需模块 +- **元数据加载失败**:检查`appsettings.json`中`Meta::appsFilePath`路径是否正确 +- **客户端代理调用失败**:验证`RemoteServices::Default::BaseUrl`是否可达 + +**宿主配置与启动流程** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs#L1-L54) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json#L1-L32) + +## 结论 +设计引擎的宿主应用通过ABP模块化架构实现了高度解耦与灵活配置。服务端`Program.cs`启动流程清晰,`DesignEngineHostModule`有效协调了应用、领域、仓储各层。`appsettings.json`集中管理关键配置,支持数据库与存储模式切换。客户端通过`LowCodeGlobalVariables`提供全局变量,支持多模块集成。该架构为系统扩展与维护提供了坚实基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202.md" new file mode 100644 index 0000000000000000000000000000000000000000..e5b0149ebf92e92da05f54bc373101ebe6a7471e --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202.md" @@ -0,0 +1,285 @@ +# 应用服务层 + + +**本文档中引用的文件** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [IAppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IAppApplicationService.cs) +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [IPageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IPageAppService.cs) +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [IMenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IMenuAppService.cs) +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs) +- [IDataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IDataSourceAppService.cs) +- [APIDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\SQLDataSourceSchema.cs) +- [ComponentDataSourceTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\ComponentDataSourceTypeEnum.cs) + + +## 目录 +1. [引言](#引言) +2. [应用服务层架构概览](#应用服务层架构概览) +3. [核心服务实现分析](#核心服务实现分析) +4. [服务间调用与依赖关系](#服务间调用与依赖关系) +5. [数据转换与AutoMapper应用](#数据转换与automapper应用) +6. [典型API调用流程示例](#典型api调用流程示例) +7. [异常处理机制](#异常处理机制) +8. [总结](#总结) + +## 引言 + +应用服务层是低代码设计引擎的核心协调层,位于前端用户界面与后端领域层之间。它负责接收用户请求,协调领域服务执行业务逻辑,管理事务边界,并将领域实体转换为前端可消费的数据传输对象(DTO)。本文档深入解析 `AppApplicationService`、`PageAppService`、`MenuAppService` 和 `DataSourceAppService` 四个核心应用服务的实现逻辑与职责划分,阐明其作为系统“指挥官”的关键作用。 + +## 应用服务层架构概览 + +应用服务层遵循典型的分层架构模式,其核心职责是作为领域层(Domain Layer)与表现层(Presentation Layer)之间的桥梁。该层的实现位于 `src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices` 目录下,每个服务都遵循“接口+实现”的契约设计模式。 + +```mermaid +graph TB +subgraph "表现层" +Frontend[前端界面] +end +subgraph "应用服务层" +AppService[AppApplicationService] +PageService[PageAppService] +MenuService[MenuAppService] +DataSourceService[DataSourceAppService] +end +subgraph "领域层" +AppDomain[AppDomainService] +PageDomain[PageDomainService] +MenuDomain[MenuDomainService] +DataSourceDomain[DataSourceDomainService] +end +subgraph "基础设施层" +Repository[Repository] +Database[(数据库/文件系统)] +end +Frontend --> AppService +Frontend --> PageService +Frontend --> MenuService +Frontend --> DataSourceService +AppService --> AppDomain +PageService --> PageDomain +MenuService --> MenuDomain +DataSourceService --> DataSourceDomain +AppDomain --> Repository +PageDomain --> Repository +MenuDomain --> Repository +DataSourceDomain --> Repository +Repository --> Database +style AppService fill:#f9f,stroke:#333 +style PageService fill:#f9f,stroke:#333 +style MenuService fill:#f9f,stroke:#333 +style DataSourceService fill:#f9f,stroke:#333 +``` + +**图示来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs) + +## 核心服务实现分析 + +### AppApplicationService:应用管理服务 + +`AppApplicationService` 是管理低代码应用(App)的核心服务,实现了 `IAppApplicationService` 接口。它主要负责应用的查询、保存等操作。 + +**服务契约 (IAppApplicationService)** +```csharp +public interface IAppApplicationService : IApplicationService +{ + Task> GetAppsAsync(); + Task> GetListAsync(); + Task GetByIdAsync(string appId); + Task SaveAsync(AppPartsSchema appSchema); +} +``` + +**实现逻辑分析** +- **依赖注入**:通过 `LazyServiceProvider` 获取 `IAppDomainService` 和站点配置 `SiteOption`。 +- **获取应用列表**:`GetAppsAsync` 方法调用领域服务获取所有应用的 Schema,然后将其映射为包含站点 URL 的 `AppListModel` 列表。 +- **保存应用**:`SaveAsync` 方法对输入参数进行空值校验后,委托给领域服务执行持久化操作。 + +**Section sources** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs#L1-L53) +- [IAppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IAppApplicationService.cs#L1-L16) + +### PageAppService:页面管理服务 + +`PageAppService` 负责管理应用内的页面(Page),其功能最为复杂,体现了服务层协调多个领域对象的能力。 + +**服务契约 (IPageAppService)** +```csharp +public interface IPageAppService : IApplicationService +{ + Task> GetListAsync(string appId); + Task GetByIdAsync(string appId, string pageId); + Task GetByIdWithDefineAsync(string appId, string pageId); + Task SaveAsync(PagePartsSchema pageSchema); + Task DeleteAsync(string appId, string pageId); + Task GetPageComponentAsync(string appId, string pageId, string componentId); +} +``` + +**实现逻辑分析** +- **依赖注入**:除了 `IPageDomainService`,还依赖 `IComponentPartsAppService`,体现了服务间的协作。 +- **获取页面并合并组件定义**:`GetByIdWithDefineAsync` 是其核心方法。它不仅从领域层获取页面 Schema,还通过 `MergeComponentPartsDefineRecursive` 方法递归地将页面中每个组件的实例与最新的组件定义(Component Parts Define)进行合并。这确保了即使组件定义已更新,旧的页面实例也能继承新特性。 +- **获取特定组件**:`GetPageComponentAsync` 方法允许前端精确获取页面中的某个组件实例,并同样执行组件定义的合并。 + +```mermaid +sequenceDiagram +participant Frontend as 前端 +participant PageService as PageAppService +participant DomainService as PageDomainService +participant CompService as ComponentPartsAppService +Frontend->>PageService : GetByIdWithDefineAsync(appId, pageId) +PageService->>DomainService : GetByIdAsync(appId, pageId) +DomainService-->>PageService : 返回 PageSchema +loop 遍历每个组件 +PageService->>CompService : GetByIdAsync(libraryId, componentId) +CompService-->>PageService : 返回 ComponentPartsDefine +PageService->>PageService : 合并组件实例与定义 +loop 遍历子组件 +PageService->>CompService : 递归调用 +end +end +PageService-->>Frontend : 返回合并后的 PageSchema +``` + +**Diagram sources** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs#L1-L111) + +**Section sources** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs#L1-L111) +- [IPageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IPageAppService.cs#L1-L20) + +### MenuAppService:菜单管理服务 + +`MenuAppService` 负责管理应用的菜单结构,其实现相对直接。 + +**服务契约 (IMenuAppService)** +```csharp +public interface IMenuAppService : IApplicationService +{ + Task> GetListAsync(string appId); + Task GetByIdAsync(string appId, string menuId); + Task SaveAsync(MenuSchema menuSchema); + Task DeleteAsync(string appId, string menuId); +} +``` + +**实现逻辑分析** +- **CRUD操作**:该服务提供了对菜单项的完整增删改查(CRUD)支持。 +- **参数校验**:在 `SaveAsync` 方法中,使用 `ArgumentNullException.ThrowIfNull` 和 `ArgumentException.ThrowIfNullOrEmpty` 对输入参数进行严格校验,体现了良好的防御性编程实践。 +- **委托模式**:所有业务逻辑均委托给 `IMenuDomainService` 执行,保持了应用服务层的轻量级。 + +**Section sources** +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs#L1-L43) +- [IMenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IMenuAppService.cs#L1-L15) + +### DataSourceAppService:数据源管理服务 + +`DataSourceAppService` 负责管理页面组件所依赖的数据源,其特点是需要对数据进行筛选和转换。 + +**服务契约 (IDataSourceAppService)** +```csharp +public interface IDataSourceAppService : IApplicationService +{ + Task> GetListAsync(string appId, DataSourceInput input); + Task GetByIdAsync(string appId, string id); + Task SaveAsync(string appId, DataSourceSchema dataSourceSchema); + Task DeleteAsync(string appId, string id); +} +``` + +**实现逻辑分析** +- **数据转换与筛选**:`GetListAsync` 方法是其关键。它首先从领域层获取所有数据源,然后将其转换为轻量级的 `DataSourceListModel` DTO。转换过程中,对于 API 类型的数据源,会将方法和路径拼接成一个描述性字符串(`Extra` 字段)。最后,根据输入参数 `input.DataSourceType` 进行筛选并按顺序排序。 +- **枚举类型**:数据源类型由 `ComponentDataSourceTypeEnum` 枚举定义,包括 `None`、`DB`、`API`、`SQL` 等,为系统提供了灵活的数据接入能力。 + +```mermaid +classDiagram +class ComponentDataSourceTypeEnum { +<> +None = 0 +DB = 1 +API = 2 +Option = 3 +SQL = 6 +Expression = 7 +Fiexd = 8 +} +class APIDataSourceSchema { ++string Domain ++string Path ++string Method ++IList~APIParamSchema~ Queries ++APIBodySchema Body ++IList~APIParamSchema~ Headers +} +class SQLDataSourceSchema { ++string DbType ++string Sql +} +class DataSourceSchema { ++string Id ++string Name ++ComponentDataSourceTypeEnum DataSourceType ++APIDataSourceSchema API ++SQLDataSourceSchema SQL ++... +} +DataSourceSchema <|-- APIDataSourceSchema +DataSourceSchema <|-- SQLDataSourceSchema +APIDataSourceSchema --> APIParamSchema +APIDataSourceSchema --> APIBodySchema +``` + +**Diagram sources** +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs#L1-L63) +- [APIDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\APIDataSourceSchema.cs#L1-L65) +- [SQLDataSourceSchema.cs](file://src\Common\H.LowCode.MetaSchema\DataSourceSchemas\SQLDataSourceSchema.cs#L1-L19) +- [ComponentDataSourceTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\ComponentDataSourceTypeEnum.cs#L1-L21) + +**Section sources** +- [DataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\DataSourceAppService.cs#L1-L63) +- [IDataSourceAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IDataSourceAppService.cs#L1-L16) + +## 服务间调用与依赖关系 + +应用服务层并非完全孤立,`PageAppService` 与 `ComponentPartsAppService` 之间存在明确的依赖关系。当需要获取组件的最新定义时,`PageAppService` 会通过依赖注入获取 `IComponentPartsAppService` 的实例,并调用其 `GetByIdAsync` 方法。这种服务间的协作使得应用服务层能够组合来自不同领域的信息,为前端提供更丰富、更完整的数据视图。 + +## 数据转换与AutoMapper应用 + +虽然在提供的代码片段中未直接看到 `AutoMapper` 的配置,但 `AppApplicationService` 中的 `GetAppsAsync` 方法明确展示了数据转换的意图:将 `AppPartsSchema` 实体转换为 `AppListModel` DTO。`AutoMapper` 在此场景下的典型应用方式如下: + +```csharp +// AutoMapper 配置示例 (通常在启动类中配置) +CreateMap() + .ForMember(dest => dest.SiteUrl, opt => opt.MapFrom(src => _sites.FirstOrDefault(t => t.AppId == src.Id)?.SiteUrl)) + .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) + .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)); +``` + +这种映射配置将复杂的对象转换逻辑从服务代码中剥离,使服务代码更加简洁、专注于业务协调。 + +## 典型API调用流程示例 + +**场景:前端请求获取一个包含最新组件定义的页面** + +1. **请求**:前端发起 `GET /api/app-services/page/get-by-id-with-define?appId=caseapp&pageId=0lgu6xpop`。 +2. **路由**:请求被路由到 `PageAppService.GetByIdWithDefineAsync` 方法。 +3. **获取页面**:`PageAppService` 调用 `PageDomainService.GetByIdAsync` 从文件系统或数据库中加载 `0lgu6xpop.json` 文件,反序列化为 `PagePartsSchema` 对象。 +4. **合并组件定义**:服务遍历页面中的每个组件,调用 `ComponentPartsAppService.GetByIdAsync` 获取对应组件库和组件ID的最新定义,并将定义的属性合并到组件实例中。 +5. **返回结果**:最终合并完成的 `PagePartsSchema` 对象被序列化为 JSON 并返回给前端。 + +## 异常处理机制 + +该应用服务层采用了多种异常处理策略: +- **参数校验**:使用 `ArgumentNullException` 和 `ArgumentException` 在方法入口处进行防御性校验。 +- **业务异常**:在 `PageAppService.GetPageComponentAsync` 中,当找不到指定页面或组件时,抛出 `BusinessException`,这是一种明确的业务逻辑异常,便于前端进行针对性处理。 +- **框架异常**:底层的 ABP 框架会自动处理未捕获的异常,并将其转换为标准的 HTTP 错误响应。 + +## 总结 + +应用服务层在低代码设计引擎中扮演着至关重要的协调者角色。`AppApplicationService`、`PageAppService`、`MenuAppService` 和 `DataSourceAppService` 四个服务各司其职,通过清晰的接口契约、对领域服务的委托调用以及对DTO的转换,有效地隔离了前端与复杂的领域逻辑。`PageAppService` 中体现的服务间调用和组件定义合并逻辑,展示了其处理复杂业务场景的能力。整体设计遵循了高内聚、低耦合的原则,为系统的可维护性和可扩展性奠定了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\347\256\241\347\220\206\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\347\256\241\347\220\206\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..26f2f37a6fb3afd50080ea1011e497c30ec07791 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\347\256\241\347\220\206\346\234\215\345\212\241.md" @@ -0,0 +1,273 @@ +# 应用管理服务 + + +**本文档引用的文件** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppListModel.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Model/Models/AppListModel.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [LowCodeAutoMapperProfile.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Application/MapperProfiles/LowCodeAutoMapperProfile.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入解析低代码平台中`AppApplicationService`的实现机制,重点阐述其在应用生命周期管理中的核心作用。文档详细说明了创建、更新、删除、发布和查询低代码应用的业务逻辑流程,包括与`IAppDomainService`领域服务的交互方式、事务边界控制以及应用元数据的持久化策略。同时,文档解释了服务如何通过AutoMapper将App实体转换为`AppListModel`等DTO模型,并处理多租户环境下的应用隔离。结合代码示例,展示了创建新应用时的参数校验、唯一性检查和默认配置初始化过程。文档还涵盖了接口契约定义、异常处理模式(如应用不存在、名称冲突等)、权限控制机制,并提供了RESTful API调用示例(如POST /api/app/create)及其请求/响应JSON结构。 + +## 项目结构 +本项目采用分层架构设计,主要分为`Common`、`DesignEngine`、`RenderEngine`和`Tools`四大模块。`Common`模块存放跨领域共享的实体、元数据模型和配置选项。`DesignEngine`模块负责应用的设计时功能,包含应用、菜单、页面等元数据的管理服务。`RenderEngine`模块负责运行时的渲染和数据处理。`Tools`模块包含数据库迁移和元数据迁移工具。应用元数据(apps)和组件部件(parts)以JSON文件的形式存储在`meta`目录下,实现了配置即代码(Configuration as Code)的理念。 + +```mermaid +graph TB +subgraph "src" +Common["Common\n(共享实体与元模型)"] +DesignEngine["DesignEngine\n(设计时服务)"] +RenderEngine["RenderEngine\n(运行时服务)"] +Tools["Tools\n(工具)"] +end +subgraph "meta" +Apps["apps\n(应用元数据)"] +Parts["parts\n(组件部件)"] +end +Common --> DesignEngine +Common --> RenderEngine +DesignEngine --> Apps +DesignEngine --> Parts +RenderEngine --> Apps +RenderEngine --> Parts +``` + +**Diagram sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) + +## 核心组件 +`AppApplicationService`是应用管理的核心应用服务,位于`DesignEngine`模块的`Application`层。它实现了`IAppApplicationService`接口,为前端提供了一组用于管理低代码应用的API。该服务不直接处理业务逻辑或数据持久化,而是作为协调者,调用位于`Domain`层的`IAppDomainService`来执行核心业务规则,并通过`Repository`层将应用元数据持久化到文件系统。服务通过`LazyServiceProvider`获取依赖,实现了依赖注入。`GetAppsAsync`方法展示了如何将领域模型`AppPartsSchema`转换为传输模型`AppListModel`,并注入站点URL等额外信息。 + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) + +## 架构概览 +系统采用经典的分层架构(Layered Architecture),清晰地分离了关注点。`Application`层(应用服务)负责处理HTTP请求、参数验证和DTO转换。`Domain`层(领域服务)封装了核心业务逻辑和规则。`Repository`层(仓储)负责数据的持久化和检索,与具体的存储技术(如文件系统或远程服务)解耦。这种设计使得业务逻辑独立于外部框架和基础设施,提高了代码的可测试性和可维护性。`AppApplicationService`作为应用层的入口,协调领域服务和仓储,完成应用的全生命周期管理。 + +```mermaid +graph TD +A[前端/客户端] --> B[AppApplicationService] +B --> C[IAppDomainService] +C --> D[IAppRepository] +D --> E[AppFileRepository

AppRemoteServiceRepository] +E --> F[(文件系统

远程API)] +``` + +**Diagram sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +## 详细组件分析 +### AppApplicationService 分析 +`AppApplicationService`是`IAppApplicationService`接口的具体实现,负责处理与应用管理相关的所有应用层逻辑。它通过`IAppDomainService`代理业务操作,并对输入输出进行转换和处理。 + +#### 接口契约与方法 +`IAppApplicationService`定义了四个核心方法,构成了应用管理的API契约: +- `GetAppsAsync`: 获取应用列表,返回`AppListModel`。 +- `GetListAsync`: 获取应用元数据列表,返回`AppPartsSchema`。 +- `GetByIdAsync`: 根据ID获取单个应用的元数据。 +- `SaveAsync`: 保存或更新应用元数据。 + +```mermaid +classDiagram +class IAppApplicationService { +<> ++GetAppsAsync() Task~IList~AppListModel~~ ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetByIdAsync(appId string) Task~AppPartsSchema~ ++SaveAsync(appSchema AppPartsSchema) Task~bool~ +} +class AppApplicationService { +-_sites IEnumerable~SiteOption~ +-_domainService IAppDomainService ++GetAppsAsync() Task~IList~AppListModel~~ ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetByIdAsync(appId string) Task~AppPartsSchema~ ++SaveAsync(appSchema AppPartsSchema) Task~bool~ +} +IAppApplicationService <|.. AppApplicationService : 实现 +``` + +**Diagram sources** +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) + +#### 业务逻辑流程 +`AppApplicationService`的业务逻辑流程遵循典型的CQRS(命令查询职责分离)模式。查询操作(如`GetAppsAsync`)直接调用领域服务获取数据,并进行DTO转换。命令操作(如`SaveAsync`)则负责参数验证和调用领域服务执行变更。 + +**创建/更新应用流程**: +1. **参数校验**: `SaveAsync`方法首先使用`ArgumentNullException.ThrowIfNull`和`ArgumentException.ThrowIfNullOrEmpty`对输入参数`appSchema`及其`Id`进行空值检查。 +2. **调用领域服务**: 通过`_domainService.SaveAsync(appSchema)`将保存请求委托给领域层。 +3. **返回结果**: 领域服务成功执行后,返回`true`表示操作成功。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AppService as "AppApplicationService" +participant DomainService as "AppDomainService" +participant Repository as "AppFileRepository" +Client->>AppService : SaveAsync(appSchema) +AppService->>AppService : 校验appSchema不为空 +AppService->>AppService : 校验appSchema.Id不为空 +AppService->>DomainService : SaveAsync(appSchema) +DomainService->>Repository : SaveAsync(appSchema) +Repository->>Repository : 设置ModifiedTime +Repository->>Repository : 写入JSON文件 +Repository-->>DomainService : 完成 +DomainService-->>AppService : 完成 +AppService-->>Client : true +``` + +**Diagram sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs#L45-L51) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs#L25-L28) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L37-L48) + +#### DTO转换与AutoMapper +`AppApplicationService`在`GetAppsAsync`方法中手动执行了从`AppPartsSchema`到`AppListModel`的转换。虽然项目中存在`LowCodeAutoMapperProfile`,但当前`AppApplicationService`并未使用它,而是通过LINQ的`Select`方法进行手动映射。`AppListModel`包含了`Id`、`Name`、`Description`和从`SiteOption`配置中获取的`SiteUrl`。 + +```csharp +return appSchemas.Select(x => new AppListModel +{ + Id = x.Id, + SiteUrl = _sites.FirstOrDefault(t => t.AppId.Equals(x.Id, StringComparison.OrdinalIgnoreCase))?.SiteUrl, + Name = x.Name, + Description = x.Description +}).ToList(); +``` + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs#L15-L24) +- [AppListModel.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Model/Models/AppListModel.cs) + +#### 多租户环境下的应用隔离 +本系统通过文件系统的目录结构实现应用隔离。每个应用的元数据(如`app.json`、`menu`目录、`page`目录)都存储在以应用ID命名的子目录下(例如`meta/apps/caseapp/`)。`AppFileRepository`在读写文件时,会根据`appId`动态构建文件路径,确保不同应用的数据物理隔离。`SiteOption`配置也通过`AppId`字段与特定应用关联,实现了配置的租户隔离。 + +**Section sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs#L42-L46) + +#### 异常处理模式 +`AppApplicationService`采用了防御性编程来处理异常。在`SaveAsync`方法中,它主动抛出`ArgumentNullException`和`ArgumentException`来处理空值和无效参数。对于其他可能的异常(如文件IO异常、领域规则异常),它选择不捕获,而是让异常向上传播。这符合领域驱动设计(DDD)的原则,即应用服务层不处理领域层的业务异常,而是由上层(如API控制器)进行统一的异常处理和响应。 + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs#L45-L47) + +#### 权限控制机制 +当前代码中未发现显式的权限控制代码。`AppApplicationService`类上标记了`[RemoteService]`属性,这通常由ABP框架处理,可能用于启用远程调用和集成其权限系统。真正的权限检查(如基于角色或策略的授权)很可能在更上层的API控制器或通过ABP的`[Authorize]`属性实现,而不在应用服务内部。 + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs#L10) + +#### 应用发布功能 +应用的发布状态由`AppSchemaBase`中的`PublishStatus`属性管理,其类型为`PublishStatusEnum`,包含`Development`、`Approving`和`Published`三种状态。`AppApplicationService`本身不直接提供发布/取消发布的专用方法。发布操作是通过`SaveAsync`方法间接完成的:客户端在更新应用元数据时,将`PublishStatus`字段设置为`Published`,然后调用`SaveAsync`进行保存。这表明发布是应用元数据的一个普通属性变更。 + +```mermaid +stateDiagram-v2 +[*] --> Development +Development --> Approving : 提交审核 +Approving --> Published : 审核通过 +Approving --> Development : 审核拒绝 +Published --> Development : 取消发布 +``` + +**Diagram sources** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs#L20-L27) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) + +#### RESTful API 调用示例 +虽然`AppApplicationService`是应用服务,但根据ABP框架的约定,它会被自动发布为RESTful API。以下是一个创建或更新应用的API调用示例。 + +**请求**: +- **方法**: POST +- **路径**: `/api/app/save` +- **内容类型**: `application/json` +- **请求体**: +```json +{ + "id": "mynewapp", + "name": "我的新应用", + "description": "这是一个测试应用", + "publishStatus": 0, + "supportPlatforms": [0] +} +``` + +**响应**: +- **状态码**: 200 OK +- **响应体**: +```json +true +``` + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [IAppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs) + +## 依赖分析 +`AppApplicationService`的依赖关系清晰地体现了分层架构。它直接依赖于`IAppDomainService`(领域服务)和`IOptions>`(配置)。`IAppDomainService`又依赖于`IAppRepository`(仓储接口),而具体的仓储实现(如`AppFileRepository`)则依赖于文件系统API。这种依赖关系确保了应用服务层的纯净,使其不直接与数据存储细节耦合。 + +```mermaid +graph TD +AppService["AppApplicationService"] +DomainService["IAppDomainService"] +Repository["IAppRepository"] +FileRepo["AppFileRepository"] +Config["IOptions~List~SiteOption~~"] +AppService --> DomainService +AppService --> Config +DomainService --> Repository +Repository --> FileRepo +``` + +**Diagram sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) + +## 性能考虑 +由于应用元数据以JSON文件形式存储,读取操作(如`GetListAsync`)需要遍历目录并反序列化多个文件,这在应用数量庞大时可能成为性能瓶颈。写入操作(`SaveAsync`)是原子的,每次只写入单个应用的元数据文件,性能相对稳定。为了提高性能,可以考虑引入缓存机制,例如使用内存缓存(如`IMemoryCache`)来缓存频繁访问的应用列表或单个应用元数据,减少对文件系统的I/O操作。 + +## 故障排除指南 +- **问题**: 调用`SaveAsync`时返回`false`或抛出异常。 + - **检查**: 确保传入的`appSchema`对象及其`Id`属性不为`null`或空字符串。 +- **问题**: 创建的应用在列表中找不到。 + - **检查**: 确认`meta/apps/{appId}/`目录下是否生成了`{appId}.json`文件。检查文件系统权限是否允许写入。 +- **问题**: `SiteUrl`在`AppListModel`中为`null`。 + - **检查**: 确认`appsettings.json`中的`SiteOptions`配置是否包含与应用ID匹配的条目。 +- **问题**: 应用发布后前端未更新。 + - **检查**: 确认`PublishStatus`字段已正确设置为`Published`,并已通过`SaveAsync`保存。检查前端是否正确处理了发布状态。 + +**Section sources** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppListModel.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Model/Models/AppListModel.cs) + +## 结论 +`AppApplicationService`作为低代码平台应用管理的核心服务,设计简洁且职责明确。它成功地将应用层逻辑与领域逻辑和数据持久化逻辑分离,遵循了良好的软件设计原则。服务通过调用领域服务来执行业务操作,并通过手动映射处理DTO转换。系统利用文件系统的目录结构实现了有效的应用隔离。虽然当前的异常处理和权限控制较为基础,但其架构为未来的扩展(如引入缓存、增强权限系统)提供了坚实的基础。整体而言,该服务是低代码平台可维护性和可扩展性的关键组成部分。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\346\225\260\346\215\256\346\272\220\347\256\241\347\220\206\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\346\225\260\346\215\256\346\272\220\347\256\241\347\220\206\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..5a8807510a3f350d91a1e1225385599c7b573ce5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\346\225\260\346\215\256\346\272\220\347\256\241\347\220\206\346\234\215\345\212\241.md" @@ -0,0 +1,314 @@ +# 数据源管理服务 + + +**本文档引用的文件** +- [IDataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IDataSourceAppService.cs) +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs) +- [IDataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IDataSourceDomainService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [ComponentDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceTypeEnum.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档深入剖析了低代码平台中数据源管理服务(DataSourceAppService)的核心功能与实现机制。该服务作为设计引擎的一部分,负责统一管理多种类型的数据源,包括数据库、API、静态选项等。文档详细阐述了数据源的创建、保存、查询、删除等全生命周期管理流程,揭示了从应用服务层到领域服务层再到仓储层的分层架构设计。通过分析接口契约、领域逻辑和文件持久化机制,展示了系统如何将数据源配置以JSON文件的形式存储在文件系统中,并支持按应用ID进行隔离管理。同时,文档还介绍了不同类型数据源(如API、SQL)的差异化配置结构及其在系统中的分类方式。 + +## 项目结构 +项目采用分层架构设计,将应用逻辑、领域逻辑和数据访问逻辑清晰分离。数据源管理功能主要分布在`src/DesignEngine`目录下,遵循典型的DDD(领域驱动设计)模式。 + +```mermaid +graph TB +subgraph "设计引擎 DesignEngine" +subgraph "应用层 Application" +AppService[DataSourceAppService] +end +subgraph "领域层 Domain" +DomainService[DataSourceDomainService] +Repository[IDataSourceRepository] +end +subgraph "仓储层 Repository.JsonFile" +FileRepository[DataSourceFileRepository] +end +subgraph "共享模型 Common" +MetaSchema[MetaSchema] +end +end +AppService --> DomainService +DomainService --> Repository +Repository --> FileRepository +FileRepository --> MetaSchema +AppService --> MetaSchema +``` + +**图示来源** +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) + +**本节来源** +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) + +## 核心组件 +数据源管理服务的核心组件包括应用服务(AppService)、领域服务(DomainService)和仓储(Repository)。`DataSourceAppService`作为外部接口的入口,实现了`IDataSourceAppService`契约,提供增删改查等RESTful风格的操作。`DataSourceDomainService`封装了业务逻辑,确保操作的原子性和一致性。`DataSourceFileRepository`则负责将数据源配置持久化到文件系统,采用JSON格式存储,路径为`{metaBaseDir}/{appId}/datasource/{id}.json`。所有数据源的配置都继承自`DataSourceSchema`基类,该类定义了ID、名称、类型、排序等通用属性,并通过组合模式支持不同类型数据源的特定配置。 + +**本节来源** +- [IDataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IDataSourceAppService.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 架构概览 +系统采用清晰的分层架构,确保关注点分离。应用服务层负责处理HTTP请求和响应,进行基本的参数验证。领域服务层包含核心业务逻辑,协调仓储操作。仓储层则专注于数据的持久化,与具体的存储介质(如文件系统)交互。这种设计使得上层逻辑不依赖于底层存储实现,便于未来扩展支持数据库或其他存储方式。 + +```mermaid +graph TD +Client[客户端] --> API[DataSourceAppService] +API --> Domain[DataSourceDomainService] +Domain --> Repository[IDataSourceRepository] +Repository --> Implementation[DataSourceFileRepository] +Implementation --> Storage[文件系统 JSON] +style Client fill:#f9f,stroke:#333 +style API fill:#bbf,stroke:#333 +style Domain fill:#f96,stroke:#333 +style Repository fill:#6f9,stroke:#333 +style Implementation fill:#69f,stroke:#333 +style Storage fill:#9f9,stroke:#333 +``` + +**图示来源** +- [IDataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IDataSourceAppService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 详细组件分析 +### 应用服务层分析 +`DataSourceAppService`实现了`IDataSourceAppService`接口,是外部系统访问数据源功能的入口。它通过依赖注入获取`IDataSourceDomainService`实例,并将请求委派给领域服务处理。 + +#### 类图 +```mermaid +classDiagram +class IDataSourceAppService { +<> ++GetListAsync(appId, input) IList~DataSourceListModel~ ++GetByIdAsync(appId, id) DataSourceSchema ++SaveAsync(appId, dataSourceSchema) bool ++DeleteAsync(appId, id) bool +} +class DataSourceAppService { +-_domainService IDataSourceDomainService ++GetListAsync(appId, input) Task~IList~DataSourceListModel~~ ++GetByIdAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task~bool~ ++DeleteAsync(appId, id) Task~bool~ +} +class IDataSourceDomainService { +<> ++GetListAsync(appId) Task~IList~DataSourceSchema~~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +IDataSourceAppService <|-- DataSourceAppService +DataSourceAppService --> IDataSourceDomainService : "依赖" +``` + +**图示来源** +- [IDataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IDataSourceAppService.cs) +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs) +- [IDataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IDataSourceDomainService.cs) + +**本节来源** +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs) + +### 领域服务层分析 +`DataSourceDomainService`实现了`IDataSourceDomainService`接口,是业务逻辑的核心。它不包含复杂的业务规则,主要职责是协调仓储操作,体现了该系统中领域逻辑相对简单的特性。 + +#### 类图 +```mermaid +classDiagram +class IDataSourceDomainService { +<> ++GetListAsync(appId) Task~IList~DataSourceSchema~~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +class DataSourceDomainService { +-_repository IDataSourceRepository ++DataSourceDomainService(repository) ++GetListAsync(appId) Task~IList~DataSourceSchema~~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +class IDataSourceRepository { +<> ++GetListAsync(appId) Task~IList~DataSourceSchema~~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +IDataSourceDomainService <|-- DataSourceDomainService +DataSourceDomainService --> IDataSourceRepository : "依赖" +``` + +**图示来源** +- [IDataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IDataSourceDomainService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) + +### 仓储层分析 +`DataSourceFileRepository`是`IDataSourceRepository`的具体实现,负责将数据源配置持久化到文件系统。它使用`FileRepositoryBase`基类提供的文件读写能力。 + +#### 数据源保存流程 +```mermaid +flowchart TD +Start([开始保存数据源]) --> Validate["验证参数
非空检查"] +Validate --> SetTime["设置修改时间
ModifiedTime = UTC Now"] +SetTime --> BuildPath["构建文件路径
{metaBaseDir}/{appId}/datasource/{id}.json"] +BuildPath --> CheckDir["检查目录是否存在"] +CheckDir --> |不存在| CreateDir["创建目录"] +CheckDir --> |存在| WriteFile +CreateDir --> WriteFile["写入JSON文件
使用UTF-8编码"] +WriteFile --> Complete["完成"] +style Start fill:#9f9,stroke:#333 +style Complete fill:#9f9,stroke:#333 +``` + +**图示来源** +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs#L55-L75) + +**本节来源** +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +### 数据模型分析 +`DataSourceSchema`是所有数据源的基类,采用组合模式支持不同类型的数据源配置。 + +#### 数据源类型枚举 +```mermaid +classDiagram +class ComponentDataSourceTypeEnum { +<> +None = 0 +DB = 1 +API = 2 +Option = 3 +SQL = 6 +Expression = 7 +Fiexd = 8 +} +``` + +**图示来源** +- [ComponentDataSourceTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceTypeEnum.cs) + +#### 数据源模式类图 +```mermaid +classDiagram +class DataSourceSchema { ++AppId string ++Id string ++Name string ++DisplayName string ++Description string ++Order int ++DataSourceType ComponentDataSourceTypeEnum ++PublishStatus bool +} +class APIDataSourceSchema { ++Domain string ++Path string ++Method string ++Queries IList~APIParamSchema~ ++Body APIBodySchema ++Headers IList~APIParamSchema~ +} +class SQLDataSourceSchema { ++DbType string ++Sql string +} +class OptionDataSourceSchema { ++Options OptionDataSourceSchema[] ++Values IDictionary~string, string~ +} +DataSourceSchema --> APIDataSourceSchema : "API" +DataSourceSchema --> SQLDataSourceSchema : "SQL" +DataSourceSchema --> OptionDataSourceSchema : "Option" +``` + +**图示来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) + +**本节来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) + +## 依赖关系分析 +系统各组件之间存在清晰的依赖关系,遵循依赖倒置原则。高层模块(AppService)依赖于抽象(DomainService接口),而非具体实现。 + +```mermaid +graph TD +DataSourceAppService --> IDataSourceDomainService +IDataSourceDomainService --> DataSourceDomainService +DataSourceDomainService --> IDataSourceRepository +IDataSourceRepository --> DataSourceFileRepository +DataSourceFileRepository --> FileRepositoryBase +DataSourceAppService --> DataSourceListModel +DataSourceDomainService --> DataSourceSchema +DataSourceFileRepository --> DataSourceSchema +``` + +**图示来源** +- [IDataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IDataSourceAppService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +**本节来源** +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 性能考量 +由于数据源配置通常不会频繁变动,且单个应用的数据源数量有限,当前基于文件系统的持久化方案在性能上是可接受的。每次读取操作会加载应用目录下的所有数据源文件,对于数据源数量较多的应用,可能会产生一定的I/O开销。缓存机制可以进一步优化性能,但当前代码中未实现。`GetAllEntities`方法中使用了`.Result`来同步获取异步结果,这在高并发场景下可能导致线程阻塞,是一个潜在的性能瓶颈。 + +## 故障排除指南 +### 常见问题 +1. **数据源无法保存**:检查`appId`和`id`是否为空,确保`metaBaseDir`配置正确且应用目录有写入权限。 +2. **数据源无法读取**:确认文件路径`{metaBaseDir}/{appId}/datasource/{id}.json`是否存在,文件内容是否为有效的JSON格式。 +3. **连接测试失败**:虽然本文档未涉及连接测试代码,但通常需要检查API的域名、路径、参数或数据库连接字符串是否正确。 + +### 错误处理 +- `SaveAsync`和`DeleteAsync`方法在参数为空时会抛出`ArgumentNullException`或`ArgumentException`。 +- 文件读取时,如果文件不存在,`GetAsync`会抛出异常,而`GetListAsync`会返回空列表。 +- 文件写入时,如果目录不存在,会自动创建。 + +**本节来源** +- [DataSourceAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs#L45-L48) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 结论 +数据源管理服务通过清晰的分层架构实现了对多种类型数据源的统一管理。系统采用DDD模式,将应用服务、领域服务和仓储分离,确保了代码的可维护性和可扩展性。数据源配置以JSON文件的形式持久化在文件系统中,实现了按应用隔离的存储策略。`DataSourceSchema`基类通过组合模式灵活支持API、SQL、选项等不同类型的数据源。尽管当前实现较为简单,但其架构设计为未来引入更复杂的业务逻辑(如连接测试、字段探测、敏感信息加密)提供了良好的基础。建议优化`GetAllEntities`中的同步等待问题,并考虑引入缓存机制以提升读取性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\350\217\234\345\215\225\347\256\241\347\220\206\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\350\217\234\345\215\225\347\256\241\347\220\206\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..a97679e101615fa488639e034ce0ecc0d53185a1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\350\217\234\345\215\225\347\256\241\347\220\206\346\234\215\345\212\241.md" @@ -0,0 +1,254 @@ +# 菜单管理服务 + + +**本文档引用的文件** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档全面解析了低代码平台中的菜单管理服务(MenuAppService)的实现逻辑。该服务负责管理应用的菜单项,支持菜单的增删改查操作,维护菜单的层级结构,并构建用于导航的树形菜单。文档重点描述了菜单项的父子关系管理、排序机制、图标与路径配置、权限控制以及与页面的关联方式。通过分析核心代码文件,揭示了从数据存储到树形结构构建的完整流程。 + +## 项目结构 +菜单管理服务是低代码平台设计引擎(DesignEngine)的一部分,其代码分布在多个模块中,遵循分层架构设计。核心逻辑位于`H.LowCode.DesignEngine.Application`模块,业务规则在`H.LowCode.DesignEngine.Domain`模块,数据持久化由`H.LowCode.DesignEngine.Repository.JsonFile`模块实现,而数据结构定义在`H.LowCode.MetaSchema`模块中。 + +```mermaid +graph TB +subgraph "设计引擎 (DesignEngine)" +subgraph "应用层 (Application)" +MenuAppService["MenuAppService
处理API请求"] +end +subgraph "领域层 (Domain)" +MenuDomainService["MenuDomainService
核心业务逻辑"] +MenuRepository["IMenuRepository
数据访问接口"] +end +subgraph "基础设施层 (Repository)" +MenuFileRepository["MenuFileRepository
JSON文件存储"] +end +subgraph "元数据模型 (MetaSchema)" +MenuSchema["MenuSchema
菜单数据结构"] +end +end +MenuAppService --> MenuDomainService +MenuDomainService --> MenuRepository +MenuFileRepository --> MenuRepository +MenuSchema --> MenuAppService +MenuSchema --> MenuDomainService +MenuSchema --> MenuFileRepository +style MenuAppService fill:#e1f5fe,stroke:#039be5 +style MenuDomainService fill:#e8f5e8,stroke:#43a047 +style MenuFileRepository fill:#fff3e0,stroke:#fb8c00 +style MenuSchema fill:#f3e5f5,stroke:#8e24aa +``` + +**图示来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) + +**本节来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) + +## 核心组件 +菜单管理服务的核心组件包括`MenuAppService`、`MenuDomainService`、`MenuFileRepository`和`MenuSchema`。`MenuAppService`作为应用服务,对外提供API接口;`MenuDomainService`封装了核心业务逻辑;`MenuFileRepository`负责将菜单数据以JSON文件的形式持久化到文件系统;`MenuSchema`定义了菜单项的数据结构,包含标题、图标、路径、排序和父子关系等属性。 + +**本节来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) + +## 架构概览 +菜单管理服务采用典型的分层架构,分为应用层、领域层和基础设施层。应用层的`MenuAppService`接收外部请求,通过依赖注入获取领域服务`MenuDomainService`的实例来执行业务逻辑。领域服务`MenuDomainService`通过`IMenuRepository`接口与数据访问层交互,具体的实现由`MenuFileRepository`提供,它将菜单数据存储在`meta/apps/{appId}/menu/`目录下的JSON文件中。`MenuSchema`作为数据传输对象(DTO),贯穿于各层之间。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AppService as "MenuAppService" +participant DomainService as "MenuDomainService" +participant Repository as "MenuFileRepository" +Client->>AppService : GetListAsync(appId) +AppService->>DomainService : GetListAsync(appId) +DomainService->>Repository : GetListAsync(appId) +Repository-->>DomainService : 返回菜单列表 +DomainService-->>AppService : 返回菜单列表 +AppService-->>Client : 返回树形菜单结构 +Client->>AppService : SaveAsync(menuSchema) +AppService->>DomainService : SaveAsync(menuSchema) +DomainService->>Repository : SaveAsync(menuSchema) +Repository-->>DomainService : 完成 +DomainService-->>AppService : 完成 +AppService-->>Client : true +Client->>AppService : DeleteAsync(appId, menuId) +AppService->>DomainService : DeleteAsync(appId, menuId) +DomainService->>Repository : DeleteAsync(appId, menuId) +Repository-->>DomainService : 完成 +DomainService-->>AppService : 完成 +AppService-->>Client : true +``` + +**图示来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs#L12-L41) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs#L15-L18) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L39-L80) + +## 详细组件分析 +本节将深入分析菜单管理服务的各个关键组件,包括菜单数据结构、增删改查操作、树形结构构建和删除约束等。 + +### 菜单数据结构分析 +`MenuSchema`类定义了菜单项的所有属性,是整个服务的数据基础。 + +```mermaid +classDiagram +class MenuSchema { ++string AppId ++string Id ++string ParentId ++string Title ++int MenuType ++string Icon ++string MenuUrl ++int Order ++IList Childrens +} +MenuSchema <|-- MetaSchemaBase : "继承" +``` + +**图示来源** +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs#L5-L37) + +**本节来源** +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) + +#### 菜单项层级结构与导航树构建 +服务通过`GetListAsync`方法获取指定应用的所有菜单项,并在`MenuFileRepository`中调用`BuildTreeMenus`方法将扁平化的菜单列表转换为树形结构。该方法首先创建一个以菜单ID为键的字典,然后遍历所有菜单项,如果`ParentId`为空,则将其作为根节点添加到`treeMenus`列表中;否则,根据`ParentId`在字典中查找父节点,并将当前菜单项添加到父节点的`Childrens`集合中。最后,对根节点和每个父节点的子节点集合按`Order`字段进行排序。 + +```mermaid +flowchart TD +Start([开始]) --> LoadFiles["加载所有菜单JSON文件"] +LoadFiles --> ParseJson["解析JSON为MenuSchema对象"] +ParseJson --> CreateList["创建菜单列表"] +CreateList --> BuildTree["调用BuildTreeMenus"] +subgraph BuildTreeMenus +BuildTree --> CreateDict["创建ID到菜单的字典"] +CreateDict --> LoopMenus["遍历每个菜单"] +LoopMenus --> CheckParent{"ParentId为空?"} +CheckParent --> |是| AddToRoot["添加到根节点列表"] +CheckParent --> |否| FindParent["在字典中查找父节点"] +FindParent --> ParentFound{"找到父节点?"} +ParentFound --> |是| AddToChildren["添加到父节点的Childrens"] +ParentFound --> |否| ThrowError["抛出KeyNotFoundException"] +AddToChildren --> SortChildren["按Order排序子节点"] +end +BuildTree --> SortRoot["按Order排序根节点"] +SortRoot --> ReturnTree["返回树形结构"] +ReturnTree --> End([结束]) +style BuildTreeMenus fill:#f0f8ff,stroke:#4682b4 +``` + +**图示来源** +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L39-L84) + +**本节来源** +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) + +#### 菜单增删改查操作 +`MenuAppService`提供了标准的CRUD(创建、读取、更新、删除)接口。`SaveAsync`方法用于创建或更新菜单项,它会验证输入参数的合法性,并在保存时更新`ModifiedTime`字段。`DeleteAsync`方法在删除前会检查是否存在子节点,如果存在,则抛出`InvalidOperationException`异常,防止出现孤立的子节点。 + +```mermaid +flowchart TD +subgraph "保存菜单 (SaveAsync)" +SaveStart([开始]) --> ValidateInput["验证menuSchema不为空且Id不为空"] +ValidateInput --> SetModified["设置ModifiedTime为当前UTC时间"] +SetModified --> SaveToFile["将menuSchema序列化为JSON并写入文件"] +SaveToFile --> SaveEnd([结束]) +end +subgraph "删除菜单 (DeleteAsync)" +DeleteStart([开始]) --> CheckFile["检查菜单文件是否存在"] +CheckFile --> LoadAllMenus["加载应用下所有菜单"] +LoadAllMenus --> CheckChildren{"是否存在ParentId等于menuId的子节点?"} +CheckChildren --> |是| ThrowDeleteError["抛出InvalidOperationException"] +CheckChildren --> |否| DeleteFile["删除菜单文件"] +DeleteFile --> DeleteEnd([结束]) +end +style SaveStart fill:#c8e6c9,stroke:#43a047 +style SaveEnd fill:#c8e6c9,stroke:#43a047 +style DeleteStart fill:#ffcdd2,stroke:#e53935 +style DeleteEnd fill:#ffcdd2,stroke:#e53935 +style SaveToFile fill:#bbdefb,stroke:#1976d2 +style DeleteFile fill:#bbdefb,stroke:#1976d2 +style CheckChildren fill:#fff9c4,stroke:#fbc02d +``` + +**图示来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs#L30-L41) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L81-L129) + +**本节来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) + +## 依赖分析 +菜单管理服务的依赖关系清晰,遵循依赖倒置原则。`MenuAppService`依赖于抽象的`IMenuDomainService`,`MenuDomainService`依赖于抽象的`IMenuRepository`。具体的实现`MenuFileRepository`实现了`IMenuRepository`接口。这种设计使得应用层和领域层不直接依赖于具体的数据存储技术,提高了代码的可测试性和可维护性。 + +```mermaid +graph LR +MenuAppService --> IMenuDomainService +IMenuDomainService --> MenuDomainService +MenuDomainService --> IMenuRepository +IMenuRepository --> MenuFileRepository +style MenuAppService fill:#e1f5fe,stroke:#039be5 +style IMenuDomainService fill:#b2dfdb,stroke:#00897b +style MenuDomainService fill:#e8f5e8,stroke:#43a047 +style IMenuRepository fill:#b2dfdb,stroke:#00897b +style MenuFileRepository fill:#fff3e0,stroke:#fb8c00 +``` + +**图示来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs#L12) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs#L10) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L9) + +**本节来源** +- [MenuAppService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs) + +## 性能考虑 +目前的实现将每个菜单项存储为一个独立的JSON文件。这种设计简单直接,但在菜单项数量庞大时,`GetListAsync`方法需要遍历整个菜单目录并读取每个文件,可能会导致性能瓶颈。此外,`DeleteAsync`方法在删除前需要加载所有菜单项以检查子节点,这也增加了I/O开销。一个潜在的优化方向是引入缓存机制,在应用启动或菜单变更时将整个菜单树缓存到内存中,从而避免频繁的文件I/O操作。 + +## 故障排除指南 +* **问题:删除菜单项时失败,提示“存在子节点, 不允许删除!”** + * **原因**:尝试删除的菜单项仍有子菜单。 + * **解决方案**:请先删除或移动所有子菜单,然后再尝试删除父菜单。 + +* **问题:获取菜单列表时返回空或部分菜单** + * **原因**:文件系统中的菜单JSON文件可能损坏,或者`ParentId`指向了一个不存在的ID。 + * **解决方案**:检查`meta/apps/{appId}/menu/`目录下的所有JSON文件,确保`ParentId`的有效性,并修复或删除损坏的文件。 + +* **问题:菜单树的顺序不正确** + * **原因**:`Order`字段的值设置不正确。 + * **解决方案**:确保在保存菜单项时,为`Order`字段设置了正确的整数值,数值越小,排序越靠前。 + +**本节来源** +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L110) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L55) +- [MenuFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs#L70) + +## 结论 +菜单管理服务通过清晰的分层架构和简洁的JSON文件存储方案,有效地实现了菜单项的增删改查和树形结构管理。服务通过`MenuSchema`的`ParentId`和`Childrens`属性维护层级关系,并利用`Order`字段实现排序。`BuildTreeMenus`方法是构建导航树的核心,而`DeleteAsync`方法中的子节点检查保证了数据的完整性。尽管当前实现存在潜在的性能问题,但其设计为未来的优化(如引入缓存)提供了良好的基础。该服务是低代码平台中构建应用导航结构的关键组件。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\351\241\265\351\235\242\347\256\241\347\220\206\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\351\241\265\351\235\242\347\256\241\347\220\206\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..361fb325b38fae8a5b678eec9fdf1ea50eba9e7c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\345\272\224\347\224\250\346\234\215\345\212\241\345\261\202/\351\241\265\351\235\242\347\256\241\347\220\206\346\234\215\345\212\241.md" @@ -0,0 +1,284 @@ +# 页面管理服务 + + +**本文档引用文件** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [IPageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IPageAppService.cs) +- [PageListModel.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Model\Models\PageListModel.cs) +- [IPageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IPageDomainService.cs) +- [PageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\PageDomainService.cs) +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs) +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档详细阐述了低代码平台中 `PageAppService` 在页面设计与管理中的核心职责。该服务作为应用层的关键组件,负责协调领域服务完成页面的增删改查、发布、版本管理和元数据操作。文档将深入分析其与 `IPageDomainService` 的协作机制、DTO 与实体的映射逻辑、分页查询实现、事务处理、缓存策略及事件发布机制,并结合代码实例说明页面类型、路由规则和权限校验等关键功能。 + +## 项目结构 +项目采用分层架构,核心页面管理功能位于 `src/DesignEngine` 目录下。主要模块包括: +- **Application**: 应用服务层,`PageAppService` 位于此,处理业务编排。 +- **Application.Contracts**: 定义应用服务接口,如 `IPageAppService`。 +- **Domain**: 领域层,包含 `IPageDomainService` 和 `PageDomainService`,负责核心业务逻辑。 +- **Repository.JsonFile**: 数据访问层,`PageFileRepository` 将页面元数据持久化为 JSON 文件。 +- **Model**: 数据传输对象(DTO)定义,如 `PageListModel`。 +- **Common/H.LowCode.MetaSchema**: 元数据模型基类和枚举定义。 + +```mermaid +graph TD +A[PageAppService] --> B[IPageDomainService] +B --> C[IPageRepository] +C --> D[PageFileRepository] +A --> E[IComponentPartsAppService] +F[PageListModel] --> A +G[PagePartsSchema] --> A +H[PageSchemaBase] --> G +``` + +**图示来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [IPageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IPageAppService.cs) +- [IPageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IPageDomainService.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [project_structure](file://project_structure) + +## 核心组件 +核心组件包括 `PageAppService`(应用服务)、`IPageDomainService`(领域服务接口)、`PageDomainService`(领域服务实现)和 `PageFileRepository`(仓储实现)。`PageAppService` 作为协调者,调用 `IPageDomainService` 执行业务逻辑,后者通过 `IPageRepository` 操作数据。`PageListModel` 是用于列表展示的 DTO,而 `PagePartsSchema` 则是包含完整页面结构的领域实体。 + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [IPageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IPageDomainService.cs) +- [PageListModel.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Model\Models\PageListModel.cs) + +## 架构概览 +系统采用经典的分层架构(Application -> Domain -> Repository),确保关注点分离。`PageAppService` 处于应用层,接收外部请求,进行初步校验后,将任务委派给领域服务 `PageDomainService`。领域服务负责业务规则的执行,如页面结构验证,然后通过仓储接口 `IPageRepository` 将数据持久化。当前实现使用 `PageFileRepository` 将页面元数据以 JSON 文件形式存储在磁盘上。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AppService as "PageAppService" +participant DomainService as "PageDomainService" +participant Repository as "PageFileRepository" +Client->>AppService : SaveAsync(pageSchema) +AppService->>AppService : 参数校验 +AppService->>DomainService : SaveAsync(pageSchema) +DomainService->>Repository : SaveAsync(pageSchema) +Repository-->>DomainService : 保存成功 +DomainService-->>AppService : 返回 +AppService-->>Client : true +``` + +**图示来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [PageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\PageDomainService.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +## 详细组件分析 + +### PageAppService 分析 +`PageAppService` 是页面管理功能的入口,实现了 `IPageAppService` 接口,提供了页面的增删改查、获取及组件查询等 API。 + +#### 职责与方法 +- **增删改查 (CRUD)**: `SaveAsync` 和 `DeleteAsync` 方法分别用于创建/更新和删除页面。`GetListAsync` 和 `GetByIdAsync` 用于查询。 +- **协调领域服务**: 服务通过依赖注入获取 `IPageDomainService` 实例,并将其作为 `LazyServiceProvider`,在需要时才解析,以优化性能。所有核心操作(如保存、删除)都直接委托给 `_domainService`。 +- **组件属性合并**: `GetByIdWithDefineAsync` 方法在获取页面后,会递归遍历页面中的所有组件,并调用 `MergeComponentPartsDefineRecursive` 方法,从 `IComponentPartsAppService` 获取组件的最新定义(`ComponentPartsDefine`),并将其与页面中组件的实例属性进行合并。这确保了旧的组件实例能够继承新版本组件的所有特性和默认配置。 + +```csharp +private async Task MergeComponentPartsDefineRecursive(ComponentPartsSchema component) +{ + // 获取组件定义 + var componentPartsDefine = await _componentPartsAppService.GetByIdAsync(component.LibraryId, component.ComponentId); + // 实例与定义合并 + component.MergeComponentPartsDefine(componentPartsDefine); + // 递归处理子组件 + if (component.Childrens != null && component.Childrens.Count > 0) + { + foreach (var child in component.Childrens) + { + await MergeComponentPartsDefineRecursive(child); + } + } +} +``` + +#### 页面 DTO 与实体映射 +`PageListModel` 是一个轻量级的 DTO,用于在页面列表中展示关键信息。它与领域实体 `PagePartsSchema` 的映射发生在仓储层(`PageFileRepository`)。 + +```csharp +// 在 PageFileRepository.GetListAsync 中的映射逻辑 +PageListModel model = new() +{ + PageId = pageSchema.Id, + PageName = pageSchema.Name, + Order = pageSchema.Order, + PageType = pageSchema.PageType, + PublishStatus = pageSchema.PublishStatus, + ModifiedTime = pageSchema.ModifiedTime +}; +``` +这种映射将完整的 `PagePartsSchema` 实体精简为列表视图所需的字段,提高了查询效率。 + +#### 分页查询实现 +`GetListAsync` 方法返回一个 `List`。虽然当前实现没有显式的分页参数(如 `pageIndex`, `pageSize`),但其返回的是一个完整的列表。分页逻辑可能在前端或更高层的 API 网关中实现。服务本身负责从仓储获取所有数据,并按 `Order` 字段进行排序。 + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [PageListModel.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Model\Models\PageListModel.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +### PageDomainService 分析 +`PageDomainService` 是 `IPageDomainService` 接口的实现,它本身不包含复杂的业务逻辑,而是作为一个薄层,将调用转发给 `IPageRepository`。这表明当前的业务规则(如页面创建时的默认配置生成、结构验证、父子关系维护)可能直接内嵌在 `PagePartsSchema` 实体的构造函数或方法中,或者在 `PageAppService` 中完成,而领域服务层主要负责协调。 + +#### 与 IPageDomainService 的协作 +`PageAppService` 通过 `IPageDomainService` 接口与领域服务交互,这遵循了依赖倒置原则。尽管当前 `PageDomainService` 实现较为简单,但它为未来扩展(如添加复杂的验证逻辑、事务管理或事件发布)提供了清晰的扩展点。 + +**本节来源** +- [PageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\PageDomainService.cs) +- [IPageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IPageDomainService.cs) + +### 页面保存流程分析 +页面保存流程是一个典型的 CQRS 模式应用。 + +#### 事务处理 +在当前基于文件系统的实现中,`PageFileRepository.SaveAsync` 方法将整个页面 Schema 序列化为一个 JSON 文件并写入磁盘。这个操作本身是原子的(覆盖写入),但由于没有数据库事务,无法保证跨多个文件的强一致性。如果未来迁移到数据库,`PageDomainService` 将是添加事务注解(如 `[UnitOfWork]`)的理想位置。 + +#### 缓存更新策略 +当前代码中未发现显式的缓存机制(如内存缓存或分布式缓存)。每次 `GetByIdAsync` 调用都会直接从文件系统读取 JSON 文件。这意味着数据始终是最新,但可能影响性能。一个潜在的优化是在 `PageDomainService` 或 `PageAppService` 中引入缓存层,在数据变更时(`SaveAsync`, `DeleteAsync`)使缓存失效。 + +#### 事件发布机制 +当前代码中未发现事件发布(Event Publishing)的实现。`PageAppService` 在 `SaveAsync` 成功后直接返回 `true`,没有发布任何领域事件(如 `PageCreatedEvent`, `PageUpdatedEvent`)。事件机制可以在此服务中添加,用于通知其他系统(如索引服务、审计服务)页面状态的变更。 + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [PageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\PageDomainService.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +### 页面类型与路由规则 +#### 页面类型 (PageTypeEnum) +`PageTypeEnum` 枚举定义了平台支持的页面类型,包括普通页面、表单页面、列表页面和报表页面。该类型存储在 `PageSchemaBase` 的 `PageType` 属性中,用于在运行时区分页面的用途和渲染方式。 + +```csharp +public enum PageTypeEnum +{ + [Display(Name = "普通")] + Normal = 0, + [Display(Name = "表单")] + Form = 1, + [Display(Name = "列表")] + Table = 2, + [Display(Name = "报表")] + Report = 5 +} +``` + +#### 路由生成规则 +当前代码库中未找到明确的路由生成逻辑。路由规则可能由前端框架(如 Blazor)根据应用和页面的 ID 动态生成,或在 `RenderEngine` 模块中处理。`PageFileRepository` 中的 `pageFileName_Format` 定义了元数据文件的存储路径 `"{0}\{1}\page\{2}.json"`,其中 `{1}` 是 `appId`,`{2}` 是 `pageId`,这暗示了 URL 路径可能与此类似(例如 `/app/{appId}/page/{pageId}`)。 + +**本节来源** +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs) +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +### 权限校验逻辑 +在分析的 `PageAppService`、`PageDomainService` 和 `PageFileRepository` 代码中,**未发现显式的权限校验逻辑**。例如,在 `SaveAsync` 或 `DeleteAsync` 方法中,没有检查当前用户是否具有修改特定 `appId` 下页面的权限。这表明权限校验可能在更上层的拦截器、中间件或 API 网关中实现,或者在未来的版本中需要添加。 + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [PageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\PageDomainService.cs) + +### API 示例 +#### 创建表单页面 +```csharp +// 1. 创建页面 Schema +var formPage = new PagePartsSchema +{ + AppId = "caseapp", + Name = "用户信息表单", + PageType = PageTypeEnum.Form, + Order = 1, + PageProperty = new PagePropertySchema { PageLayout = 1 }, // 一列表单 + Components = new List() + // ... 添加表单组件 +}; + +// 2. 调用服务保存 +var success = await pageAppService.SaveAsync(formPage); +if (success) +{ + Console.WriteLine("表单页面创建成功!"); +} +``` + +#### 更新页面布局配置 +```csharp +// 1. 获取现有页面 +var pageSchema = await pageAppService.GetByIdAsync("caseapp", "0lgu6xpop"); + +// 2. 修改布局 +pageSchema.PageProperty.PageLayout = 3; // 改为三列布局 + +// 3. 保存更新 +await pageAppService.SaveAsync(pageSchema); +``` + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [PageSchemaBase.cs](file://src\Common\H.LowCode.MetaSchema\PageSchemaBase.cs) +- [PageTypeEnum.cs](file://src\Common\H.LowCode.MetaSchema\Enums\PageTypeEnum.cs) + +## 依赖分析 +`PageAppService` 的主要依赖关系清晰: +- **强依赖**: `IPageDomainService` (领域服务) 和 `IComponentPartsAppService` (用于组件定义合并)。 +- **间接依赖**: 通过领域服务依赖 `IPageRepository`,最终由 `PageFileRepository` 实现。 +- **数据模型依赖**: `PageListModel` 和 `PagePartsSchema`。 + +```mermaid +graph TD +PageAppService --> IPageDomainService +PageAppService --> IComponentPartsAppService +IPageDomainService --> IPageRepository +IPageRepository --> PageFileRepository +PageListModel -.-> PageAppService +PagePartsSchema -.-> PageAppService +``` + +**图示来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [IPageDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IPageDomainService.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) + +## 性能考量 +- **优点**: 基于文件的存储简单、轻量,读取速度快,适合元数据不频繁变更的场景。 +- **缺点**: + - **列表查询**: `GetListAsync` 会扫描整个 `page` 目录并读取每个 JSON 文件,当页面数量庞大时,性能会显著下降。建议实现分页和缓存。 + - **缓存缺失**: 缺少缓存机制,每次请求都会触发磁盘 I/O。 + - **并发写入**: 文件系统在高并发写入时可能存在锁竞争问题。 + +## 故障排除指南 +- **页面无法保存**: 检查 `appId` 和 `pageId` 是否为空,确认磁盘路径 `{metaBaseDir}\{appId}\page\` 是否可写。 +- **页面列表为空**: 确认 `appId` 是否正确,检查对应应用的 `page` 目录是否存在且包含 `.json` 文件。 +- **组件属性未更新**: 确保 `IComponentPartsAppService` 能正确返回最新的组件定义,检查 `MergeComponentPartsDefineRecursive` 逻辑是否执行。 + +**本节来源** +- [PageAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\PageAppService.cs) +- [PageFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\PageFileRepository.cs) + +## 结论 +`PageAppService` 是低代码平台页面管理的核心服务,它通过协调 `IPageDomainService` 和 `IComponentPartsAppService`,高效地完成了页面的全生命周期管理。其设计遵循了分层架构和依赖倒置原则。然而,当前实现缺少事务、缓存和事件发布等高级特性,且权限校验需在外部处理。未来可通过引入数据库、缓存和领域事件来增强系统的健壮性和可扩展性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\350\256\276\350\256\241\345\274\225\346\223\216.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\350\256\276\350\256\241\345\274\225\346\223\216.md" new file mode 100644 index 0000000000000000000000000000000000000000..b1881f3c09e5fbbbcd3e496a7248e0d431479827 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\350\256\276\350\256\241\345\274\225\346\223\216.md" @@ -0,0 +1,462 @@ +# 设计引擎 + + +**本文档中引用的文件** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [FileRepositoryBase.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Base\FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) +- [DragItem.razor.css](file://src\DesignEngine\H.LowCode.DesignEngine\ComponentPanel\DragItem.razor.css) +- [PageSetting.razor.css](file://src\DesignEngine\H.LowCode.DesignEngine\SettingPanel\PageSetting.razor.css) +- [DragDropStateService.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\Services\DragDropStateService.cs) +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs) +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs) +- [ComponentDesignStateSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentDesignStateSchema.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖关系分析](#依赖关系分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +设计引擎是低代码平台中的可视化开发环境,允许用户通过拖拽方式构建应用程序界面。该引擎采用分层架构,包含应用层、领域层和仓库层,支持多种存储后端(如JsonFile、RemoteService、EF Core)。本文档全面阐述设计引擎的功能与实现机制,重点分析其模块组成、调用关系以及元数据持久化机制。 + +## 项目结构 +设计引擎的项目结构清晰地划分为多个模块,每个模块负责不同的功能。主要模块包括: +- **H.LowCode.DesignEngine**: 包含前端组件和样式文件。 +- **H.LowCode.DesignEngine.Application**: 提供应用服务,处理业务逻辑。 +- **H.LowCode.DesignEngine.Domain**: 封装业务逻辑和领域规则。 +- **H.LowCode.DesignEngine.Repository.JsonFile**: 实现基于JSON文件的元数据持久化。 +- **H.LowCode.DesignEngineBase**: 提供基础服务,如拖拽状态管理。 + +```mermaid +graph TD +subgraph "前端" +ComponentPanel[组件面板] +SettingPanel[设置面板] +end +subgraph "应用层" +AppApplicationService[AppApplicationService] +DataSourceAppService[DataSourceAppService] +MenuAppService[MenuAppService] +PageAppService[PageAppService] +end +subgraph "领域层" +AppDomainService[AppDomainService] +DataSourceDomainService[DataSourceDomainService] +MenuDomainService[MenuDomainService] +PageDomainService[PageDomainService] +end +subgraph "仓库层" +AppFileRepository[AppFileRepository] +DataSourceFileRepository[DataSourceFileRepository] +MenuFileRepository[MenuFileRepository] +PageFileRepository[PageFileRepository] +end +ComponentPanel --> AppApplicationService +SettingPanel --> AppApplicationService +AppApplicationService --> AppDomainService +AppDomainService --> AppFileRepository +DataSourceAppService --> DataSourceDomainService +DataSourceDomainService --> DataSourceFileRepository +MenuAppService --> MenuDomainService +MenuDomainService --> MenuFileRepository +PageAppService --> PageDomainService +PageDomainService --> PageFileRepository +``` + +**图示来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +**本节来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +## 核心组件 +设计引擎的核心组件包括应用服务、领域服务和仓库服务。这些组件协同工作,实现应用、页面、菜单和数据源的CRUD操作。 + +### 应用服务与领域服务的调用关系 +应用服务(AppApplicationService)通过依赖注入获取领域服务(AppDomainService)的实例,并调用其方法来处理业务逻辑。领域服务进一步调用仓库服务(IAppRepository)来持久化数据。 + +```mermaid +sequenceDiagram +participant AppApplicationService as AppApplicationService +participant AppDomainService as AppDomainService +participant AppFileRepository as AppFileRepository +AppApplicationService->>AppDomainService : GetListAsync() +AppDomainService->>AppFileRepository : GetListAsync() +AppFileRepository-->>AppDomainService : 返回应用列表 +AppDomainService-->>AppApplicationService : 返回应用列表 +AppApplicationService->>AppDomainService : SaveAsync(appSchema) +AppDomainService->>AppFileRepository : SaveAsync(appSchema) +AppFileRepository-->>AppDomainService : 保存成功 +AppDomainService-->>AppApplicationService : 保存成功 +``` + +**图示来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +**本节来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) + +## 架构概述 +设计引擎采用典型的分层架构,分为应用层、领域层和仓库层。每一层都有明确的职责,确保系统的可维护性和可扩展性。 + +### 分层架构 +- **应用层**: 提供应用、页面、菜单、数据源的CRUD服务。 +- **领域层**: 封装业务逻辑和领域规则。 +- **仓库层**: 支持多种存储后端,如JsonFile、RemoteService、EF Core。 + +```mermaid +graph TD +A[应用层] --> B[领域层] +B --> C[仓库层] +C --> D[存储后端] +D --> E[Json文件] +D --> F[远程服务] +D --> G[EF Core] +``` + +**图示来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +**本节来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +## 详细组件分析 +### 元数据持久化机制 +设计引擎通过`FileRepositoryBase`类实现元数据的持久化。该类提供了读取和写入JSON文件的基本方法,具体的仓库实现类(如`AppFileRepository`)继承自`FileRepositoryBase`,并实现具体的持久化逻辑。 + +#### FileRepositoryBase +`FileRepositoryBase`是所有文件仓库的基类,负责初始化元数据目录路径,并提供读取文件内容的方法。 + +```csharp +public abstract class FileRepositoryBase +{ + public bool? IsChangeTrackingEnabled { get; set; } + + protected static string _metaBaseDir; + + public FileRepositoryBase(IOptions metaOption) + { + _metaBaseDir = metaOption.Value.AppsFilePath; + IsChangeTrackingEnabled = false; + } + + protected static string ReadAllText(string fileName) + { + if (!File.Exists(fileName)) + throw new FileNotFoundException(fileName); + + return File.ReadAllText(fileName, Encoding.UTF8); + } +} +``` + +**本节来源** +- [FileRepositoryBase.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Base\FileRepositoryBase.cs) + +#### AppFileRepository +`AppFileRepository`实现了`IAppRepository`接口,负责应用元数据的持久化。它将应用元数据保存为JSON文件,并存储在指定的目录中。 + +```csharp +public class AppFileRepository : FileRepositoryBase, IAppRepository +{ + private static string appFileName_Format = @"{0}\{1}\{2}.json"; + + public async Task> GetListAsync() + { + List appSchemas = []; + + if (Directory.Exists(_metaBaseDir) == false) + return appSchemas; + + var directories = Directory.GetDirectories(_metaBaseDir); + foreach (var directory in directories) + { + DirectoryInfo dirInfo = new(directory); + var fileName = string.Format(appFileName_Format, _metaBaseDir, dirInfo.Name, dirInfo.Name); + + if (!File.Exists(fileName)) + continue; + + var appSchemaJson = ReadAllText(fileName); + var appSchema = appSchemaJson.FromJson(); + appSchemas.Add(appSchema); + } + + return await Task.FromResult(appSchemas); + } + + public async Task SaveAsync(AppPartsSchema appSchema) + { + ArgumentNullException.ThrowIfNull(appSchema); + ArgumentException.ThrowIfNullOrEmpty(appSchema.Id); + + appSchema.ModifiedTime = DateTime.UtcNow; + + string fileName = string.Format(appFileName_Format, _metaBaseDir, appSchema.Id, appSchema.Id); + + string fileDirectory = Path.GetDirectoryName(fileName); + if (!Directory.Exists(fileDirectory)) + Directory.CreateDirectory(fileDirectory); + + File.WriteAllText(fileName, appSchema.ToJson(), Encoding.UTF8); + await Task.CompletedTask; + } + + public async Task GetAsync(string appId) + { + string fileName = string.Format(appFileName_Format, _metaBaseDir, appId, appId); + + var appSchemaJson = ReadAllText(fileName); + var appSchema = appSchemaJson.FromJson(); + return await Task.FromResult(appSchema); + } +} +``` + +**本节来源** +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +### 前端实现 +设计引擎的前端实现主要包括组件面板、属性设置面板和拖拽状态管理服务。 + +#### 组件面板 +组件面板通过`DragItem.razor.css`文件定义样式,每个组件项具有固定的宽度和高度,并在鼠标悬停时显示边框和颜色变化。 + +```css +.dragitem { + float: left; + width: 6.8rem; + height: 2.2rem; + margin: 4px; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + color: #333; + background-color: #f5f7fa; +} + +.dragitem:hover { + border: #409eff dashed 1px; + color: #409eff; +} +``` + +**本节来源** +- [DragItem.razor.css](file://src\DesignEngine\H.LowCode.DesignEngine\ComponentPanel\DragItem.razor.css) + +#### 属性设置面板 +属性设置面板通过`PageSetting.razor.css`文件定义样式,每个设置项具有一定的外边距。 + +```css +.pagesetting-item { + margin: 5px 15px 20px 10px; +} +``` + +**本节来源** +- [PageSetting.razor.css](file://src\DesignEngine\H.LowCode.DesignEngine\SettingPanel\PageSetting.razor.css) + +#### 拖拽状态管理服务 +`DragDropStateService`负责管理拖拽过程中的各种状态,包括当前拖拽的组件、最后选中的组件、最后拖拽到的组件等。该服务通过字典存储不同应用和页面的状态,并提供相应的获取和设置方法。 + +```csharp +public class DragDropStateService +{ + private IDictionary schemaStates = new Dictionary(); + + public ComponentPartsSchema GetRootComponent(string appId, string pageId) + { + var stateSchema = GetStateSchema(appId, pageId); + return stateSchema?.RootComponent; + } + + public void SetRootComponent(string appId, string pageId, ComponentPartsSchema rootComponent) + { + SetStateSchema(appId, pageId, (stateSchema) => { + stateSchema.RootComponent = rootComponent; + }); + } + + // 其他方法... +} +``` + +**本节来源** +- [DragDropStateService.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\Services\DragDropStateService.cs) + +### 数据结构分析 +#### ComponentPartsSchema +`ComponentPartsSchema`类定义了组件的元数据结构,包括组件ID、名称、类型、渲染片段、数据源、属性定义分组、子组件等。此外,还包含设计过程中的状态信息,如是否选中、拖拽效果样式等。 + +```csharp +public class ComponentPartsSchema : ComponentSchemaBase +{ + [JsonPropertyName("partsId")] + public string PartsId { get; set; } = ShortIdGenerator.Generate(); + + [JsonPropertyName("libid")] + public string LibraryId { get; set; } + + [JsonPropertyName("cn")] + public string ComponentName { get; set; } + + [JsonPropertyName("ct")] + public int ComponentType { get; set; } + + [JsonPropertyName("frag")] + public ComponentPartsFragmentSchema Fragment { get; set; } + + [JsonPropertyName("ds")] + public ComponentPartsDataSourceSchema DataSource { get; set; } = new(); + + [JsonPropertyName("attrdefgroups")] + public IEnumerable AttributeDefineGroups { get; set; } = []; + + [JsonPropertyName("childs")] + public IList Childrens { get; set; } = []; + + [JsonPropertyName("sptevs")] + public string[] SupportEvents { get; set; } + + [JsonPropertyName("order")] + public int Order { get; set; } + + [JsonPropertyName("pub")] + public int PublishStatus { get; set; } + + [JsonPropertyName("mt")] + public DateTime ModifiedTime { get; set; } + + [JsonIgnore] + public ComponentDesignStateSchema DesignState { get; set; } = new(); + + [JsonIgnore] + public Action Refresh { get; set; } + + public void RefreshState() + { + Refresh?.Invoke(); + } + + // 其他方法... +} +``` + +**本节来源** +- [ComponentPartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\ComponentPartsSchema.cs) + +#### PagePartsSchema +`PagePartsSchema`类定义了页面的元数据结构,包括组件列表和支持的事件。 + +```csharp +public class PagePartsSchema : PageSchemaBase +{ + [JsonPropertyName("comps")] + public IList Components { get; set; } = []; + + [JsonPropertyName("sptevs")] + public string[] SupportEvents { get; } = ["OnLoad"]; +} +``` + +**本节来源** +- [PagePartsSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PagePartsSchema.cs) + +#### ComponentDesignStateSchema +`ComponentDesignStateSchema`类定义了组件在设计过程中的状态,这些状态信息无需持久化存储。 + +```csharp +public class ComponentDesignStateSchema +{ + [JsonIgnore] + public bool IsSelected { get; set; } + + [JsonIgnore] + public string DragEffectStyle { get; set; } + + [JsonIgnore] + public bool IsDroppedFromComponentPanel { get; set; } + + [JsonIgnore] + public string AnimationTransform { get; set; } = string.Empty; + + [JsonIgnore] + public bool IsAnimating { get; set; } +} +``` + +**本节来源** +- [ComponentDesignStateSchema.cs](file://src\Common\H.LowCode.MetaSchema.DesignEngine\PropertySchemas\ComponentDesignStateSchema.cs) + +## 依赖关系分析 +设计引擎的各个组件之间存在明确的依赖关系。应用服务依赖于领域服务,领域服务依赖于仓库服务,仓库服务依赖于具体的存储后端。 + +```mermaid +graph TD +A[AppApplicationService] --> B[AppDomainService] +B --> C[AppFileRepository] +C --> D[Json文件] +E[DataSourceAppService] --> F[DataSourceDomainService] +F --> G[DataSourceFileRepository] +G --> D +H[MenuAppService] --> I[MenuDomainService] +I --> J[MenuFileRepository] +J --> D +K[PageAppService] --> L[PageDomainService] +L --> M[PageFileRepository] +M --> D +``` + +**图示来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +**本节来源** +- [AppApplicationService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\AppApplicationService.cs) +- [AppDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\AppDomainService.cs) +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) + +## 性能考量 +设计引擎在处理大量元数据时,应考虑以下性能优化措施: +- 使用缓存机制减少对文件系统的频繁读写。 +- 优化JSON序列化和反序列化的性能。 +- 在前端实现中,使用虚拟滚动技术提高组件面板的渲染性能。 + +## 故障排除指南 +### 常见问题 +- **元数据无法保存**: 检查文件路径是否正确,确保目录存在且有写权限。 +- **组件拖拽失效**: 检查`DragDropStateService`是否正确初始化,确保状态管理正常。 +- **样式不生效**: 检查CSS文件是否正确引用,确保样式规则没有被覆盖。 + +### 调试建议 +- 使用日志记录关键操作,如保存元数据、加载应用等。 +- 在开发环境中启用详细的错误信息,便于定位问题。 + +**本节来源** +- [AppFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\AppFileRepository.cs) +- [DragDropStateService.cs](file://src\DesignEngine\H.LowCode.DesignEngineBase\Services\DragDropStateService.cs) + +## 结论 +设计引擎通过分层架构和模块化设计,实现了低代码平台的可视化开发功能。应用服务、领域服务和仓库服务的协同工作,确保了元数据的高效管理和持久化。前端组件面板和属性设置面板的实现,提供了直观的用户界面。拖拽状态管理服务则保证了拖拽操作的流畅性和状态的一致性。通过合理的性能优化和故障排除措施,设计引擎能够稳定高效地支持低代码应用的开发。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\351\242\206\345\237\237\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\351\242\206\345\237\237\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..7bb4119f2caaf815a813b34d7d0c2a5c39a034e1 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\345\272\224\347\224\250\351\242\206\345\237\237\346\234\215\345\212\241.md" @@ -0,0 +1,264 @@ +# 应用领域服务 + + +**本文档引用文件** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IAppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [SupportPlatformEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/SupportPlatformEnum.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) + + +## 目录 +1. [项目结构](#项目结构) +2. [核心组件](#核心组件) +3. [架构概览](#架构概览) +4. [详细组件分析](#详细组件分析) +5. [依赖分析](#依赖分析) +6. [性能考量](#性能考量) +7. [最佳实践与优化建议](#最佳实践与优化建议) + +## 项目结构 + +本项目采用模块化分层架构,主要分为 `Common`、`DesignEngine` 和 `RenderEngine` 三大模块。`Common` 模块存放共享的元数据模型和基础组件;`DesignEngine` 负责应用的设计时功能,包含领域服务、应用服务和基于 JSON 文件的元数据持久化;`RenderEngine` 则负责运行时渲染逻辑。 + +应用元数据(如应用、页面、菜单)以 JSON 文件形式存储在 `meta/apps` 目录下,每个应用一个子目录,其核心配置文件与应用ID同名。设计引擎通过 `AppFileRepository` 实现对这些文件的读写操作。 + +```mermaid +graph TB +subgraph "设计引擎 DesignEngine" +subgraph "领域层 Domain" +AppDomainService["应用领域服务
AppDomainService"] +IAppDomainService["应用领域服务接口
IAppDomainService"] +end +subgraph "应用层 Application" +AppApplicationService["应用应用服务
AppApplicationService"] +IAppApplicationService["应用应用服务接口
IAppApplicationService"] +end +subgraph "仓储层 Repository" +AppFileRepository["应用文件仓储
AppFileRepository"] +IAppRepository["应用仓储接口
IAppRepository"] +end +AppDomainService --> AppFileRepository : "依赖" +AppApplicationService --> AppDomainService : "调用" +end +subgraph "公共模块 Common" +AppSchemaBase["应用元数据基类
AppSchemaBase"] +AppPartsSchema["应用部件元数据
AppPartsSchema"] +PublishStatusEnum["发布状态枚举
PublishStatusEnum"] +SupportPlatformEnum["支持平台枚举
SupportPlatformEnum"] +end +AppPartsSchema --> AppSchemaBase : "继承" +AppFileRepository --> AppPartsSchema : "读写" +AppDomainService --> AppPartsSchema : "操作" +``` + +**图示来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) + +## 核心组件 + +`AppDomainService` 是低代码平台中负责应用生命周期管理的核心领域服务。它遵循领域驱动设计(DDD)原则,封装了与应用聚合根相关的所有业务逻辑和规则。该服务不直接处理持久化,而是通过依赖倒置,将数据访问操作委托给 `IAppRepository` 接口,从而实现了业务逻辑与数据存储的解耦。 + +其主要职责包括: +- **应用元数据的获取**:提供异步方法获取所有应用列表或根据ID获取单个应用。 +- **应用元数据的保存**:协调应用聚合根的持久化操作。 +- **业务规则的执行**:虽然当前实现较为简单,但其设计为未来扩展复杂的业务校验逻辑(如唯一性检查、状态流转)提供了清晰的入口。 + +**本节来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IAppDomainService.cs) + +## 架构概览 + +系统采用典型的分层架构,从上至下分为应用服务层、领域服务层和仓储层。 + +1. **应用服务层 (Application Layer)**:`AppApplicationService` 作为应用服务,是外部(如前端API)的直接调用入口。它负责处理应用服务契约、数据传输对象(DTO)的转换,并协调领域服务的调用。 +2. **领域服务层 (Domain Layer)**:`AppDomainService` 作为领域服务,是业务逻辑的核心。它专注于应用聚合根的业务规则和状态管理,确保数据的一致性和完整性。 +3. **仓储层 (Repository Layer)**:`AppFileRepository` 实现了 `IAppRepository` 接口,负责将 `AppPartsSchema` 对象持久化到文件系统(JSON文件)或从文件系统中读取。它隐藏了底层存储的细节。 + +这种分层确保了关注点分离,使得业务逻辑清晰、可测试且易于维护。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AppAppService as "AppApplicationService" +participant AppDomainService as "AppDomainService" +participant AppRepository as "AppFileRepository" +Client->>AppAppService : SaveAsync(appSchema) +AppAppService->>AppAppService : 参数校验 (null, Id) +AppAppService->>AppDomainService : SaveAsync(appSchema) +AppDomainService->>AppRepository : SaveAsync(appSchema) +AppRepository->>AppRepository : 设置ModifiedTime +AppRepository->>AppRepository : 序列化为JSON +AppRepository->>AppRepository : 写入文件系统 +AppRepository-->>AppDomainService : 完成 +AppDomainService-->>AppAppService : 完成 +AppAppService-->>Client : 返回true +``` + +**图示来源** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +## 详细组件分析 + +### 应用领域服务 (AppDomainService) 分析 + +`AppDomainService` 的实现简洁而符合DDD规范。它通过构造函数注入 `IAppRepository`,体现了依赖注入和依赖倒置原则。 + +#### 类图 +```mermaid +classDiagram +class AppDomainService { +-IAppRepository _repository ++AppDomainService(IAppRepository repository) ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(string appId) Task~AppPartsSchema~ ++SaveAsync(AppPartsSchema appSchema) Task +} +class IAppDomainService { +<> ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(string appId) Task~AppPartsSchema~ ++SaveAsync(AppPartsSchema appSchema) Task +} +class AppPartsSchema { ++string Id ++string Name ++string Icon ++string Picture ++string Description ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class AppSchemaBase { +<> ++string Id ++string Name ++string Icon ++string Picture ++string Description ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class PublishStatusEnum { +Development +Approving +Published +} +class SupportPlatformEnum { +Web +Mobile +WXMiniApp +} +AppDomainService --> IAppRepository : "依赖" +AppDomainService --> AppPartsSchema : "操作" +AppPartsSchema --> AppSchemaBase : "继承" +AppPartsSchema --> PublishStatusEnum : "引用" +AppPartsSchema --> SupportPlatformEnum : "引用" +AppDomainService ..|> IAppDomainService : "实现" +``` + +**图示来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IAppDomainService.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [SupportPlatformEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/SupportPlatformEnum.cs) + +#### 业务规则校验逻辑 + +根据当前代码分析,`AppDomainService` 本身并未实现复杂的业务规则校验。其 `SaveAsync` 方法直接委托给仓储层。然而,**业务规则的校验点主要位于其上层调用者 `AppApplicationService`**: + +1. **参数校验**:在 `AppApplicationService.SaveAsync` 方法中,明确调用了 `ArgumentNullException.ThrowIfNull(appSchema)` 和 `ArgumentException.ThrowIfNullOrEmpty(appSchema.Id)`,确保了传入的应用元数据对象及其ID不为空。这是最基础的输入验证。 +2. **元数据完整性**:由于 `AppPartsSchema` 继承自 `AppSchemaBase`,其核心属性(如 `Id`, `Name`, `PublishStatus`)在反序列化时会由JSON框架处理。若JSON中缺少这些字段,反序列化可能失败或使用默认值,这构成了隐式的完整性检查。 +3. **状态流转控制**:`PublishStatusEnum` 定义了 `Development`、`Approving`、`Published` 三种状态,为状态流转提供了数据基础。但当前代码中并未实现状态变更的业务规则(例如,不能从 `Published` 直接变更为 `Development`),这部分逻辑需要在 `AppDomainService` 或 `AppApplicationService` 中补充。 +4. **应用标识唯一性**:当前的 `AppFileRepository` 在保存时,会根据 `appSchema.Id` 确定文件路径。如果存在同名文件,新内容会直接覆盖旧文件。这表明**系统目前没有强制执行应用ID的唯一性检查**。要实现唯一性,需要在 `SaveAsync` 过程中,先查询所有应用,检查ID是否已存在。 + +#### 聚合根构建与持久化 + +- **聚合根构建**:`AppPartsSchema` 类本身非常简单,仅继承了 `AppSchemaBase`。真正的应用聚合根实例是通过从JSON文件反序列化 `AppPartsSchema` 对象来构建的。这个过程由 `AppFileRepository.GetAsync` 完成。 +- **持久化操作**:`AppDomainService` 通过调用 `IAppRepository.SaveAsync(AppPartsSchema appSchema)` 来实现持久化。`AppFileRepository` 的实现会: + 1. 验证 `appSchema` 和 `Id` 不为空。 + 2. 更新 `ModifiedTime` 为当前UTC时间。 + 3. 根据 `Id` 确定文件路径(格式为 `{metaBaseDir}/{appId}/{appId}.json`)。 + 4. 确保目录存在,然后将对象序列化为JSON字符串并写入文件。 + +#### 异常处理与事务边界 + +- **异常处理**:当前代码的异常处理较为基础。`AppApplicationService` 处理了空值参数,而 `AppFileRepository` 在文件操作时可能抛出 `IOException` 等,但未在 `AppDomainService` 或 `AppApplicationService` 中显式捕获和处理。建议在 `AppDomainService` 中捕获仓储层异常,并根据情况抛出更具体的领域异常(如 `AppSaveFailedException`)。 +- **事务边界**:由于应用元数据是独立的JSON文件,且 `AppDomainService` 只操作单个 `AppPartsSchema`,因此其 `SaveAsync` 方法的事务边界就是单个文件的写入操作。文件系统的原子性(写入成功或失败)保证了单个应用数据的最终一致性。对于跨聚合(如应用、页面、菜单)的一致性维护,当前设计未体现,需要更高级的协调机制。 + +**本节来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) + +## 依赖分析 + +`AppDomainService` 的依赖关系清晰,体现了松耦合的设计。 + +```mermaid +graph TD +AppDomainService --> IAppRepository : "依赖接口" +IAppRepository --> AppFileRepository : "具体实现" +AppFileRepository --> FileRepositoryBase : "继承" +AppFileRepository --> AppPartsSchema : "操作数据" +AppPartsSchema --> AppSchemaBase : "继承" +AppSchemaBase --> PublishStatusEnum : "引用" +AppSchemaBase --> SupportPlatformEnum : "引用" +AppApplicationService --> AppDomainService : "调用服务" +``` + +**图示来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) + +## 性能考量 + +- **读取性能**:`GetListAsync` 方法会扫描 `meta/apps` 目录下的所有子目录,并为每个目录读取一个JSON文件。当应用数量庞大时,这可能导致性能瓶颈。优化方案包括引入缓存机制,或维护一个应用列表的索引文件。 +- **写入性能**:`SaveAsync` 操作是单个文件的IO操作,性能取决于磁盘速度。由于是直接覆盖写入,不存在复杂的事务开销,性能较好。 +- **序列化开销**:每次读写都需要进行JSON的序列化和反序列化,对于大型应用配置,这会带来一定的CPU开销。 + +## 最佳实践与优化建议 + +1. **增强业务规则校验**:在 `AppDomainService` 中实现完整的业务规则,例如: + ```csharp + public async Task SaveAsync(AppPartsSchema appSchema) + { + // 检查ID唯一性(排除自身) + var existingApps = await _repository.GetListAsync(); + var existingApp = existingApps.FirstOrDefault(a => a.Id == appSchema.Id && a.Id != appSchema.Id); + if (existingApp != null) + { + throw new BusinessException("应用ID已存在"); + } + + // 检查状态流转合法性 + if (appSchema.PublishStatus == PublishStatusEnum.Development && + appSchema.PreviousStatus == PublishStatusEnum.Published) + { + throw new BusinessException("已发布应用不能直接变更为开发中"); + } + + await _repository.SaveAsync(appSchema); + } + ``` +2. **引入缓存**:为 `GetListAsync` 和 `GetAsync` 方法添加内存缓存(如 `IMemoryCache`),显著提升读取性能。 +3. **完善异常处理**:在 `AppDomainService` 中捕获 `IAppRepository` 抛出的底层异常,并将其转换为领域特定的业务异常,便于上层服务进行统一处理。 +4. **考虑最终一致性**:如果未来需要维护应用与页面、菜单等实体的一致性,可以考虑使用领域事件(Domain Events)模式。当应用状态变更时,发布一个事件,由其他服务监听并更新关联实体。 +5. **优化文件结构**:对于大型应用,可以考虑将应用元数据拆分为多个文件(如 `app.json`, `pages.json`, `menus.json`),以提高读写效率和可维护性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\346\225\260\346\215\256\346\272\220\351\242\206\345\237\237\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\346\225\260\346\215\256\346\272\220\351\242\206\345\237\237\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..f1cb6a149b9b40d15a0901c68a752c30874045e9 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\346\225\260\346\215\256\346\272\220\351\242\206\345\237\237\346\234\215\345\212\241.md" @@ -0,0 +1,302 @@ +# 数据源领域服务 + + +**本文档引用的文件** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IDataSourceDomainService.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) +- [StateHasChangeSchema.cs](file://src/Common/H.LowCode.MetaSchema/StateHasChangeSchema.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 + +本文档深入剖析了低代码平台中 `DataSourceDomainService` 对各类数据源(API、SQL、静态选项等)的统一管理机制。通过分析其领域服务实现、数据源抽象建模、持久化机制及缓存策略,全面阐述了系统在数据源创建、验证、测试连接、依赖管理及安全性保障方面的设计与实现。 + +## 项目结构 + +本项目采用分层架构,主要分为 `Common`(通用组件与元数据模型)、`DesignEngine`(设计时核心逻辑)、`RenderEngine`(运行时渲染逻辑)和 `Tools`(工具模块)。数据源管理的核心逻辑位于 `DesignEngine` 的 `Domain` 层,其元数据模型定义在 `Common` 层,持久化实现则位于 `Repository.JsonFile` 模块。 + +```mermaid +graph TB +subgraph "Common" +MetaSchema[MetaSchema] +Entity[Entity] +end +subgraph "DesignEngine" +Domain[Domain] +Repository[Repository] +Application[Application] +end +subgraph "RenderEngine" +RenderDomain[Domain] +RenderRepository[Repository] +end +MetaSchema --> Domain +Domain --> Repository +Repository --> JsonFile[JsonFile Repository] +``` + +**图示来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 核心组件 + +`DataSourceDomainService` 是数据源管理的核心领域服务,它通过 `IDataSourceRepository` 接口与底层持久化机制解耦,实现了对应用内所有数据源的增删改查(CRUD)操作。该服务定义了获取所有数据源列表、按类型筛选(如仅API)、获取单个数据源、保存和删除数据源等核心方法。 + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IDataSourceDomainService.cs) + +## 架构概览 + +系统采用领域驱动设计(DDD)模式,将数据源管理的业务逻辑封装在 `Domain` 层。`DataSourceDomainService` 作为领域服务,协调 `DataSourceSchema` 领域对象和 `IDataSourceRepository` 仓储接口。持久化实现 `DataSourceFileRepository` 将数据源元数据以 JSON 文件的形式存储在文件系统中,实现了轻量级的配置管理。 + +```mermaid +classDiagram +class DataSourceDomainService { ++GetListAsync(appId) Task~IList~ ++GetAllApisAsync(appId) Task~IList~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +class IDataSourceDomainService { +<> ++GetListAsync(appId) Task~IList~ ++GetAllApisAsync(appId) Task~IList~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +class DataSourceSchema { ++AppId string ++Id string ++Name string ++DisplayName string ++DataSourceType ComponentDataSourceTypeEnum ++TableFields IList~TableFieldSchema~ ++API APIDataSourceSchema ++Options OptionDataSourceSchema[] ++Values IDictionary~string, string~ ++SQLOptionDataSource SQLDataSourceSchema ++APIOptionDataSource APIDataSourceSchema +} +class IDataSourceRepository { +<> ++GetListAsync(appId) Task~IList~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +class DataSourceFileRepository { ++GetListAsync(appId) Task~IList~ ++GetAsync(appId, id) Task~DataSourceSchema~ ++SaveAsync(appId, dataSourceSchema) Task ++DeleteAsync(appId, id) Task +} +DataSourceDomainService --> IDataSourceRepository : "依赖" +DataSourceDomainService ..> IDataSourceDomainService : "实现" +DataSourceFileRepository ..> IDataSourceRepository : "实现" +``` + +**图示来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IDataSourceDomainService.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) + +## 详细组件分析 + +### 数据源抽象建模 + +系统通过 `DataSourceSchema` 基类对不同类型的数据源进行统一建模。该类使用 `DataSourceType` 枚举区分数据源类型,并通过属性聚合的方式包含不同类型数据源的具体配置。 + +#### 数据源类型与结构 + +```mermaid +classDiagram +class DataSourceSchema { ++DataSourceType ComponentDataSourceTypeEnum +} +class APIDataSourceSchema { ++Domain string ++Path string ++Method string ++Queries IList~APIParamSchema~ ++Body APIBodySchema ++Headers IList~APIParamSchema~ +} +class SQLDataSourceSchema { ++DbType string ++Sql string +} +class OptionDataSourceSchema { ++Id string ++Label string ++Value string +} +class TableFieldSchema { ++Name string ++Type string ++IsPrimaryKey bool +} +DataSourceSchema --> APIDataSourceSchema : "API" +DataSourceSchema --> SQLDataSourceSchema : "SQLOptionDataSource" +DataSourceSchema --> OptionDataSourceSchema : "Options" +DataSourceSchema --> TableFieldSchema : "TableFields" +``` + +**图示来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs) + +**本节来源** +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) +- [OptionDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs) + +### 统一管理机制 + +`DataSourceDomainService` 通过统一的接口方法管理所有数据源。例如,`GetListAsync` 方法从仓库获取应用内所有数据源,而 `GetAllApisAsync` 则在此基础上通过 LINQ 筛选出类型为 `API` 的数据源。 + +```csharp +public async Task> GetAllApisAsync(string appId) +{ + var list = await GetListAsync(appId); + return list.Where(t => t.DataSourceType == ComponentDataSourceTypeEnum.API).ToList(); +} +``` + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs#L15-L20) + +### 连接验证与参数校验 + +虽然在 `DataSourceDomainService` 中未直接实现复杂的连接验证逻辑,但其依赖的 `IDataSourceRepository` 和上层应用服务(如 `DataSourceAppService`)会负责具体的验证。参数校验主要通过数据传输对象(DTO)的属性注解(如 `[JsonRequired]`)在应用层完成。 + +**本节来源** +- [DataSourceInput.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/Inputs/DataSourceInput.cs#L7) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) + +### 安全性检查流程 + +#### SQL注入防护 +系统通过在 EF Core 查询拦截器 `QueryWithNoLockDbCommandInterceptor` 中修改 SQL 命令,为所有 `FROM` 和 `JOIN` 子句添加 `WITH (NOLOCK)` 提示。虽然这主要是为了提高查询性能,但其通过正则表达式操作 SQL 文本的方式,也间接要求开发者避免在 SQL 字符串中直接拼接用户输入,从而降低了 SQL 注入风险。真正的 SQL 注入防护应依赖于参数化查询,这在 EF Core 的正常使用中是默认启用的。 + +#### API超时设置 +在当前分析的代码中,未直接发现 API 超时设置的配置。此类设置通常在 HTTP 客户端(如 `HttpClient`)的配置或 API 调用的具体实现中进行。 + +#### 认证信息加密存储 +在 `APIDataSourceSchema` 的定义中,认证信息(如 API 密钥、Token)通常会作为 `Headers` 或 `Queries` 的一部分进行配置。然而,代码中并未显示对这些敏感信息进行加密存储的逻辑。理想情况下,敏感信息应加密后存储,或通过密钥管理服务(KMS)进行引用。 + +**本节来源** +- [QueryWithNoLockDbCommandInterceptor.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/QueryWithNoLockDbCommandInterceptor.cs#L25-L33) +- [APIDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs#L15-L17) + +### 测试连接功能与缓存失效 + +#### 测试连接实现 +测试连接功能通常由上层应用服务(`DataSourceAppService`)调用 `DataSourceDomainService` 获取数据源配置后,根据 `DataSourceType` 实例化相应的客户端(如 `HttpClient` 用于 API,`DbConnection` 用于数据库)并执行一个轻量级的连接操作(如发送一个空请求或执行 `SELECT 1`)来实现。`DataSourceDomainService` 本身不直接处理测试逻辑。 + +#### 元数据更新与缓存失效 +当数据源被保存(`SaveAsync`)时,`DataSourceFileRepository` 会更新对应的 JSON 文件。为了通知系统元数据已变更,系统使用了 `StateHasChangeSchema` 基类。该基类包含一个 `StateKey` 属性和一个 `ChangeStateKey()` 方法。每当元数据发生变更时,调用 `ChangeStateKey()` 会生成一个新的唯一键。上层组件(如页面渲染器)可以监听此 `StateKey` 的变化,一旦检测到变化,即可触发缓存失效和重新加载元数据的逻辑,确保用户界面与最新配置保持同步。 + +```csharp +// 在保存数据源时,会更新 ModifiedTime,但 ChangeStateKey 可能由上层调用 +dataSourceSchema.ModifiedTime = DateTime.UtcNow; +``` + +**本节来源** +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs#L55) +- [StateHasChangeSchema.cs](file://src/Common/H.LowCode.MetaSchema/StateHasChangeSchema.cs#L6-L10) + +### 依赖分析、引用计数与级联删除 + +#### 依赖分析与引用计数 +当前代码分析中,未发现显式的依赖分析或引用计数管理机制。`DataSourceDomainService` 的 `DeleteAsync` 方法直接删除数据源,没有检查是否有其他组件(如页面、组件)正在引用该数据源。 + +#### 级联删除规则 +目前的删除逻辑是直接的,不包含级联删除。如果一个数据源被其他元数据(如页面配置)所引用,直接删除该数据源会导致引用失效,可能引发运行时错误。一个健壮的系统应在删除前进行依赖检查,或提供级联删除选项。 + +```csharp +public async Task DeleteAsync(string appId, string id) +{ + string fileName = string.Format(dataSourceName_Format, _metaBaseDir, appId, id); + if (!File.Exists(fileName)) + return; + File.Delete(fileName); + await Task.CompletedTask; +} +``` + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs#L35-L39) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs#L70-L79) + +## 依赖分析 + +`DataSourceDomainService` 的核心依赖关系清晰。它直接依赖于 `IDataSourceRepository` 接口,实现了业务逻辑与数据访问的解耦。`DataSourceSchema` 类作为领域对象,被 `DataSourceDomainService` 和 `DataSourceFileRepository` 共同使用。`DataSourceFileRepository` 依赖于 `MetaOption` 配置来确定元数据的存储路径。 + +```mermaid +graph TD +A[DataSourceDomainService] --> B[IDataSourceRepository] +B --> C[DataSourceFileRepository] +C --> D[MetaOption] +A --> E[DataSourceSchema] +C --> E +``` + +**图示来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs#L7) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs#L12) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) + +## 性能考量 + +- **持久化性能**:使用文件系统存储元数据简单轻量,但在高并发读写场景下,文件 I/O 可能成为瓶颈。`DataSourceFileRepository` 的 `GetListAsync` 方法会遍历目录下所有文件,当数据源数量庞大时,性能会线性下降。 +- **内存使用**:每次读取数据源都会反序列化整个 JSON 文件,对于大型数据源,可能会占用较多内存。 +- **缓存策略**:当前设计依赖 `StateKey` 触发缓存失效,但缺乏主动的内存缓存机制。频繁读取数据源列表可能会导致重复的文件读取和反序列化操作。 + +## 故障排除指南 + +- **数据源无法保存**:检查 `MetaOption` 配置的 `_metaBaseDir` 路径是否正确,以及应用是否有对该目录的读写权限。 +- **数据源列表为空**:确认 `appId` 是否正确,以及对应的 `datasource` 目录下是否存在 `.json` 文件。 +- **测试连接失败**:检查数据源配置(如 API 的域名、路径、认证头)是否正确,网络是否通畅,数据库连接字符串是否有效。 +- **删除数据源后功能异常**:可能是因为有页面或组件仍在引用已删除的数据源。建议在删除前先进行依赖检查。 + +**本节来源** +- [DataSourceFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) + +## 结论 + +`DataSourceDomainService` 通过领域驱动设计,为低代码平台提供了统一的数据源管理能力。其通过抽象的 `DataSourceSchema` 模型和 `IDataSourceRepository` 接口,实现了对 API、SQL、静态选项等多种数据源的灵活支持。系统采用文件存储作为持久化方案,简单易用。在安全性方面,虽有基础防护,但对敏感信息的加密存储有待加强。缓存失效机制通过 `StateKey` 变更实现,有效保证了元数据的一致性。然而,系统在依赖分析、引用计数和级联删除方面存在不足,直接删除被引用的数据源可能导致系统不稳定。未来可考虑引入数据库存储、增强安全加密、实现依赖检查和提供更完善的缓存策略来进一步提升系统的健壮性和性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\350\217\234\345\215\225\351\242\206\345\237\237\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\350\217\234\345\215\225\351\242\206\345\237\237\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..548ed3e090ee9e44e8e592b51167bd4b28e7fb77 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\350\217\234\345\215\225\351\242\206\345\237\237\346\234\215\345\212\241.md" @@ -0,0 +1,234 @@ +# 菜单领域服务 + + +**本文档中引用的文件** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [IMenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IMenuDomainService.cs) +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [IMenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application.Contracts\AppServices\IMenuAppService.cs) +- [IMenuRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaRepositories\IMenuRepository.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档系统性阐述了`MenuDomainService`在菜单层级结构管理中的实现机制。重点解析了菜单项的树形结构维护、父子节点关系约束、排序规则和路径生成算法。详细说明了菜单创建、移动、删除操作中的业务校验逻辑,包括循环引用检测、层级深度限制和权限关联验证。描述了菜单与应用、页面之间的绑定关系管理,以及如何确保导航结构的一致性与完整性。结合代码实例展示了递归遍历、批量更新和缓存同步的实现策略。提供了菜单数据加载性能优化建议和常见操作异常的处理方案,为上层服务调用提供可靠支撑。 + +## 项目结构 +本项目采用分层架构设计,将菜单管理功能分布在多个模块中。核心的菜单领域服务位于`src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices`目录下,其数据模型定义在`src\Common\H.LowCode.MetaSchema`中。数据持久化通过`src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories`中的文件存储库实现。应用服务层则通过`src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices`对外提供API接口。 + +```mermaid +graph TB +subgraph "应用服务层" +MenuAppService["菜单应用服务
MenuAppService"] +end +subgraph "领域服务层" +MenuDomainService["菜单领域服务
MenuDomainService"] +end +subgraph "数据访问层" +MenuRepository["菜单存储库
IMenuRepository"] +MenuFileRepository["文件存储库实现
MenuFileRepository"] +end +subgraph "数据模型" +MenuSchema["菜单数据模型
MenuSchema"] +end +MenuAppService --> MenuDomainService +MenuDomainService --> MenuRepository +MenuFileRepository --> MenuRepository +MenuSchema --> MenuDomainService +MenuSchema --> MenuFileRepository +``` + +**图示来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +**本节来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +## 核心组件 +菜单管理的核心组件包括`MenuSchema`数据模型、`MenuDomainService`领域服务、`MenuFileRepository`存储库实现以及`MenuAppService`应用服务。这些组件共同协作,实现了菜单的全生命周期管理。 + +`MenuSchema`类定义了菜单项的所有属性,包括ID、父ID、标题、类型、图标、路径和排序号。`MenuDomainService`作为领域服务,封装了所有业务逻辑,确保操作的原子性和一致性。`MenuFileRepository`负责将菜单数据持久化到JSON文件中。`MenuAppService`则作为外部接口,为前端或其他服务提供调用入口。 + +**本节来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) + +## 架构概述 +菜单管理系统的架构遵循领域驱动设计(DDD)原则,分为应用层、领域层和基础设施层。应用层负责处理HTTP请求和响应;领域层包含核心业务逻辑和领域模型;基础设施层负责数据持久化。 + +```mermaid +graph TD +A["前端/客户端"] --> B["菜单应用服务
MenuAppService"] +B --> C["菜单领域服务
MenuDomainService"] +C --> D["菜单存储库接口
IMenuRepository"] +D --> E["文件存储库实现
MenuFileRepository"] +E --> F["JSON文件系统"] +C --> G["菜单数据模型
MenuSchema"] +``` + +**图示来源** +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [IMenuRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaRepositories\IMenuRepository.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) + +## 详细组件分析 + +### 菜单数据模型分析 +`MenuSchema`类是菜单系统的核心数据结构,定义了菜单项的所有属性和关系。 + +```mermaid +classDiagram +class MenuSchema { ++string AppId ++string Id ++string ParentId ++string Title ++int MenuType ++string Icon ++string MenuUrl ++int Order ++IList~MenuSchema~ Childrens +} +``` + +**图示来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) + +**本节来源** +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) + +### 菜单领域服务分析 +`MenuDomainService`实现了菜单管理的核心业务逻辑,通过依赖注入获取`IMenuRepository`来执行数据操作。 + +```mermaid +sequenceDiagram +participant AppService as 菜单应用服务 +participant DomainService as 菜单领域服务 +participant Repository as 菜单存储库 +AppService->>DomainService : GetListAsync(appId) +DomainService->>Repository : GetListAsync(appId) +Repository-->>DomainService : 返回菜单列表 +DomainService-->>AppService : 返回菜单列表 +AppService->>DomainService : SaveAsync(menuSchema) +DomainService->>Repository : SaveAsync(menuSchema) +Repository-->>DomainService : 完成 +DomainService-->>AppService : 完成 +AppService->>DomainService : DeleteAsync(appId, menuId) +DomainService->>Repository : DeleteAsync(appId, menuId) +Repository-->>DomainService : 完成 +DomainService-->>AppService : 完成 +``` + +**图示来源** +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [IMenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IMenuDomainService.cs) +- [IMenuRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaRepositories\IMenuRepository.cs) + +**本节来源** +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) + +### 菜单存储库分析 +`MenuFileRepository`实现了基于文件系统的菜单数据持久化,将每个菜单项保存为独立的JSON文件。 + +```mermaid +flowchart TD +Start([获取菜单列表]) --> CheckDir["检查菜单目录是否存在"] +CheckDir --> |不存在| ReturnEmpty["返回空列表"] +CheckDir --> |存在| ReadFiles["读取所有JSON文件"] +ReadFiles --> ParseJson["解析JSON为MenuSchema对象"] +ParseJson --> BuildTree["构建树形结构"] +BuildTree --> SortRoot["根节点按Order排序"] +SortRoot --> ReturnList["返回树形菜单列表"] +StartSave([保存菜单]) --> Validate["验证参数"] +Validate --> SetTime["设置修改时间"] +Validate --> CreateDir["创建目录如不存在"] +CreateDir --> WriteFile["写入JSON文件"] +WriteFile --> Complete["完成"] +StartDelete([删除菜单]) --> CheckFile["检查文件是否存在"] +CheckFile --> |不存在| Return[返回] +CheckFile --> |存在| CheckChildren["检查是否存在子节点"] +CheckChildren --> |存在| ThrowError["抛出异常:存在子节点"] +CheckChildren --> |不存在| DeleteFile["删除文件"] +DeleteFile --> CompleteDelete["完成"] +``` + +**图示来源** +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +**本节来源** +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +## 依赖分析 +菜单管理系统各组件之间的依赖关系清晰明确,遵循依赖倒置原则。高层模块依赖于抽象接口,而非具体实现。 + +```mermaid +graph TD +MenuAppService --> IMenuDomainService +MenuDomainService --> IMenuRepository +MenuFileRepository --> IMenuRepository +MenuDomainService --> MenuSchema +MenuFileRepository --> MenuSchema +``` + +**图示来源** +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [IMenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IMenuDomainService.cs) +- [IMenuRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaRepositories\IMenuRepository.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) +- [MenuSchema.cs](file://src\Common\H.LowCode.MetaSchema\MenuSchema.cs) + +**本节来源** +- [MenuAppService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Application\AppServices\MenuAppService.cs) +- [MenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\MenuDomainService.cs) +- [IMenuDomainService.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaDomainServices\IMenuDomainService.cs) +- [IMenuRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Domain\MetaRepositories\IMenuRepository.cs) +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +## 性能考虑 +菜单数据的加载性能主要受文件I/O操作影响。`MenuFileRepository`在加载菜单列表时,会读取应用目录下所有菜单JSON文件,然后在内存中构建树形结构。对于菜单数量较多的应用,这可能导致性能瓶颈。 + +优化建议: +1. 实现缓存机制,避免重复读取文件系统 +2. 考虑将所有菜单数据存储在单个文件中,减少文件打开关闭开销 +3. 实现懒加载,只在需要时加载子菜单 +4. 使用更高效的数据存储方式,如数据库 + +**本节来源** +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs) + +## 故障排除指南 +### 菜单删除失败 +当尝试删除一个仍有子节点的菜单时,系统会抛出`InvalidOperationException`异常,提示"存在子节点, 不允许删除!"。解决方法是先删除所有子节点,再删除父节点。 + +### 父节点引用错误 +在构建树形结构时,如果发现某个菜单项的`ParentId`在菜单列表中找不到对应的父节点,系统会抛出`KeyNotFoundException`异常。这通常发生在数据不一致或文件损坏的情况下。 + +### 文件路径错误 +确保`MetaOption`配置中的基础目录路径正确,否则可能导致无法找到菜单文件或无法创建目录。 + +**本节来源** +- [MenuFileRepository.cs](file://src\DesignEngine\H.LowCode.DesignEngine.Repository.JsonFile\Repositories\MenuFileRepository.cs#L76-L129) + +## 结论 +`MenuDomainService`通过清晰的分层架构和职责分离,有效地管理了菜单的层级结构。系统实现了基本的树形结构维护、父子节点关系约束和排序功能。然而,在性能优化、循环引用检测和层级深度限制方面还有改进空间。当前的文件存储方案适合小型应用,但对于大型应用可能需要考虑更高效的存储和缓存策略。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\351\241\265\351\235\242\351\242\206\345\237\237\346\234\215\345\212\241.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\351\241\265\351\235\242\351\242\206\345\237\237\346\234\215\345\212\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..27fc5ad139ab3b0cb26d41d5da9bce2c94c890ab --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\351\241\265\351\235\242\351\242\206\345\237\237\346\234\215\345\212\241.md" @@ -0,0 +1,283 @@ +# 页面领域服务 + + +**本文档引用的文件** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [IPageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IPageDomainService.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) +- [ComponentPartsDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/DataSourceSchemas/ComponentPartsDataSourceSchema.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档全面分析了低代码平台中的**页面领域服务(PageDomainService)**,重点聚焦于页面元数据管理、页面类型控制(普通/表单/列表/报表)、发布流程、结构校验、组件布局合法性、与应用的关联验证、版本控制、状态变更规则以及与数据源和事件配置的一致性保证机制。通过深入解析代码实现,揭示了页面聚合根的操作流程、与IPageRepository的交互模式及事务处理方式,并探讨了批量操作、依赖检测和级联更新的实现细节,旨在为开发者提供清晰的业务逻辑理解。 + +## 项目结构 +项目采用分层架构,核心业务逻辑位于`src/DesignEngine`和`src/RenderEngine`目录下。`src/Common`包含共享的元数据模型和枚举。`PageDomainService`作为领域服务,位于`H.LowCode.DesignEngine.Domain`模块中,负责处理页面的核心业务逻辑。 + +```mermaid +graph TB +subgraph "src/Common" +A[MetaSchema] --> B[PageSchemaBase] +A --> C[PageTypeEnum] +A --> D[PublishStatusEnum] +end +subgraph "src/DesignEngine" +E[Domain] --> F[PageDomainService] +E --> G[IPageDomainService] +H[Repository.JsonFile] --> I[PageFileRepository] +end +subgraph "src/Common/H.LowCode.MetaSchema.DesignEngine" +J[PagePartsSchema] +K[ComponentPartsSchema] +end +F --> I : "依赖" +F --> J : "操作" +J --> K : "包含" +``` + +**图示来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) + +**本节来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) + +## 核心组件 +`PageDomainService`是页面管理的核心领域服务,实现了`IPageDomainService`接口。它不直接处理数据持久化,而是通过依赖注入的`IPageRepository`来完成。其主要职责是定义页面管理的业务契约,包括获取页面列表、根据ID获取页面、保存页面和删除页面。 + +**本节来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [IPageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IPageDomainService.cs) + +## 架构概览 +系统采用领域驱动设计(DDD)模式,`PageDomainService`作为领域服务层,协调聚合根`PagePartsSchema`与仓储`IPageRepository`之间的交互。`PagePartsSchema`是页面的聚合根,包含了页面的所有元数据,如名称、类型、数据源、事件和组件布局。`IPageRepository`的具体实现`PageFileRepository`负责将`PagePartsSchema`序列化为JSON文件并存储在文件系统中。 + +```mermaid +sequenceDiagram +participant Client as "客户端" +participant AppService as "PageAppService" +participant DomainService as "PageDomainService" +participant Repository as "PageFileRepository" +participant FileSystem as "文件系统" +Client->>AppService : SaveAsync(pageSchema) +AppService->>DomainService : SaveAsync(pageSchema) +DomainService->>Repository : SaveAsync(pageSchema) +Repository->>FileSystem : 写入JSON文件 +FileSystem-->>Repository : 成功 +Repository-->>DomainService : 完成 +DomainService-->>AppService : 完成 +AppService-->>Client : 返回成功 +``` + +**图示来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) + +## 详细组件分析 +### 页面领域服务 (PageDomainService) 分析 +`PageDomainService`是一个轻量级的门面,它将应用服务(Application Service)的请求转发给仓储(Repository)。它本身不包含复杂的业务逻辑,但定义了清晰的业务边界。 + +#### 类图 +```mermaid +classDiagram +class IPageDomainService { +<> ++GetListAsync(appId) PageListModel[] ++GetByIdAsync(appId, pageId) PagePartsSchema ++SaveAsync(pageSchema) void ++DeleteAsync(appId, pageId) void +} +class PageDomainService { +-_repository IPageRepository ++PageDomainService(repository) +} +class IPageRepository { +<> ++GetListAsync(appId) PageListModel[] ++GetByIdAsync(appId, pageId) PagePartsSchema ++SaveAsync(pageSchema) void ++DeleteAsync(appId, pageId) void +} +IPageDomainService <|.. PageDomainService : 实现 +PageDomainService --> IPageRepository : 依赖 +``` + +**图示来源** +- [IPageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/IPageDomainService.cs) +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [IPageRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs) + +#### 业务逻辑实现 +`PageDomainService`的实现非常直接,每个方法都直接调用`IPageRepository`的对应方法。例如,`SaveAsync`方法接收一个`PagePartsSchema`对象,并将其传递给`_repository.SaveAsync`。 + +```csharp +public async Task SaveAsync(PagePartsSchema pageSchema) +{ + await _repository.SaveAsync(pageSchema); +} +``` + +**本节来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) + +### 页面元数据与类型控制分析 +页面的核心元数据由`PageSchemaBase`和`PagePartsSchema`定义。`PageSchemaBase`是所有页面的基类,定义了通用属性。 + +#### 页面类型 (PageTypeEnum) +页面类型通过`PageTypeEnum`枚举进行控制,支持四种类型: +- **Normal (0)**: 普通页面 +- **Form (1)**: 表单页面 +- **Table (2)**: 列表页面 +- **Report (5)**: 报表页面 + +此枚举确保了页面类型的强类型约束和可读性。 + +#### 页面状态 (PublishStatusEnum) +页面的发布状态由`PublishStatusEnum`枚举管理: +- **Development**: 开发中(草稿) +- **Approving**: 审核中 +- **Published**: 已发布 + +此状态机控制了页面的生命周期,决定了页面是否可以被渲染引擎访问。 + +#### 页面聚合根 (PagePartsSchema) +`PagePartsSchema`继承自`PageSchemaBase`,是页面的聚合根,包含了页面的所有组成部分。 + +```mermaid +classDiagram +class PageSchemaBase { ++string AppId ++string Id ++string Name ++int Order ++PageTypeEnum PageType ++int PublishStatus ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList~EventSchema~ Events +} +class PagePartsSchema { ++IList~ComponentPartsSchema~ Components ++string[] SupportEvents +} +PageSchemaBase <|-- PagePartsSchema +``` + +**图示来源** +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) + +**本节来源** +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) + +### 页面创建与结构校验分析 +虽然`PageDomainService`本身不执行结构校验,但其依赖的`PageFileRepository`在保存时会进行基本的空值检查。更复杂的校验(如组件布局合法性)通常在应用服务层或前端完成。 + +#### 组件布局与一致性保证 +`PagePartsSchema`通过`Components`属性管理一个组件列表。每个`ComponentPartsSchema`都包含其自身的数据源`DataSource`和事件`Events`,这保证了页面与数据源、事件配置的一致性。 + +```mermaid +classDiagram +class PagePartsSchema { ++IList~ComponentPartsSchema~ Components +} +class ComponentPartsSchema { ++string ComponentId ++string LibraryId ++ComponentPartsFragmentSchema Fragment ++ComponentPartsDataSourceSchema DataSource ++IList~ComponentPartsSchema~ Childrens ++string[] SupportEvents +} +class ComponentPartsFragmentSchema { ++string DefaultTypeName ++string TypeName ++ComponentPartsFragmentSchema[] ChildFragments +} +class ComponentPartsDataSourceSchema { ++ComponentDataSourceSchema DataSourceFragment +} +PagePartsSchema --> ComponentPartsSchema : 包含 +ComponentPartsSchema --> ComponentPartsFragmentSchema : 渲染 +ComponentPartsSchema --> ComponentPartsDataSourceSchema : 数据 +ComponentPartsSchema --> ComponentPartsSchema : 嵌套 +``` + +**图示来源** +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) +- [ComponentPartsFragmentSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsFragmentSchema.cs) +- [ComponentPartsDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/DataSourceSchemas/ComponentPartsDataSourceSchema.cs) + +**本节来源** +- [PagePartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/PagePartsSchema.cs) +- [ComponentPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs) + +### 批量操作、依赖检测与级联更新 +当前`PageDomainService`的接口设计(`GetListAsync`, `DeleteAsync`)支持批量操作。例如,`GetListAsync`可以获取一个应用下的所有页面,`DeleteAsync`可以删除单个页面。然而,代码中并未直接体现复杂的依赖检测或级联更新逻辑。这类逻辑可能在应用服务层实现,例如,在删除一个应用时,需要级联删除其下的所有页面。 + +## 依赖分析 +`PageDomainService`的依赖关系清晰,仅依赖于`IPageRepository`接口,实现了控制反转(IoC)。`PageFileRepository`则依赖于`MetaOption`配置来确定元数据的存储路径。`PagePartsSchema`及其子组件形成了一个复杂的对象图,但通过JSON序列化/反序列化,实现了与文件系统的松耦合。 + +```mermaid +graph TD +A[PageDomainService] --> B[IPageRepository] +B --> C[PageFileRepository] +C --> D[MetaOption] +A --> E[PagePartsSchema] +E --> F[ComponentPartsSchema] +F --> G[ComponentPartsFragmentSchema] +F --> H[ComponentPartsDataSourceSchema] +``` + +**图示来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + +**本节来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) + +## 性能考量 +由于数据存储在文件系统中,性能主要受文件I/O影响。`GetListAsync`方法需要读取目录下所有JSON文件并反序列化,对于页面数量庞大的应用,这可能成为性能瓶颈。可以考虑引入缓存机制来优化频繁的读取操作。`SaveAsync`和`DeleteAsync`操作是原子的,单个文件的读写性能通常较好。 + +## 故障排除指南 +- **问题:保存页面失败,但无错误信息。** + **解决方案:** 检查`MetaOption`配置的`_metaBaseDir`路径是否存在且有写入权限。确认`pageSchema.Id`和`AppId`不为空。 + +- **问题:获取页面列表为空。** + **解决方案:** 检查指定的`appId`是否正确,确认`meta/apps/{appId}/page/`目录下是否存在JSON文件。 + +- **问题:页面类型或状态不正确。** + **解决方案:** 检查前端或应用服务层是否正确设置了`PageType`和`PublishStatus`字段,确保使用的是`PageTypeEnum`和`PublishStatusEnum`的正确值。 + +**本节来源** +- [PageFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs) +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) + +## 结论 +`PageDomainService`作为低代码平台的核心领域服务,提供了一个简洁而有效的API来管理页面的生命周期。它通过清晰的分层(领域服务、仓储)和聚合根设计(`PagePartsSchema`),实现了业务逻辑与数据持久化的分离。虽然当前实现侧重于基础的CRUD操作,但其设计为扩展复杂的业务规则(如结构校验、依赖检测、工作流)提供了坚实的基础。未来可以通过引入缓存、数据库存储或更复杂的校验规则来进一步提升其功能和性能。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202.md" "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202.md" new file mode 100644 index 0000000000000000000000000000000000000000..cfe3d747e3c2e727d2a4a2f5cd703c661772641b --- /dev/null +++ "b/.qoder/repowiki/zh/content/\350\256\276\350\256\241\345\274\225\346\223\216/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202/\351\242\206\345\237\237\346\234\215\345\212\241\345\261\202.md" @@ -0,0 +1,266 @@ +# 领域服务层 + + +**本文档引用的文件** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [IPageRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs) +- [IMenuRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IMenuRepository.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [MenuSchema.cs](file://src/Common/H.LowCode.MetaSchema/MenuSchema.cs) +- [DataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs) +- [PublishStatusEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs) + + +## 目录 + +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考量](#性能考量) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 + +本文档全面阐述低代码设计引擎的领域服务层(Domain Layer)架构与核心实现。重点分析 `AppDomainService`、`PageDomainService`、`MenuDomainService` 和 `DataSourceDomainService` 如何封装业务规则、维护领域模型一致性并协调聚合根操作。文档将说明领域服务与仓储接口(如 `IAppRepository`)的依赖关系,以及如何通过领域事件或事务边界保证数据完整性。结合代码实例解释应用创建时的校验逻辑、页面发布状态变更、菜单层级结构维护等关键业务流程。同时描述领域模型(如 `App`、`Page`)的聚合边界与生命周期管理,并说明领域服务如何为上层应用服务提供细粒度的业务能力支撑。 + +## 项目结构 + +低代码平台的源码结构清晰地划分为多个模块,其中领域服务层位于 `src/DesignEngine/H.LowCode.DesignEngine.Domain` 目录下。该层是业务逻辑的核心,负责封装与特定业务领域相关的复杂规则和流程。 + +```mermaid +graph TB +subgraph "src" +subgraph "DesignEngine" +subgraph "H.LowCode.DesignEngine.Domain" +subgraph "MetaDomainServices" +ADS[AppDomainService] +PDS[PageDomainService] +MDS[MenuDomainService] +DSDS[DataSourceDomainService] +end +subgraph "MetaRepositories" +IAR[IAppRepository] +IPR[IPageRepository] +IMR[IMenuRepository] +IDSR[IDataSourceRepository] +end +end +subgraph "H.LowCode.DesignEngine.Application" +AAS[AppApplicationService] +PAS[PageAppService] +end +end +subgraph "Common" +subgraph "H.LowCode.MetaSchema" +ASB[AppSchemaBase] +PSB[PageSchemaBase] +MS[MenuSchema] +DSS[DataSourceSchema] +end +end +end +ADS --> IAR +PDS --> IPR +MDS --> IMR +DSDS --> IDSR +AAS --> ADS +PAS --> PDS +``` + +**图示来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +**本节来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +## 核心组件 + +领域服务层的核心组件是四个主要的领域服务类:`AppDomainService`、`PageDomainService`、`MenuDomainService` 和 `DataSourceDomainService`。这些服务类均继承自 `Volo.Abp.Domain.Services.DomainService`,并实现了对应的接口(如 `IAppDomainService`)。它们的主要职责是封装跨多个实体或聚合的复杂业务逻辑,协调对仓储(Repository)的调用,并确保业务规则的一致性。 + +**本节来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) + +## 架构概览 + +领域服务层在整体架构中扮演着承上启下的关键角色。上层的应用服务(Application Service)通过领域服务来执行业务操作,而领域服务则通过仓储接口与数据持久化层进行交互。这种分层设计确保了业务逻辑的集中化和可维护性。 + +```mermaid +graph LR +A[应用服务层
AppApplicationService] --> B[领域服务层
AppDomainService] +B --> C[仓储层
IAppRepository] +C --> D[数据源
文件/数据库] +``` + +**图示来源** +- [AppApplicationService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs) +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +## 详细组件分析 + +### AppDomainService 分析 + +`AppDomainService` 是应用(App)领域的核心服务,负责管理应用元数据的生命周期。它通过依赖注入获取 `IAppRepository` 实例,从而将具体的持久化细节(如文件存储或数据库访问)与业务逻辑解耦。 + +#### 类图 +```mermaid +classDiagram +class AppDomainService { ++IAppRepository _repository ++GetListAsync() IList~AppPartsSchema~ ++GetAsync(string appId) AppPartsSchema ++SaveAsync(AppPartsSchema appSchema) void +} +class IAppRepository { ++GetListAsync() Task~IList~AppPartsSchema~~ ++GetAsync(string appId) Task~AppPartsSchema~ ++SaveAsync(AppPartsSchema appSchema) Task +} +AppDomainService --> IAppRepository : "依赖" +``` + +**图示来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +**本节来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) + +### PageDomainService 分析 + +`PageDomainService` 负责管理页面(Page)的业务逻辑。与 `AppDomainService` 类似,它也依赖于 `IPageRepository` 来执行数据操作。其关键方法包括根据应用ID获取页面列表、根据ID获取特定页面、保存页面以及删除页面。 + +#### 类图 +```mermaid +classDiagram +class PageDomainService { ++IPageRepository _repository ++GetListAsync(string appId) PageListModel[] ++GetByIdAsync(string appId, string pageId) PagePartsSchema ++SaveAsync(PagePartsSchema pageSchema) void ++DeleteAsync(string appId, string pageId) void +} +class IPageRepository { ++GetListAsync(string appId) Task~PageListModel[]~ ++GetByIdAsync(string appId, string pageId) Task~PagePartsSchema~ ++SaveAsync(PagePartsSchema pageSchema) Task ++DeleteAsync(string appId, string pageId) Task +} +PageDomainService --> IPageRepository : "依赖" +``` + +**图示来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [IPageRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs) + +**本节来源** +- [PageDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs) +- [IPageRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs) + +### MenuDomainService 分析 + +`MenuDomainService` 用于管理菜单(Menu)的增删改查操作。它维护了菜单的层级结构(通过 `ParentId` 字段),并确保菜单项的有序性(通过 `Order` 字段)。该服务通过 `IMenuRepository` 与数据层交互。 + +#### 类图 +```mermaid +classDiagram +class MenuDomainService { ++IMenuRepository _repository ++GetListAsync(string appId) IList~MenuSchema~ ++GetAsync(string appId, string menuId) MenuSchema ++SaveAsync(MenuSchema menuSchema) void ++DeleteAsync(string appId, string menuId) void +} +class IMenuRepository { ++GetListAsync(string appId) Task~IList~MenuSchema~~ ++GetAsync(string appId, string menuId) Task~MenuSchema~ ++SaveAsync(MenuSchema menuSchema) Task ++DeleteAsync(string appId, string menuId) Task +} +MenuDomainService --> IMenuRepository : "依赖" +``` + +**图示来源** +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [IMenuRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IMenuRepository.cs) + +**本节来源** +- [MenuDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs) +- [IMenuRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IMenuRepository.cs) + +### DataSourceDomainService 分析 + +`DataSourceDomainService` 是数据源(DataSource)的管理服务,其逻辑相对复杂,因为它需要处理多种类型的数据源(API、数据库表、选项等)。该服务不仅提供基本的CRUD操作,还提供了根据数据源类型进行过滤的业务方法,例如 `GetAllApisAsync` 用于获取所有API类型的数据源。 + +#### 流程图 +```mermaid +flowchart TD +A[调用GetAllApisAsync] --> B[调用GetListAsync获取所有数据源] +B --> C{遍历数据源列表} +C --> D[检查DataSourceType是否为API] +D --> |是| E[加入结果列表] +D --> |否| F[跳过] +E --> G[返回API数据源列表] +F --> G +``` + +**图示来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) + +**本节来源** +- [DataSourceDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs) +- [IDataSourceRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs) + +## 依赖分析 + +领域服务层的组件之间存在清晰的依赖关系。每个领域服务都依赖于一个或多个仓储接口,这些接口定义了数据访问的契约。具体的实现由下层的 `Repository.JsonFile` 或 `Repository.EntityFrameworkCore` 模块提供。这种依赖倒置原则(Dependency Inversion Principle)使得领域服务不依赖于具体的数据存储技术,从而提高了代码的可测试性和可维护性。 + +```mermaid +graph TD +ADS[AppDomainService] --> IAR[IAppRepository] +PDS[PageDomainService] --> IPR[IPageRepository] +MDS[MenuDomainService] --> IMR[IMenuRepository] +DSDS[DataSourceDomainService] --> IDSR[IDataSourceRepository] +IAR --> JFR[AppFileRepository] +IPR --> JFR[PageFileRepository] +IMR --> JFR[MenuFileRepository] +IDSR --> JFR[DataSourceFileRepository] +``` + +**图示来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +**本节来源** +- [IAppRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +## 性能考量 + +当前领域服务层的设计主要基于同步或异步的仓储调用。对于 `DataSourceDomainService` 中的 `GetAllEntities` 方法,其使用了 `.Result` 来阻塞获取异步结果,这在高并发场景下可能导致线程池饥饿,是一个潜在的性能瓶颈,建议重构为完全异步的方法。此外,所有数据操作都通过仓储进行,具体的性能表现取决于仓储的实现(如文件I/O或数据库查询)。 + +## 故障排除指南 + +当领域服务层出现数据不一致或操作失败时,应首先检查对应的仓储实现。例如,如果 `SaveAsync` 方法调用后数据未持久化,应检查 `AppFileRepository.SaveAsync` 是否正确地将 `AppPartsSchema` 对象序列化并写入到 `meta/apps/{appId}/appId.json` 文件中。同时,应确保领域模型(如 `AppSchemaBase`)的属性具有正确的序列化特性(如 `[JsonPropertyName]`),以避免数据丢失。 + +**本节来源** +- [AppDomainService.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +## 结论 + +低代码平台的领域服务层设计良好,遵循了领域驱动设计(DDD)的基本原则。通过将业务逻辑集中封装在 `AppDomainService`、`PageDomainService` 等服务中,并通过清晰的仓储接口与数据层解耦,系统实现了高内聚、低耦合。领域模型(`AppSchemaBase`、`PageSchemaBase` 等)定义了核心数据结构和业务状态(如 `PublishStatusEnum`)。未来可优化的方向包括消除同步等待(`.Result`),并考虑引入领域事件来解耦更复杂的业务流程。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\205\203\346\225\260\346\215\256\345\220\214\346\255\245\346\234\272\345\210\266.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\205\203\346\225\260\346\215\256\345\220\214\346\255\245\346\234\272\345\210\266.md" new file mode 100644 index 0000000000000000000000000000000000000000..d8867a71aff5b935fb4288c63cdaa711bc57329d --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\205\203\346\225\260\346\215\256\345\220\214\346\255\245\346\234\272\345\210\266.md" @@ -0,0 +1,271 @@ +# 元数据同步机制 + + +**本文档引用的文件** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [结论](#结论) + +## 引言 +本文档全面解析低代码平台中设计引擎与渲染引擎之间的元数据同步机制。重点阐述当用户在设计引擎中完成应用设计后,元数据(包括应用、页面、组件、数据源等JSON文件)如何从设计态持久化存储导出,并安全传输至渲染引擎的`meta`目录。文档详细说明了`AppFileRepository`等文件存储实现如何支持元数据的读写操作,发布流程中的版本控制、完整性校验与原子更新等关键机制,以及不同部署模式下的同步策略。 + +## 项目结构 +项目采用分层模块化架构,主要分为`meta`元数据存储目录和`src`源代码目录。 + +`meta`目录是元数据的物理存储位置,其结构清晰: +- `apps`:存放各个应用的元数据,每个应用(如`caseapp`、`testapp`)拥有独立的子目录,内含`datasource`、`menu`、`page`等分类的JSON文件。 +- `parts\componentParts\antdesign`:存放组件库的元数据定义。 + +`src`目录包含多个核心模块: +- `Common`:存放跨引擎共享的基础元数据模型(`MetaSchema`)和配置。 +- `DesignEngine`:设计引擎,负责应用的设计与元数据的持久化。 +- `RenderEngine`:渲染引擎,负责读取元数据并运行时渲染应用。 +- `Tools`:包含数据库迁移和元数据迁移工具。 + +```mermaid +graph TB +subgraph "元数据存储" +meta["meta/"] +apps["apps/"] +parts["parts/componentParts/"] +meta --> apps +meta --> parts +end +subgraph "源代码" +src["src/"] +DesignEngine["DesignEngine/"] +RenderEngine["RenderEngine/"] +Common["Common/"] +Tools["Tools/"] +src --> DesignEngine +src --> RenderEngine +src --> Common +src --> Tools +end +DesignEngine -- "读写" --> meta +RenderEngine -- "读取" --> meta +``` + +**Diagram sources** +- [meta](file://meta) +- [src](file://src) + +## 核心组件 +本节分析实现元数据同步的核心组件,包括文件存储库、元数据模型和配置选项。 + +**Section sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + +## 架构概览 +元数据同步的核心在于设计引擎和渲染引擎对同一`meta`目录的协同访问。两者通过相似的文件存储库模式进行交互,但关注的元数据模型不同。 + +```mermaid +sequenceDiagram +participant 设计引擎 as 设计引擎 +participant AppFileRepository_D as AppFileRepository (设计) +participant meta as meta目录 +participant AppFileRepository_R as AppFileRepository (渲染) +participant 渲染引擎 as 渲染引擎 +设计引擎 ->> AppFileRepository_D : SaveAsync(appSchema) +AppFileRepository_D ->> meta : 写入apps/{appId}/{appId}.json +meta -->> AppFileRepository_D : 完成 +AppFileRepository_D -->> 设计引擎 : 完成 +Note over 设计引擎,渲染引擎 : 用户发布应用 +渲染引擎 ->> AppFileRepository_R : GetAsync(appId) +AppFileRepository_R ->> meta : 读取apps/{appId}/{appId}.json +meta -->> AppFileRepository_R : 返回JSON +AppFileRepository_R -->> 渲染引擎 : 返回AppSchema +``` + +**Diagram sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [meta](file://meta) + +## 详细组件分析 + +### 文件存储库分析 +`AppFileRepository`是元数据持久化的关键实现,它在设计引擎和渲染引擎中都有对应的版本,均继承自`FileRepositoryBase`。 + +#### 设计引擎的AppFileRepository +设计引擎的`AppFileRepository`使用`AppPartsSchema`作为数据模型,该模型继承自`AppSchemaBase`,专为设计态的丰富配置而设计。 + +```csharp +public class AppFileRepository : FileRepositoryBase, IAppRepository +{ + private static string appFileName_Format = @"{0}\{1}\{2}.json"; + + public AppFileRepository(IOptions metaOption) : base(metaOption) { } + + public async Task SaveAsync(AppPartsSchema appSchema) + { + // ... 验证和设置修改时间 + string fileName = string.Format(appFileName_Format, _metaBaseDir, appSchema.Id, appSchema.Id); + string fileDirectory = Path.GetDirectoryName(fileName); + if (!Directory.Exists(fileDirectory)) + Directory.CreateDirectory(fileDirectory); + File.WriteAllText(fileName, appSchema.ToJson(), Encoding.UTF8); + await Task.CompletedTask; + } +} +``` +此实现确保了元数据的原子写入。它首先创建目录(如果不存在),然后直接写入文件。虽然没有显式的事务或临时文件机制,但`File.WriteAllText`在大多数文件系统上是原子操作。 + +**Section sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +#### 渲染引擎的AppFileRepository +渲染引擎的`AppFileRepository`使用`AppSchema`作为数据模型,该模型同样继承自`AppSchemaBase`,但更侧重于运行时所需的精简信息。 + +```csharp +public class AppFileRepository : FileRepositoryBase, IAppRepository +{ + private static string appFileName_Format = @"{0}\{1}\{2}.json"; + + public AppFileRepository(IOptions metaOption) : base(metaOption) { } + + public async Task GetAsync(string appId) + { + string fileName = string.Format(appFileName_Format, _metaBaseDir, appId, appId); + var appSchemaJson = ReadAllText(fileName); + var appSchema = appSchemaJson.FromJson(); + return await Task.FromResult(appSchema); + } +} +``` +此实现专注于高效读取。它通过`ReadAllText`方法读取文件内容,并反序列化为`AppSchema`对象。 + +**Section sources** +- [AppFileRepository.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +#### FileRepositoryBase基类 +`FileRepositoryBase`为所有文件存储库提供了基础功能,如配置注入和文件读取。 + +```csharp +public abstract class FileRepositoryBase +{ + protected static string _metaBaseDir; + + public FileRepositoryBase(IOptions metaOption) + { + _metaBaseDir = metaOption.Value.AppsFilePath; // 从配置中获取元数据根路径 + IsChangeTrackingEnabled = false; + } + + protected static string ReadAllText(string fileName) + { + if (!File.Exists(fileName)) + throw new FileNotFoundException(fileName); + return File.ReadAllText(fileName, Encoding.UTF8); + } +} +``` +该基类通过依赖注入获取`MetaOption`,从而确定`meta`目录的物理路径。 + +**Section sources** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [FileRepositoryBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) + +### 元数据模型分析 +元数据模型采用继承结构,实现了设计态与运行态的分离与统一。 + +```mermaid +classDiagram +class AppSchemaBase { ++string Id ++string Name ++string Icon ++string Picture ++string Description ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class AppPartsSchema { +<<设计态>> +} +class AppSchema { +<<运行态>> +} +AppPartsSchema --|> AppSchemaBase +AppSchema --|> AppSchemaBase +``` + +**Diagram sources** +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) + +- `AppSchemaBase`:定义了应用元数据的公共基础属性,如ID、名称、图标、版本和发布状态。 +- `AppPartsSchema`:设计引擎专用的模型,继承自`AppSchemaBase`,可扩展设计态特有的复杂配置。 +- `AppSchema`:渲染引擎专用的模型,继承自`AppSchemaBase`,结构更精简,适合运行时快速加载。 + +### 配置分析 +`MetaOption`类定义了元数据存储的路径配置。 + +```csharp +public class MetaOption +{ + public const string SectionName = "Meta"; + public string AppsFilePath { get; set; } // 指向meta/apps目录 + public string PartsFilePath { get; set; } // 指向meta/parts目录 +} +``` +此配置通过依赖注入被`FileRepositoryBase`使用,确保了路径的集中管理。 + +**Section sources** +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + +## 依赖分析 +系统内各组件的依赖关系清晰,遵循了依赖倒置原则。 + +```mermaid +graph TD +A[AppFileRepository] --> B[FileRepositoryBase] +B --> C[MetaOption] +C --> D[Configuration] +A --> E[AppPartsSchema/AppSchema] +E --> F[AppSchemaBase] +F --> G[MetaSchemaBase] +A -.-> H[IAppRepository] +``` + +设计引擎和渲染引擎的`AppFileRepository`都依赖于`FileRepositoryBase`和各自的元数据模型。`FileRepositoryBase`依赖于`MetaOption`配置。这种分层设计使得文件存储逻辑与具体引擎解耦。 + +**Diagram sources** +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [AppPartsSchema.cs](file://src/Common/H.LowCode.MetaSchema.DesignEngine/AppPartsSchema.cs) +- [AppSchema.cs](file://src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs) + +## 性能考虑 +1. **增量更新**:当前`SaveAsync`是全量写入。优化方向是实现增量更新,仅保存变更的部分,减少I/O开销。 +2. **缓存预热**:渲染引擎在启动时可以预加载所有应用的`AppSchema`到内存缓存中,避免每次请求都读取磁盘。 +3. **文件监听**:设计引擎在保存文件后,可以通过文件系统监听(如`FileSystemWatcher`)通知渲染引擎,使其能及时刷新缓存,实现近实时同步。 + +## 结论 +该低代码平台的元数据同步机制通过共享文件系统(`meta`目录)实现,设计简洁。`AppFileRepository`及其基类提供了统一的文件读写接口,而`AppPartsSchema`和`AppSchema`的分离设计则兼顾了设计态的灵活性与运行态的效率。发布流程本质上是设计引擎将`AppPartsSchema`序列化并写入`meta`目录,渲染引擎随后读取并反序列化为`AppSchema`的过程。对于分布式部署,可将直接文件复制替换为通过消息队列触发对象存储的同步,以保证一致性。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\244\232\347\216\257\345\242\203\351\205\215\347\275\256\347\256\241\347\220\206.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\244\232\347\216\257\345\242\203\351\205\215\347\275\256\347\256\241\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..ac1162df5c1c07bae37a1b1aed22e5efd08e0a4c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\244\232\347\216\257\345\242\203\351\205\215\347\275\256\347\256\241\347\220\206.md" @@ -0,0 +1,314 @@ +# 多环境配置管理 + + +**本文档引用的文件** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.Development.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.Development.json) +- [launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [appsettings.Development.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.Development.json) +- [launchSettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Properties/launchSettings.json) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) + + +## 目录 +1. [引言](#引言) +2. [基础配置文件作用](#基础配置文件作用) +3. [环境特定配置覆盖机制](#环境特定配置覆盖机制) +4. [启动配置与环境变量](#启动配置与环境变量) +5. [设计引擎与渲染引擎配置对比](#设计引擎与渲染引擎配置对比) +6. [配置加载机制与优先级](#配置加载机制与优先级) +7. [配置项分类管理建议](#配置项分类管理建议) +8. [配置验证与热重载](#配置验证与热重载) + +## 引言 +本低代码平台采用基于 ASP.NET Core 的多环境配置策略,通过 `appsettings.json` 作为基础配置,结合环境特定文件(如 `appsettings.Development.json`)实现灵活的配置管理。平台包含设计引擎和渲染引擎两个核心模块,分别服务于应用构建和运行时展示。本文详细说明其配置体系结构、加载机制及最佳实践。 + +## 基础配置文件作用 +`appsettings.json` 是平台的核心配置文件,定义了所有环境下的默认配置值。该文件位于各主机项目根目录下,为应用程序提供基础设置。 + +### 设计引擎基础配置 +设计引擎的 `appsettings.json` 包含以下关键配置项: + +```json +{ + "AllowedHosts": "*", + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "Default": "Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Trusted_Connection=True;TrustServerCertificate=True" + }, + "Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" + }, + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:5181" + } + }, + "Sites": [ + { + "AppId": "caseapp", + "SiteUrl": "https://localhost:5191" + }, + { + "AppId": "testapp", + "SiteUrl": "https://localhost:5191" + } + ] +} +``` + +#### 配置项说明 +- **ConnectionStrings**: 定义数据库连接字符串,用于持久化元数据。 +- **Meta**: 指定元数据文件存储路径,`appsFilePath` 和 `partsFilePath` 分别指向应用和组件库的 JSON 定义文件。 +- **RemoteServices**: 配置远程服务基地址,设计引擎通过此地址调用其他服务。 +- **Sites**: 定义站点映射关系,将应用 ID 与运行时 URL 关联。 + +### 渲染引擎基础配置 +渲染引擎的 `appsettings.json` 结构类似,但 `RemoteServices` 的 `BaseUrl` 指向设计引擎: + +```json +{ + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:5191" + } + } +} +``` + +这表明渲染引擎在运行时从设计引擎获取元数据。 + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +## 环境特定配置覆盖机制 +平台使用 ASP.NET Core 内置的配置分层机制,允许环境特定文件覆盖基础配置中的值。 + +### 开发环境配置 +`appsettings.Development.json` 文件仅包含日志级别配置: + +```json +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} +``` + +此配置会**合并**到 `appsettings.json` 中,仅当键存在时进行覆盖。例如,日志级别设置会被应用,而数据库连接等其他配置仍沿用基础文件的值。 + +### 配置覆盖原则 +- **层级优先级**:`appsettings.{Environment}.json` > `appsettings.json` +- **深度合并**:对象属性逐层合并,而非完全替换 +- **动态加载**:根据 `ASPNETCORE_ENVIRONMENT` 环境变量自动选择配置文件 + +**Section sources** +- [appsettings.Development.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.Development.json) +- [appsettings.Development.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.Development.json) + +## 启动配置与环境变量 +`launchSettings.json` 文件定义了开发环境下的启动行为和环境变量,位于 `Properties` 目录中。 + +### 设计引擎启动配置 +```json +{ + "profiles": { + "DesignEngine": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:5181;http://localhost:5180", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} +``` + +### 渲染引擎启动配置 +```json +{ + "profiles": { + "RenderEngine": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:5191;http://localhost:5190", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} +``` + +### 关键配置说明 +- **applicationUrl**: 定义服务监听地址,设计引擎使用 5181 端口,渲染引擎使用 5191 端口。 +- **launchBrowser**: 设计引擎启动时自动打开浏览器,渲染引擎则不自动打开。 +- **ASPNETCORE_ENVIRONMENT**: 明确设置环境为 "Development",触发加载 `appsettings.Development.json`。 + +**Section sources** +- [launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json) +- [launchSettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Properties/launchSettings.json) + +## 设计引擎与渲染引擎配置对比 + +```mermaid +graph TD +subgraph "设计引擎" +A1["端口: 5181"] +A2["RemoteServices: 指向自身"] +A3["Sites: 指向渲染引擎 5191"] +A4["启动时打开浏览器"] +end +subgraph "渲染引擎" +B1["端口: 5191"] +B2["RemoteServices: 指向设计引擎 5181"] +B3["无 Sites 配置"] +B4["启动时不打开浏览器"] +end +A2 --> B1 +A3 --> B1 +``` + +**Diagram sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json) +- [launchSettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Properties/launchSettings.json) + +### 配置结构异同 +| 特性 | 设计引擎 | 渲染引擎 | +|------|--------|--------| +| **核心功能** | 应用设计与构建 | 应用运行时渲染 | +| **RemoteServices** | 指向自身服务 | 指向设计引擎获取元数据 | +| **Sites 配置** | 存在,定义应用部署地址 | 不存在 | +| **启动行为** | 自动打开浏览器 | 不自动打开 | +| **应用状态** | `LowCodeAppState(true)` | `LowCodeAppState(false)` | + +**Section sources** +- [DesignEngineHostModule.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs) +- [RenderEngineHostModule.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs) +- [LowCodeAppState.cs](file://src/Common/H.LowCode.ComponentBase/LowCodeAppState.cs) + +## 配置加载机制与优先级 +平台遵循 ASP.NET Core 标准配置加载流程,优先级从低到高如下: + +1. `appsettings.json` +2. `appsettings.{Environment}.json` +3. 环境变量 +4. 命令行参数 + +### 配置加载流程 +```mermaid +flowchart TD +Start([程序启动]) --> SetEnv["设置 ASPNETCORE_ENVIRONMENT"] +SetEnv --> LoadBase["加载 appsettings.json"] +LoadBase --> LoadEnv["加载 appsettings.{Environment}.json"] +LoadEnv --> LoadEnvVars["加载环境变量"] +LoadEnvVars --> BuildConfig["构建 IConfiguration"] +BuildConfig --> RegisterOptions["注册强类型选项"] +RegisterOptions --> UseConfig["应用程序使用配置"] +``` + +### 强类型配置绑定 +平台使用 `MetaOption` 和 `SiteOption` 类实现强类型配置: + +```csharp +public class MetaOption +{ + public const string SectionName = "Meta"; + public string AppsFilePath { get; set; } + public string PartsFilePath { get; set; } +} + +public class SiteOption +{ + public const string SectionName = "Sites"; + public string AppId { get; set; } + public string SiteUrl { get; set; } +} +``` + +这些类通过依赖注入在服务中使用,确保类型安全和编译时检查。 + +**Section sources** +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) +- [SiteOption.cs](file://src/Common/H.LowCode.Configuration/Options/SiteOption.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +## 配置项分类管理建议 +为确保配置安全性和可维护性,建议按以下方式分类管理: + +### 敏感信息(如数据库连接字符串) +- **管理方式**:使用环境变量或 Azure Key Vault 等密钥管理服务 +- **示例**: + ```bash + set ConnectionStrings__Default=Server=prod;Database=H_LowCode;User=sa;Password=*** + ``` + +### 运行时参数(如 API 地址) +- **管理方式**:保留在 `appsettings.json` 中,通过环境文件覆盖 +- **示例**: + ```json + // appsettings.Production.json + { + "RemoteServices": { + "Default": { + "BaseUrl": "https://api.prod.com" + } + } + } + ``` + +### 功能开关(如调试模式) +- **管理方式**:使用布尔型配置项,结合环境变量控制 +- **示例**: + ```json + { + "Features": { + "EnableDebugTools": true + } + } + ``` + +## 配置验证与热重载 +### 配置验证机制 +建议在 `Program.cs` 中添加配置验证: + +```csharp +// 示例代码(未在源码中实现,建议添加) +builder.Services.Configure(options => +{ + if (string.IsNullOrEmpty(options.AppsFilePath)) + throw new InvalidOperationException("Meta:appsFilePath 不能为空"); +}); +``` + +### 热重载支持 +- **开发环境**:启用 `dotnet watch` 可实现配置文件修改后自动重启 +- **运行时**:可通过 API 端点触发配置重新加载(需自定义实现) + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\256\271\345\231\250\345\214\226\351\203\250\347\275\262.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\256\271\345\231\250\345\214\226\351\203\250\347\275\262.md" new file mode 100644 index 0000000000000000000000000000000000000000..0983f1fab60f964e065fa3f64bcf39689243c833 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\345\256\271\345\231\250\345\214\226\351\203\250\347\275\262.md" @@ -0,0 +1,261 @@ +# 容器化部署 + + +**本文档中引用的文件** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + + +## 目录 +1. [简介](#简介) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 简介 +本文档提供基于Docker的容器化部署完整指南,涵盖设计引擎和渲染引擎的多阶段构建、配置管理、服务编排及Kubernetes扩展方案。项目采用模块化架构,包含设计引擎(DesignEngine)和渲染引擎(RenderEngine),分别用于低代码应用的设计与运行时渲染。两者均基于ASP.NET Core Blazor Server/WebAssembly混合模式开发,通过Entity Framework Core与数据库交互,并使用JSON文件存储元数据。本文将详细说明如何实现编译与运行环境分离,优化镜像体积,并通过docker-compose和Kubernetes进行服务编排。 + +## 项目结构 +项目采用分层架构,主要分为`meta`、`src`和`Tools`三大目录。`meta`目录存放应用元数据(如页面、菜单、数据源配置),`src`目录包含核心源码,`Tools`目录包含数据库迁移工具。 + +```mermaid +graph TB +subgraph "元数据" +meta["meta/"] +apps["apps/"] +parts["parts/"] +end +subgraph "源码" +src["src/"] +DesignEngine["DesignEngine/"] +RenderEngine["RenderEngine/"] +Common["Common/"] +Tools["Tools/"] +end +subgraph "部署" +Docker["Dockerfile"] +Compose["docker-compose.yml"] +end +meta --> DesignEngine +meta --> RenderEngine +src --> Docker +Docker --> Compose +``` + +**Diagram sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +## 核心组件 +核心组件包括设计引擎和渲染引擎,两者共享`Common`模块中的基础类库。设计引擎提供可视化设计界面,渲染引擎负责应用的运行时展示。两者均通过`Host`项目作为入口点,使用`appsettings.json`进行配置,并通过`DbContext`与数据库交互。 + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +## 架构概述 +系统采用微服务架构,设计引擎和渲染引擎作为独立服务运行,共享同一数据库。元数据通过文件系统(`meta`目录)进行管理,支持JSON文件存储。数据库使用SQL Server LocalDB进行本地开发,生产环境可替换为远程SQL Server实例。 + +```mermaid +graph LR +subgraph "客户端" +Browser["浏览器"] +end +subgraph "服务端" +DE["设计引擎"] +RE["渲染引擎"] +DB[(数据库)] +end +Browser --> DE +Browser --> RE +DE --> DB +RE --> DB +DE --> meta +RE --> meta +``` + +**Diagram sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +## 详细组件分析 + +### 设计引擎分析 +设计引擎负责低代码应用的可视化设计,其核心配置位于`appsettings.json`,包括数据库连接字符串、元数据路径和远程服务地址。 + +#### 配置文件分析 +设计引擎的`appsettings.json`包含以下关键配置: +- **ConnectionStrings**: 数据库连接字符串,指向本地SQL Server LocalDB实例。 +- **Meta**: 元数据文件路径,指向`../../../meta/apps`和`../../../meta/parts`。 +- **RemoteServices**: 远程服务基地址,用于API调用。 +- **Sites**: 应用站点配置,定义了`caseapp`和`testapp`的访问URL。 + +```json +{ + "ConnectionStrings": { + "Default": "Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Trusted_Connection=True;TrustServerCertificate=True" + }, + "Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" + }, + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:5181" + } + }, + "Sites": [ + { + "AppId": "caseapp", + "SiteUrl": "https://localhost:5191" + } + ] +} +``` + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) + +#### 启动流程分析 +设计引擎的启动流程在`Program.cs`中定义,主要步骤包括: +1. 创建WebApplicationBuilder。 +2. 添加Razor组件、控制器和响应压缩服务。 +3. 配置Autofac依赖注入容器。 +4. 构建并初始化应用。 +5. 配置HTTP请求管道,包括静态文件、HTTPS重定向、路由和控制器映射。 + +```csharp +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); +builder.Services.AddControllers(); +builder.Services.AddResponseCompression(); +builder.Host.UseAutofac(); +await builder.AddApplicationAsync(); +var app = builder.Build(); +await app.InitializeApplicationAsync(); +app.UseStaticFiles(); +app.UseHttpsRedirection(); +app.UseRouting(); +app.MapControllers(); +app.MapRazorComponents(); +await app.RunAsync(); +``` + +**Section sources** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +### 渲染引擎分析 +渲染引擎负责低代码应用的运行时渲染,其配置与设计引擎类似,但不包含`Sites`配置。 + +#### 配置文件分析 +渲染引擎的`appsettings.json`与设计引擎基本一致,但`RemoteServices`的`BaseUrl`指向设计引擎。 + +```json +{ + "ConnectionStrings": { + "Default": "Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Trusted_Connection=True;TrustServerCertificate=True" + }, + "Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" + }, + "RemoteServices": { + "Default": { + "BaseUrl": "https://localhost:5191" + } + } +} +``` + +**Section sources** +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +#### 启动流程分析 +渲染引擎的启动流程与设计引擎几乎完全相同,仅模块类型不同。 + +```csharp +await builder.AddApplicationAsync(); +``` + +**Section sources** +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +### 数据库交互分析 +设计引擎和渲染引擎均通过Entity Framework Core与数据库交互,使用`DesignEngineDbContext`和`RenderEngineDbContext`。 + +#### DbContext分析 +`DbContext`类实现了动态实体管理,通过`EntityTypeManager`加载动态实体,并在`OnModelCreating`中配置表映射、属性映射和主键。 + +```csharp +protected override void OnModelCreating(ModelBuilder modelBuilder) +{ + var dynamicEntities = _entityTypeManager.LoadDynamicEntities(); + foreach (var dynamicEntity in dynamicEntities) + { + var entityBuilder = modelBuilder.Entity(dynamicEntity.EntityType) + .ToTable(dynamicEntity.EntityName); + ConfigureProperties(entityBuilder, dynamicEntity, dynamicEntity.EntityType); + entityBuilder.HasKey(dynamicEntity.PrimaryKey); + } + base.OnModelCreating(modelBuilder); +} +``` + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +## 依赖分析 +项目依赖关系清晰,设计引擎和渲染引擎独立运行,共享数据库和元数据。`Common`模块提供基础类库,`Tools`模块提供数据库迁移功能。 + +```mermaid +graph TD +DE["设计引擎"] --> Common["Common"] +RE["渲染引擎"] --> Common +DE --> DB[(数据库)] +RE --> DB +Migrator["DbMigrator"] --> DB +Common --> DB +``` + +**Diagram sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +**Section sources** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + +## 性能考虑 +- **响应压缩**: 启用了Brotli压缩,优化网络传输。 +- **静态文件缓存**: 静态文件设置了600秒的缓存。 +- **EF Core拦截器**: 使用`QueryWithNoLockDbCommandInterceptor`优化查询性能。 +- **动态实体**: 通过动态实体减少数据库表数量,提高灵活性。 + +## 故障排除指南 +- **数据库连接失败**: 检查`ConnectionStrings`配置,确保SQL Server服务运行。 +- **元数据加载失败**: 检查`Meta`路径配置,确保`meta`目录存在且可读。 +- **API调用失败**: 检查`RemoteServices`的`BaseUrl`,确保服务可达。 +- **健康检查失败**: 项目未配置健康检查中间件,需在`Program.cs`中添加`app.MapHealthChecks("/health")`。 + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +## 结论 +本文档详细分析了低代码平台的容器化部署方案。设计引擎和渲染引擎可分别构建为独立Docker镜像,通过`appsettings.json`进行配置管理。建议使用多阶段Docker构建优化镜像体积,并通过`docker-compose.yml`编排服务。在Kubernetes中,可使用ConfigMap管理配置,Secret存储敏感信息,Ingress配置路由。未来可添加健康检查和日志驱动集成以增强运维能力。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\346\200\247\350\203\275\350\260\203\344\274\230.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\346\200\247\350\203\275\350\260\203\344\274\230.md" new file mode 100644 index 0000000000000000000000000000000000000000..9946192e02df274fdc76d0a6c597c55bad360c2c --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\346\200\247\350\203\275\350\260\203\344\274\230.md" @@ -0,0 +1,290 @@ +# 性能调优 + + +**本文档引用的文件** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDynamicComponentBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/RenderEngineDynamicComponentBase.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构分析](#项目结构分析) +3. [核心组件分析](#核心组件分析) +4. [架构概览](#架构概览) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档旨在为低代码平台提供系统级性能优化建议。通过分析元数据读取、静态资源处理、数据库访问、核心工具类性能以及Web优化技术,提出一系列可实施的性能调优策略。文档将深入探讨缓存策略、压缩技术、连接池配置等关键性能因素,并提供具体的实现建议和基准指标。 + +## 项目结构分析 +该项目采用模块化设计,主要分为`meta`(元数据)、`src`(源代码)和`Tools`(工具)三大目录。`meta`目录存储应用程序的元数据配置,包括应用、菜单、页面和组件等JSON文件。`src`目录包含多个子系统,如设计引擎、渲染引擎和通用组件库,采用分层架构设计。 + +```mermaid +graph TB +subgraph "元数据" +meta["meta/"] +apps["apps/"] +parts["parts/"] +end +subgraph "源代码" +src["src/"] +DesignEngine["DesignEngine/"] +RenderEngine["RenderEngine/"] +Common["Common/"] +Tools["Tools/"] +end +meta --> DesignEngine +meta --> RenderEngine +DesignEngine --> RenderEngine +``` + +**图源** +- [项目结构](file://README.md) + +## 核心组件分析 +系统的核心组件包括设计引擎、渲染引擎和元数据管理模块。设计引擎负责可视化设计和元数据管理,渲染引擎负责运行时页面渲染,两者共享元数据结构但职责分离。通用组件库提供跨模块的基础功能。 + +**本节来源** +- [H.LowCode.ComponentBase.csproj](file://src/Common/H.LowCode.ComponentBase/H.LowCode.ComponentBase.csproj) +- [H.LowCode.MetaSchema.csproj](file://src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj) + +## 架构概览 +系统采用前后端分离的微服务架构,设计引擎和渲染引擎作为独立的服务运行。元数据通过文件系统或远程服务存储,支持JSON文件和数据库两种存储方式。渲染引擎通过元数据动态生成UI组件,实现低代码的核心功能。 + +```mermaid +graph LR +A[客户端] --> B[渲染引擎] +C[设计器] --> D[设计引擎] +D --> E[元数据存储] +B --> E +E --> F[(数据库)] +E --> G[文件系统] +``` + +**图源** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) + +## 详细组件分析 + +### 元数据缓存策略分析 +当前系统在读取元数据时直接从文件系统加载,缺乏有效的缓存机制,导致频繁的I/O操作。所有元数据读取操作均通过`FileRepositoryBase`类实现,该类直接读取JSON文件而没有缓存层。 + +```csharp +protected static string ReadAllText(string fileName) +{ + if (!File.Exists(fileName)) + throw new FileNotFoundException(fileName); + + return File.ReadAllText(fileName, Encoding.UTF8); +} +``` + +**建议的缓存策略**: +1. **内存缓存**:使用`MemoryCache`对频繁访问的元数据进行缓存 +2. **分布式缓存**:在集群环境下使用Redis实现分布式缓存 +3. **缓存失效机制**:基于元数据的`ModifiedTime`字段实现时间戳验证 + +```mermaid +flowchart TD +Start([请求元数据]) --> CheckCache["检查缓存"] +CheckCache --> CacheHit{"缓存命中?"} +CacheHit --> |是| ReturnCache["返回缓存数据"] +CacheHit --> |否| ReadFile["读取文件系统"] +ReadFile --> ParseJson["解析JSON"] +ParseJson --> UpdateCache["更新缓存"] +UpdateCache --> ReturnResult["返回结果"] +ReturnCache --> End([响应]) +ReturnResult --> End +``` + +**图源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [AppFileRepository.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs) + +**本节来源** +- [FileRepositoryBase.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs) +- [MetaOption.cs](file://src/Common/H.LowCode.Configuration/Options/MetaOption.cs) + +### ObjectMerger性能瓶颈分析 +`ObjectMerger`类是系统中的核心工具类,用于对象属性的合并操作,但存在多个性能瓶颈: + +```csharp +public static void Merge(Type type, object source, object target) +{ + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); + + foreach (var property in properties) + { + var sourcePropertyValue = property.GetValue(source); + // ... 处理逻辑 + } +} +``` + +**性能问题分析**: +1. **反射开销**:每次调用都使用反射获取属性信息,没有缓存 +2. **递归调用**:深度嵌套对象导致大量递归调用 +3. **集合处理**:集合合并算法效率较低,存在不必要的内存分配 + +**优化方案**: +1. **属性信息缓存**:使用`ConcurrentDictionary`缓存属性信息 +2. **编译表达式树**:使用`Expression`编译属性访问器,避免反射开销 +3. **批量处理优化**:优化集合合并算法,减少迭代次数 + +```mermaid +classDiagram +class ObjectMerger { ++static ConcurrentDictionary PropertyCache ++static void Merge(Type type, object source, object target) ++static void CompilePropertyAccessors() +} +class PropertyInfoCache { ++Type TargetType ++PropertyInfo[] Properties ++Func Getter ++Action Setter +} +ObjectMerger --> PropertyInfoCache : "使用" +``` + +**图源** +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) + +**本节来源** +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) + +### 静态资源优化分析 +系统已配置响应压缩和静态文件缓存,但在CDN分发和压缩配置方面仍有优化空间。 + +```csharp +builder.Services.AddResponseCompression(options => +{ + options.Providers.Add(); +}); +builder.Services.Configure(options => +{ + options.Level = CompressionLevel.Optimal; +}); + +app.UseStaticFiles(new StaticFileOptions +{ + OnPrepareResponse = ctx => + { + ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=600"); + } +}); +``` + +**优化建议**: +1. **压缩中间件配置**:在`appsettings.json`中配置压缩级别和MIME类型 +2. **CDN分发**:将静态资源部署到CDN,减少服务器负载 +3. **浏览器缓存优化**:延长缓存时间,添加版本控制 + +**本节来源** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +### 数据库性能优化分析 +系统使用Entity Framework Core作为ORM框架,但缺少关键的性能配置。 + +```csharp +protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) +{ + optionsBuilder.AddInterceptors(new QueryWithNoLockDbCommandInterceptor()); + base.OnConfiguring(optionsBuilder); +} +``` + +**优化建议**: +1. **连接池配置**:在连接字符串中添加连接池参数 + ``` + Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Pooling=true;Max Pool Size=100;Min Pool Size=5 + ``` +2. **命令超时设置**:配置合理的命令超时时间 +3. **查询优化**:使用`WITH (NOLOCK)`提示减少锁争用 + +**本节来源** +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) + +### 渲染引擎加载策略分析 +渲染引擎采用动态组件渲染机制,但缺乏预加载和懒加载的平衡策略。 + +```csharp +private void RenderComponentRecursive( + string componentId, bool isSupportDataSource, + ComponentSchema component, + ComponentDataSourceSchema dataSource, + ComponentFragmentSchema componentFragment, + RenderTreeBuilder builder, int index) +{ + // 递归渲染组件 +} +``` + +**优化建议**: +1. **元数据预加载**:在应用启动时预加载常用元数据 +2. **组件懒加载**:对非关键组件实现按需加载 +3. **加载优先级管理**:根据组件重要性设置加载优先级 + +**本节来源** +- [RenderEngineDynamicComponentBase.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Abstraction/RenderEngineDynamicComponentBase.cs) + +## 依赖分析 +系统各模块之间的依赖关系清晰,采用依赖注入模式管理服务。设计引擎和渲染引擎共享元数据模型,但通过不同的实现方式分离关注点。 + +```mermaid +graph TD +A[设计引擎] --> B[元数据模型] +C[渲染引擎] --> B +B --> D[通用组件] +D --> E[配置选项] +A --> F[数据库] +C --> F +``` + +**图源** +- [H.LowCode.MetaSchema.csproj](file://src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj) +- [H.LowCode.MetaSchema.RenderEngine.csproj](file://src/Common/H.LowCode.MetaSchema.RenderEngine/H.LowCode.MetaSchema.RenderEngine.csproj) + +**本节来源** +- [项目文件](file://src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj) + +## 性能考虑 +### Web优化技术建议 +1. **启用HTTP/2**:提升并发请求性能 +2. **Gzip/Brotli压缩**:已实现Brotli压缩,可进一步优化 +3. **浏览器缓存**:当前缓存时间为600秒,可延长至24小时 +4. **资源预加载**:使用``预加载关键资源 + +### 性能测试方法 +1. **基准测试**:使用JMeter或k6进行压力测试 +2. **监控指标**:关注响应时间、吞吐量、错误率 +3. **容量规划**:根据业务增长预测资源需求 + +**本节来源** +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +## 故障排除指南 +### 常见性能问题 +1. **元数据读取缓慢**:检查文件系统性能,考虑引入缓存 +2. **数据库连接耗尽**:检查连接池配置,优化连接使用 +3. **内存泄漏**:监控`ObjectMerger`的使用情况,避免循环引用 + +**本节来源** +- [ObjectMerger.cs](file://src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +## 结论 +通过对系统的全面分析,我们识别了多个性能优化机会。建议优先实施元数据缓存策略和`ObjectMerger`类的性能优化,这两项改进将显著提升系统整体性能。同时,完善数据库连接池配置和静态资源优化策略,为系统的可扩展性奠定基础。持续的性能监控和基准测试将是确保系统稳定高效运行的关键。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\346\225\260\346\215\256\345\272\223\350\277\201\347\247\273\346\265\201\347\250\213.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\346\225\260\346\215\256\345\272\223\350\277\201\347\247\273\346\265\201\347\250\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..1eafe0aabf7d95b96d47d3bd9d253cdb93d2f8c5 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\346\225\260\346\215\256\345\272\223\350\277\201\347\247\273\346\265\201\347\250\213.md" @@ -0,0 +1,316 @@ +# 数据库迁移流程 + + +**本文档引用的文件** +- [IDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/IDbSchemaMigrator.cs) +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) +- [MigratorDbContextFactory.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationGenerator/MigratorDbContextFactory.cs) +- [DbMigrationService.cs](file://src/Tools/H.LowCode.DbMigrator/DbMigrationService.cs) +- [HostedService.cs](file://src/Tools/H.LowCode.DbMigrator/HostedService.cs) +- [Program.cs](file://src/Tools/H.LowCode.DbMigrator/Program.cs) +- [appsettings.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.json) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) +- [RenderEngineDbContext.cs](file://src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs) + + +## 目录 +1. [引言](#引言) +2. [项目结构](#项目结构) +3. [核心组件](#核心组件) +4. [架构概述](#架构概述) +5. [详细组件分析](#详细组件分析) +6. [依赖分析](#依赖分析) +7. [性能考虑](#性能考虑) +8. [故障排除指南](#故障排除指南) +9. [结论](#结论) + +## 引言 +本文档深入讲解基于EF Core的数据库迁移机制,重点分析H.LowCode.DbMigrator工具的职责与实现。该工具通过DesignEngineDbContext和RenderEngineDbContext读取实体模型,生成数据库变更脚本,并支持自动化迁移。文档将详细描述迁移命令(如Add-Migration、Update-Database)的执行流程,以及如何通过代码调用IDbSchemaMigrator接口完成自动化迁移。同时,还将介绍MigratorDbContextFactory在设计时迁移中的作用,并提供从开发到生产环境的迁移最佳实践。 + +## 项目结构 +H.LowCode项目采用模块化设计,主要分为Common、DesignEngine、RenderEngine和Tools四大模块。其中,数据库迁移功能由Tools模块下的H.LowCode.DbMigrator项目实现。该工具独立于主应用运行,专门负责数据库模式的迁移和数据初始化。 + +```mermaid +graph TB +subgraph "核心模块" +Common["Common (公共组件)"] +DesignEngine["DesignEngine (设计引擎)"] +RenderEngine["RenderEngine (渲染引擎)"] +end +subgraph "工具模块" +Tools["Tools"] +DbMigrator["H.LowCode.DbMigrator"] +MetaMigrator["H.LowCode.MetaMigrator"] +end +Common --> DesignEngine +Common --> RenderEngine +DesignEngine --> DbMigrator +RenderEngine --> DbMigrator +DbMigrator --> Database[(数据库)] +``` + +**图示来源** +- [项目结构](file://README.md) + +**本节来源** +- [项目结构](file://README.md) + +## 核心组件 +H.LowCode.DbMigrator工具的核心组件包括: +- **IDbSchemaMigrator**: 数据库模式迁移的抽象接口 +- **EntityFrameworkCoreDbSchemaMigrator**: EF Core迁移的具体实现 +- **MigratorDbContext**: 继承自DesignEngineDbContext的迁移上下文 +- **MigratorDbContextFactory**: 设计时上下文工厂,用于生成迁移脚本 +- **DbMigrationService**: 协调数据库模式迁移和数据种子的服务 +- **HostedService**: 托管服务,启动时自动执行迁移 + +这些组件共同构成了一个完整的数据库迁移解决方案,支持从开发到生产的全生命周期管理。 + +**本节来源** +- [IDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/IDbSchemaMigrator.cs) +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) + +## 架构概述 +H.LowCode.DbMigrator采用分层架构,将迁移逻辑与执行环境分离。工具通过依赖注入获取所需服务,并利用EF Core的迁移功能实现数据库模式的同步。 + +```mermaid +graph TD +A["命令行/dotnet ef"] --> B["MigratorDbContextFactory"] +B --> C["创建MigratorDbContext"] +C --> D["生成迁移脚本"] +E["程序启动"] --> F["HostedService"] +F --> G["DbMigrationService"] +G --> H["IDbSchemaMigrator"] +H --> I["EntityFrameworkCoreDbSchemaMigrator"] +I --> J["MigratorDbContext.Database.MigrateAsync()"] +J --> K[(数据库)] +``` + +**图示来源** +- [MigratorDbContextFactory.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationGenerator/MigratorDbContextFactory.cs) +- [HostedService.cs](file://src/Tools/H.LowCode.DbMigrator/HostedService.cs) + +## 详细组件分析 + +### IDbSchemaMigrator接口分析 +`IDbSchemaMigrator`接口定义了数据库模式迁移的核心契约,仅包含一个`MigrateAsync`方法。这种简洁的设计使得迁移逻辑可以被不同实现替换,提高了系统的可扩展性。 + +```csharp +public interface IDbSchemaMigrator +{ + Task MigrateAsync(); +} +``` + +该接口的单一职责设计符合SOLID原则,使得迁移逻辑可以被轻松地测试和替换。 + +**本节来源** +- [IDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/IDbSchemaMigrator.cs) + +### EntityFrameworkCoreDbSchemaMigrator实现分析 +`EntityFrameworkCoreDbSchemaMigrator`是`IDbSchemaMigrator`接口的具体实现,它通过依赖注入获取`MigratorDbContext`实例,并调用其`Database.MigrateAsync()`方法执行迁移。 + +```mermaid +sequenceDiagram +participant Service as "DbMigrationService" +participant Migrator as "EntityFrameworkCoreDbSchemaMigrator" +participant Context as "MigratorDbContext" +participant DB as "数据库" +Service->>Migrator : MigrateAsync() +Migrator->>Context : GetRequiredService() +Context->>DB : Database.MigrateAsync() +DB-->>Context : 迁移结果 +Context-->>Migrator : 完成 +Migrator-->>Service : 完成 +``` + +**图示来源** +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) + +**本节来源** +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) + +### MigratorDbContext分析 +`MigratorDbContext`继承自`DesignEngineDbContext`,这是H.LowCode项目设计引擎的数据库上下文。通过继承而非重新实现,迁移工具可以复用所有实体模型配置。 + +```csharp +public class MigratorDbContext : DesignEngineDbContext +{ + public MigratorDbContext(DbContextOptions options, + EntityTypeManager entityTypeManager) : base(options, entityTypeManager) + { + } +} +``` + +这种设计的关键优势在于: +1. **模型一致性**:确保迁移使用的模型与运行时完全一致 +2. **代码复用**:避免重复定义实体映射逻辑 +3. **维护性**:模型变更只需在一处修改 + +**本节来源** +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) +- [DesignEngineDbContext.cs](file://src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs) + +### MigratorDbContextFactory分析 +`MigratorDbContextFactory`实现了`IDesignTimeDbContextFactory`接口,这是EF Core设计时迁移的关键组件。当执行`dotnet ef migrations add`命令时,EF Core工具会调用此工厂创建上下文实例。 + +```csharp +public class MigratorDbContextFactory : IDesignTimeDbContextFactory +{ + public MigratorDbContext CreateDbContext(string[] args) + { + var configurationBuilder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false); + var configuration = configurationBuilder.Build(); + + string migrationAssembly = typeof(Program).Namespace; + var builder = new DbContextOptionsBuilder() + .UseSqlServer(configuration.GetConnectionString("Default"), + b => b.MigrationsAssembly(migrationAssembly)); + + var services = new ServiceCollection(); + services.AddApplication(); + services.AddApplication(); + var serviceProvider = services.BuildServiceProvider(); + EntityTypeManager entityTypeManager = serviceProvider.GetService(); + + return new MigratorDbContext(builder.Options, entityTypeManager); + } +} +``` + +该工厂的关键配置包括: +- **连接字符串**:从appsettings.json读取 +- **迁移程序集**:指定迁移文件生成到H.LowCode.DbMigrator程序集 +- **服务提供者**:构建包含必要服务的DI容器 + +**本节来源** +- [MigratorDbContextFactory.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationGenerator/MigratorDbContextFactory.cs) +- [appsettings.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.json) + +### DbMigrationService分析 +`DbMigrationService`是迁移流程的协调者,负责按顺序执行数据库模式迁移和数据种子操作。 + +```csharp +public async Task MigrateAsync() +{ + Logger.LogInformation("Started database migrations..."); + + await MigrateDatabaseSchemaAsync(); + await SeedDataAsync(); + + Logger.LogInformation("Successfully completed all database migrations."); +} +``` + +该服务的执行流程为: +1. 记录开始日志 +2. 执行所有`IDbSchemaMigrator`的迁移 +3. 执行数据种子 +4. 记录完成日志 + +这种分阶段的执行策略确保了数据库在数据插入前已具备正确的结构。 + +**本节来源** +- [DbMigrationService.cs](file://src/Tools/H.LowCode.DbMigrator/DbMigrationService.cs) + +### HostedService分析 +`HostedService`实现了`IHostedService`接口,作为.NET的托管服务运行。当应用程序启动时,它会自动执行数据库迁移。 + +```csharp +public async Task StartAsync(CancellationToken cancellationToken) +{ + using (var application = await AbpApplicationFactory.CreateAsync(options => + { + options.Services.ReplaceConfiguration(_configuration); + options.Services.AddLogging(c => c.AddSerilog()); + options.AddDataMigrationEnvironment(); + })) + { + await application.InitializeAsync(); + + await application + .ServiceProvider + .GetRequiredService() + .MigrateAsync(); + + await application.ShutdownAsync(); + + _hostApplicationLifetime.StopApplication(); + } +} +``` + +该服务的特点包括: +- **自动执行**:应用程序启动时自动运行 +- **资源管理**:使用using语句确保资源正确释放 +- **优雅退出**:迁移完成后自动停止应用程序 + +**本节来源** +- [HostedService.cs](file://src/Tools/H.LowCode.DbMigrator/HostedService.cs) + +## 依赖分析 +H.LowCode.DbMigrator的依赖关系清晰,主要依赖于: +- **H.LowCode.DesignEngine.EntityFrameworkCore**: 提供DesignEngineDbContext +- **Microsoft.EntityFrameworkCore**: EF Core核心库 +- **Volo.Abp**: ABP框架,提供依赖注入和模块化支持 +- **Serilog**: 日志记录 + +```mermaid +graph LR +A["H.LowCode.DbMigrator"] --> B["H.LowCode.DesignEngine.EntityFrameworkCore"] +A --> C["Microsoft.EntityFrameworkCore"] +A --> D["Volo.Abp"] +A --> E["Serilog"] +B --> F["H.LowCode.Entity"] +F --> G["System.Reflection.Emit"] +``` + +**图示来源** +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) +- [MigratorDbContextFactory.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationGenerator/MigratorDbContextFactory.cs) + +**本节来源** +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) +- [MigratorDbContextFactory.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationGenerator/MigratorDbContextFactory.cs) + +## 性能考虑 +数据库迁移工具的性能主要受以下因素影响: +- **模型复杂度**:实体模型越多,迁移生成越慢 +- **数据库大小**:大型数据库的模式变更耗时较长 +- **网络延迟**:远程数据库的迁移操作受网络影响 + +最佳实践包括: +- 在非高峰时段执行大型迁移 +- 对生产环境迁移进行充分测试 +- 使用事务确保迁移的原子性 + +## 故障排除指南 +常见问题及解决方案: + +**迁移命令不工作** +- 确保在H.LowCode.DbMigrator项目目录下执行命令 +- 使用`--context MigratorDbContext`指定上下文 +- 检查appsettings.json中的连接字符串 + +**模型不一致** +- 确保DesignEngineDbContext的模型定义是最新的 +- 清理并重新生成迁移文件 +- 检查EntityTypeManager是否正确加载实体 + +**数据种子失败** +- 确认数据库模式已完全迁移 +- 检查种子数据的完整性约束 +- 查看详细的错误日志 + +**本节来源** +- [DbMigrationService.cs](file://src/Tools/H.LowCode.DbMigrator/DbMigrationService.cs) +- [HostedService.cs](file://src/Tools/H.LowCode.DbMigrator/HostedService.cs) + +## 结论 +H.LowCode.DbMigrator提供了一个完整、可靠的数据库迁移解决方案。通过继承DesignEngineDbContext,工具确保了迁移模型与运行时模型的一致性。MigratorDbContextFactory的设计使得迁移脚本可以在开发时生成,而HostedService则确保了生产环境的自动化迁移。该工具的设计体现了关注点分离、代码复用和自动化运维的最佳实践,为H.LowCode平台的稳定运行提供了坚实的基础。 \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..512294f0c8fc3d14bb5e7d6a2823d44ab81552a7 --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\347\233\221\346\216\247\344\270\216\346\227\245\345\277\227.md" @@ -0,0 +1,205 @@ +# 监控与日志 + + +**本文档引用的文件** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [H.LowCode.DesignEngine.Host.csproj](file://src/DesignEngine/H.LowCode.DesignEngine.Host/H.LowCode.DesignEngine.Host.csproj) + + +## 目录 +1. [系统监控与日志管理方案](#系统监控与日志管理方案) +2. [Serilog日志框架集成](#serilog日志框架集成) +3. [日志级别与格式配置](#日志级别与格式配置) +4. [健康检查端点实现](#健康检查端点实现) +5. [日志轮转与清理策略](#日志轮转与清理策略) +6. [安全与审计要求](#安全与审计要求) + +## 系统监控与日志管理方案 + +本方案旨在为LowCode平台建立完善的监控与日志管理体系,确保系统的可观测性、可维护性和安全性。通过集成Serilog框架实现结构化日志记录,配置健康检查端点支持外部监控,并建议使用Prometheus+Grafana进行指标可视化。 + +**Section sources** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +## Serilog日志框架集成 + +根据项目文件分析,`H.LowCode.DesignEngine.Host.csproj`项目文件中引用了Serilog相关包,确认了Serilog框架的集成。Serilog配置主要通过`appsettings.serilog.json`文件进行管理。 + +Serilog配置文件指定了多个日志输出目标(WriteTo),包括异步文件写入和控制台输出。配置中使用了Async Sink来包装File Sink,以提高日志写入性能,避免阻塞主线程。 + +```mermaid +graph TD +A[应用程序] --> B[Serilog Logger] +B --> C[Async Sink] +C --> D[File Sink] +C --> E[Console Sink] +D --> F["../Logs/log_.txt"] +E --> G[控制台输出] +``` + +**Diagram sources ** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) + +**Section sources** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) +- [H.LowCode.DesignEngine.Host.csproj](file://src/DesignEngine/H.LowCode.DesignEngine.Host/H.LowCode.DesignEngine.Host.csproj) + +## 日志级别与格式配置 + +### 日志级别划分 + +Serilog配置中定义了日志级别策略: +- **默认级别**: Information +- **重写级别**: + - System命名空间: Information + - Microsoft命名空间: Information + - Microsoft.EntityFrameworkCore: Warning + +这符合标准的日志级别划分(Debug、Info、Warning、Error),通过配置实现了精细化的级别控制。 + +### 日志格式配置 + +日志输出采用结构化格式,具体配置如下: + +**文件输出格式**: +``` +{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] [{SourceContext}] [{EventId}] {Message}{NewLine}{Exception} +``` + +**控制台输出格式**: +``` +{Timestamp:HH:mm:ss} [{Level}] {Message} {NewLine}{Exception} +``` + +文件输出包含时间戳、日志级别、源上下文、事件ID、消息内容和异常信息,为JSON格式的结构化日志,便于后续分析和处理。 + +```mermaid +classDiagram +class LogEntry { ++DateTime Timestamp ++LogLevel Level ++string SourceContext ++int EventId ++string Message ++string Exception ++string RequestId +} +class SerilogConfiguration { ++string OutputTemplate ++LogLevel MinimumLevel ++string[] Using ++WriteTo[] WriteTo +} +class WriteTo { ++string Name ++object Args +} +SerilogConfiguration --> WriteTo : "包含" +WriteTo --> LogEntry : "生成" +``` + +**Diagram sources ** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) + +**Section sources** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) + +## 健康检查端点实现 + +通过对`Program.cs`文件的分析,发现当前代码库中未实现健康检查端点(如/health)。在`H.LowCode.RenderEngine.Host`和`H.LowCode.DesignEngine.Host`的`Program.cs`文件中,均未找到`UseHealthChecks`或`MapHealthChecks`的相关配置。 + +建议在`Program.cs`中集成健康检查功能: + +```csharp +// 建议的健康检查集成代码 +builder.Services.AddHealthChecks() + .AddDbContextCheck("Database"); + +app.MapHealthChecks("/health"); +``` + +健康检查端点应返回系统关键组件的状态,包括数据库连接、缓存服务等,供外部监控系统轮询。 + +```mermaid +sequenceDiagram +participant Monitor as "监控系统" +participant API as "健康检查API" +participant DB as "数据库" +Monitor->>API : GET /health +API->>DB : 检查连接 +DB-->>API : 连接状态 +API-->>Monitor : 返回健康状态 +``` + +**Diagram sources ** +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) +- [Program.cs](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs) + +**Section sources** +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) + +## 日志轮转与清理策略 + +Serilog配置中已实现完善的日志轮转与清理策略: + +- **轮转策略**: 按天轮转(rollingInterval: "Day") +- **文件大小限制**: 10MB(fileSizeLimitBytes: 10485760) +- **保留文件数量**: 50个(retainedFileCountLimit: 50) +- **存储路径**: ../Logs/log_.txt + +该策略确保日志文件不会无限增长,当单个日志文件达到10MB或跨越到新的一天时,会自动创建新文件。同时,最多保留50个历史日志文件,超出部分将被自动清理,有效控制磁盘空间使用。 + +```mermaid +flowchart TD +A[开始写入日志] --> B{文件大小>10MB?
或新一天?} +B --> |是| C[创建新日志文件] +B --> |否| D[继续写入当前文件] +C --> E{日志文件数量>50?} +E --> |是| F[删除最旧日志文件] +E --> |否| G[保留所有文件] +F --> H[完成轮转] +G --> H +D --> H +``` + +**Diagram sources ** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) + +**Section sources** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) + +## 安全与审计要求 + +### 异常日志捕获 + +Serilog配置中通过`{Exception}`模板自动捕获和记录异常堆栈信息,确保所有未处理异常都能被完整记录。结合`{Message}`字段,可以全面了解异常发生时的上下文。 + +### 敏感信息脱敏 + +当前配置中未显式实现敏感信息脱敏机制。建议在日志记录前对敏感数据(如密码、身份证号、银行卡号等)进行脱敏处理,可通过自定义Serilog的格式化器或在业务逻辑中预处理日志消息来实现。 + +### 日志审计 + +建议实现日志审计功能,记录关键操作(如用户登录、数据修改、权限变更等)的详细信息,包括操作人、操作时间、操作内容和IP地址等。可通过在业务服务中注入日志记录器,并在关键方法中添加审计日志来实现。 + +### Prometheus指标收集 + +当前代码库中未发现Prometheus集成。建议安装`Prometheus.AspNetCore`包,并在`Program.cs`中添加相关配置,暴露关键性能指标(响应时间、错误率、数据库连接数等)供Grafana可视化。 + +```csharp +// 建议的Prometheus集成代码 +builder.Services.AddMetrics(); +builder.Services.AddMetricsTrackingMiddleware(); +builder.Services.AddMetricsEndpoints(); + +app.UseMetricsAllEndpoints(); +``` + +**Section sources** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) +- [Program.cs](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264.md" "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264.md" new file mode 100644 index 0000000000000000000000000000000000000000..f80ef3b449f3ef63dcdd4addd79252e9eab52a7a --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264/\351\203\250\347\275\262\344\270\216\350\277\220\347\273\264.md" @@ -0,0 +1,334 @@ +# 部署与运维 + + +**本文档引用的文件** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json) +- [appsettings.Development.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.Development.json) +- [launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json) +- [appsettings.Development.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.Development.json) +- [launchSettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/Properties/launchSettings.json) +- [appsettings.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.json) +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json) +- [Program.cs](file://src/Tools/H.LowCode.DbMigrator/Program.cs) +- [HostedService.cs](file://src/Tools/H.LowCode.DbMigrator/HostedService.cs) +- [DbMigrationService.cs](file://src/Tools/H.LowCode.DbMigrator/DbMigrationService.cs) +- [IDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/IDbSchemaMigrator.cs) +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) +- [MigratorDbContext.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/MigratorDbContext.cs) + + +## 目录 +1. [多环境配置管理策略](#多环境配置管理策略) +2. [数据库迁移流程](#数据库迁移流程) +3. [应用发布与元数据同步机制](#应用发布与元数据同步机制) +4. [Docker容器化部署方案](#docker容器化部署方案) +5. [监控与日志方案](#监控与日志方案) +6. [性能调优建议](#性能调优建议) + +## 多环境配置管理策略 + +本系统采用基于 `appsettings.json` 和 `launchSettings.json` 的多环境配置管理机制,通过环境变量 `ASPNETCORE_ENVIRONMENT` 实现开发、测试、生产环境的动态切换。 + +### 配置文件结构与继承机制 + +系统遵循 ASP.NET Core 的标准配置模式,使用主配置文件 `appsettings.json` 定义通用配置,通过 `appsettings.{Environment}.json` 文件覆盖特定环境的设置。配置优先级为:环境特定配置 > 主配置。 + +```json +// appsettings.json (通用配置) +{ + "ConnectionStrings": { + "Default": "Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;Trusted_Connection=True;TrustServerCertificate=True" + }, + "Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" + } +} +``` + +```json +// appsettings.Development.json (开发环境覆盖) +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} +``` + +### 环境变量与启动配置 + +`launchSettings.json` 文件定义了开发环境的启动参数,包括应用 URL、浏览器启动行为和环境变量设置。通过 `ASPNETCORE_ENVIRONMENT` 环境变量指定当前运行环境。 + +```json +{ + "profiles": { + "DesignEngine": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:5181;http://localhost:5180", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} +``` + +设计引擎与渲染引擎分别使用独立的端口(5181/5191),避免端口冲突。渲染引擎默认不启动浏览器,适合作为后台服务运行。 + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json#L1-L32) +- [appsettings.Development.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.Development.json#L1-L9) +- [launchSettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json#L1-L16) + +## 数据库迁移流程 + +系统通过 `H.LowCode.DbMigrator` 工具实现 EF Core 数据库迁移,确保代码模型与数据库结构同步。 + +### 迁移工具架构 + +迁移工具基于 .NET Generic Host 构建,采用依赖注入和模块化设计。核心组件包括: + +- **HostedService**: 托管服务入口,负责初始化 ABP 应用并触发迁移 +- **DbMigrationService**: 迁移协调服务,调用所有注册的 `IDbSchemaMigrator` +- **IDbSchemaMigrator**: 迁移契约接口,支持多数据源迁移 +- **EntityFrameworkCoreDbSchemaMigrator**: EF Core 具体实现 + +```mermaid +flowchart TD +A["Program.Main"] --> B["CreateHostBuilder"] +B --> C["ConfigSerilog"] +C --> D["RunConsoleAsync"] +D --> E["HostedService.StartAsync"] +E --> F["AbpApplicationFactory.CreateAsync"] +F --> G["InitializeAsync"] +G --> H["DbMigrationService.MigrateAsync"] +H --> I["MigrateDatabaseSchemaAsync"] +I --> J["IDbSchemaMigrator.MigrateAsync"] +J --> K["EntityFrameworkCore
DbSchemaMigrator"] +H --> L["SeedDataAsync"] +L --> M["IDataSeeder.SeedAsync"] +``` + +**Diagram sources** +- [Program.cs](file://src/Tools/H.LowCode.DbMigrator/Program.cs#L10-L40) +- [HostedService.cs](file://src/Tools/H.LowCode.DbMigrator/HostedService.cs#L15-L45) +- [DbMigrationService.cs](file://src/Tools/H.LowCode.DbMigrator/DbMigrationService.cs#L15-L50) + +### 迁移执行流程 + +1. **日志配置**: 从 `appsettings.json` 和 `appsettings.serilog.json` 加载 Serilog 配置 +2. **应用初始化**: 创建 ABP 模块化应用,注入配置和日志服务 +3. **模式迁移**: 遍历所有 `IDbSchemaMigrator` 实现,执行数据库结构同步 +4. **数据播种**: 调用 `IDataSeeder` 初始化基础数据 +5. **应用关闭**: 完成迁移后自动停止托管服务 + +```csharp +public async Task MigrateAsync() +{ + Logger.LogInformation("Started database migrations..."); + await MigrateDatabaseSchemaAsync(); // 执行EF Core迁移 + await SeedDataAsync(); // 播种初始数据 + Logger.LogInformation("Successfully completed all database migrations."); +} +``` + +**Section sources** +- [DbMigrationService.cs](file://src/Tools/H.LowCode.DbMigrator/DbMigrationService.cs#L15-L55) +- [IDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/IDbSchemaMigrator.cs#L1-L13) +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) + +## 应用发布与元数据同步机制 + +系统采用元数据驱动架构,设计引擎生成的元数据通过文件系统同步到渲染引擎。 + +### 元数据存储结构 + +元数据集中存储在项目根目录的 `meta` 文件夹中,采用分层目录结构: + +``` +meta/ +├── apps/ # 应用元数据 +│ ├── caseapp/ # 应用ID +│ │ ├── datasource/ # 数据源定义 +│ │ ├── menu/ # 菜单配置 +│ │ ├── page/ # 页面定义 +│ │ └── caseapp.json # 应用配置 +├── parts/ # 组件库元数据 +``` + +### 同步机制 + +设计引擎通过 `FileRepository` 将元数据持久化到 `meta` 目录。渲染引擎启动时从相同路径加载元数据,实现配置共享。 + +```json +// appsettings.json 中的元数据路径配置 +"Meta": { + "appsFilePath": "../../../meta/apps", + "partsFilePath": "../../../meta/parts" +} +``` + +该机制支持热更新,修改元数据文件后无需重启渲染引擎即可生效。 + +**Section sources** +- [appsettings.json](file://src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json#L10-L13) +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json#L10-L13) + +## Docker容器化部署方案 + +提供多阶段构建的 Docker 镜像,优化部署体积和安全性。 + +### Dockerfile 示例 + +```dockerfile +# 构建阶段 +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /app +COPY . . +RUN dotnet restore +RUN dotnet publish -c Release -o out + +# 运行阶段 +FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime +WORKDIR /app +COPY --from=build /app/out . +COPY meta /app/meta +EXPOSE 80 443 +ENTRYPOINT ["dotnet", "H.LowCode.RenderEngine.Host.dll"] +``` + +### 部署配置 + +```yaml +# docker-compose.yml +version: '3.8' +services: + render-engine: + build: . + ports: + - "5191:443" + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ConnectionStrings__Default=Server=sqlserver;Database=H_LowCode;... + volumes: + - ./meta:/app/meta + depends_on: + - sqlserver + + sqlserver: + image: mcr.microsoft.com/mssql/server:2022-latest + environment: + - SA_PASSWORD=YourStrong@Passw0rd + - ACCEPT_EULA=Y + ports: + - "1433:1433" +``` + +**Section sources** +- [appsettings.json](file://src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json#L5-L9) + +## 监控与日志方案 + +集成 Serilog 实现结构化日志记录,并配置健康检查端点。 + +### Serilog 配置 + +通过 `appsettings.serilog.json` 配置多目标日志输出: + +```json +{ + "Serilog": { + "Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Async", "Serilog.Sinks.Console" ], + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft.EntityFrameworkCore": "Warning" + } + }, + "WriteTo": [ + { + "Name": "Async", + "Args": { + "configure": [ + { + "Name": "File", + "Args": { + "path": "../Logs/log_.txt", + "rollingInterval": "Day", + "fileSizeLimitBytes": 10485760 + } + } + ] + } + }, + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Information" + } + } + ] + } +} +``` + +日志特性: +- 按天滚动归档,保留50个历史文件 +- 异步写入避免阻塞主线程 +- 控制台与文件双输出 +- 自定义时间戳和异常格式 + +### 健康检查 + +系统自动暴露 `/health` 端点,集成数据库连接、元数据加载等检查项。 + +**Section sources** +- [appsettings.serilog.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json#L1-L42) +- [Program.cs](file://src/Tools/H.LowCode.DbMigrator/Program.cs#L15-L35) + +## 性能调优建议 + +### 元数据缓存策略 + +在 `RenderEngine` 中实现元数据内存缓存,减少文件系统I/O: + +```csharp +services.AddMemoryCache(); +services.AddSingleton(); +``` + +缓存失效策略:文件修改时间戳检测或手动清除。 + +### 静态资源压缩 + +启用 Brotli/Gzip 压缩: + +```csharp +services.AddResponseCompression(options => +{ + options.EnableForHttps = true; +}); +``` + +### 数据库连接池配置 + +在连接字符串中优化连接池: + +```json +"Server=(localdb)\\MSSQLLocalDB;Database=H_LowCode;...;Max Pool Size=100;Min Pool Size=10;Connection Timeout=30" +``` + +### 其他建议 + +- 使用 `ReadOnlySaveChangesInterceptor` 优化只读查询性能 +- 通过 `QueryWithNoLockDbCommandInterceptor` 减少锁竞争 +- 定期执行数据库迁移以保持索引优化 + +**Section sources** +- [EntityFrameworkCoreDbSchemaMigrator.cs](file://src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs) +- [appsettings.json](file://src/Tools/H.LowCode.DbMigrator/appsettings.json#L1-L10) \ No newline at end of file diff --git "a/.qoder/repowiki/zh/content/\351\241\271\347\233\256\346\246\202\350\277\260.md" "b/.qoder/repowiki/zh/content/\351\241\271\347\233\256\346\246\202\350\277\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..396e4aad2ddf850523f200267e23a420779471fc --- /dev/null +++ "b/.qoder/repowiki/zh/content/\351\241\271\347\233\256\346\246\202\350\277\260.md" @@ -0,0 +1,309 @@ +# 项目概述 + + +**本文档引用的文件** +- [README.md](file://README.md) +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [TableColumnSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/TableSchemas/TableColumnSchema.cs) +- [PageTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs) +- [ComponentValueTypeEnum.cs](file://src/Common/H.LowCode.MetaSchema/Enums/ComponentValueTypeEnum.cs) +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs) +- [ComponentStyleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs) +- [meta/apps/caseapp/caseapp.json](file://meta/apps/caseapp/caseapp.json) +- [meta/apps/testapp/testapp.json](file://meta/apps/testapp/testapp.json) + + +## 目录 +1. [项目概述](#项目概述) +2. [项目结构](#项目结构) +3. [核心架构与设计目标](#核心架构与设计目标) +4. [元数据驱动机制](#元数据驱动机制) +5. [设计引擎与渲染引擎协作](#设计引擎与渲染引擎协作) +6. [模块化分层架构](#模块化分层架构) +7. [Common模块共享功能](#common模块共享功能) +8. [元数据组织方式](#元数据组织方式) +9. [学习路径与扩展能力](#学习路径与扩展能力) +10. [系统上下文图](#系统上下文图) +11. [核心组件交互图](#核心组件交互图) + +## 项目结构 + +本项目采用模块化分层架构,主要由 `meta`(元数据)、`src`(源码)和 `Tools`(工具)三大目录构成。`src` 目录下包含 `Common`(公共模块)、`DesignEngine`(设计引擎)、`RenderEngine`(渲染引擎)等核心组件。 + +```mermaid +graph TB +subgraph "元数据" +meta[meta] +end +subgraph "源码" +Common[Common] +DesignEngine[DesignEngine] +RenderEngine[RenderEngine] +end +subgraph "工具" +Tools[Tools] +end +meta --> DesignEngine +DesignEngine --> RenderEngine +Common --> DesignEngine +Common --> RenderEngine +Tools --> DesignEngine +Tools --> RenderEngine +``` + +**图示来源** +- [README.md](file://README.md) +- 项目根目录结构 + +## 核心架构与设计目标 + +该项目是一个基于 .NET 8.0 和 Blazor 的可视化低代码平台,旨在通过元数据驱动的方式实现应用的快速构建与渲染。其核心设计目标是将应用的结构、行为和样式抽象为可配置的元数据,从而实现无需编写代码即可完成应用开发。 + +系统采用领域驱动设计(DDD)理念,划分为表现层、应用层、领域层和基础设施层,确保各层职责清晰、松耦合。设计引擎负责元数据的编辑与管理,渲染引擎则根据元数据动态生成用户界面。 + +**本节来源** +- [README.md](file://README.md) + +## 元数据驱动机制 + +整个平台的核心是“元数据驱动”机制。所有应用的结构、页面、菜单、数据源、组件属性、事件等均以 JSON 文件形式存储在 `meta` 目录中。系统在运行时读取这些元数据,并据此动态构建应用。 + +例如,一个应用的元数据包含名称、图标、版本、支持平台等信息;页面元数据则包含页面类型、数据源、事件、布局属性等。通过解析这些元数据,渲染引擎能够自动生成对应的 UI 组件和交互逻辑。 + +```mermaid +flowchart TD +Start([开始]) --> LoadMeta["加载元数据 (JSON)"] +LoadMeta --> ParseMeta["解析元数据"] +ParseMeta --> GenerateUI["生成UI组件"] +GenerateUI --> BindData["绑定数据源"] +BindData --> HandleEvent["处理事件逻辑"] +HandleEvent --> End([应用运行]) +``` + +**图示来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) + +## 设计引擎与渲染引擎协作 + +设计引擎(DesignEngine)和渲染引擎(RenderEngine)是系统的两大核心模块,二者通过共享的 `Common` 模块进行协作。 + +- **设计引擎**:提供可视化编辑界面,允许用户拖拽组件、配置属性、设置数据源和事件。其输出为结构化的元数据文件(JSON),存储于 `meta` 目录。 +- **渲染引擎**:读取 `meta` 目录中的元数据,在运行时动态生成 Blazor 组件树,实现应用的展示与交互。 + +两者通过 `Common` 模块中的元数据 Schema 保持契约一致,确保设计时与运行时的行为统一。 + +```mermaid +sequenceDiagram +participant Designer as 设计者 +participant DesignEngine as 设计引擎 +participant Meta as 元数据 (meta) +participant RenderEngine as 渲染引擎 +participant User as 用户 +Designer->>DesignEngine : 拖拽组件、配置属性 +DesignEngine->>Meta : 生成并保存元数据 +Meta->>RenderEngine : 提供元数据 +RenderEngine->>RenderEngine : 解析元数据 +RenderEngine->>RenderEngine : 动态生成UI +RenderEngine->>User : 展示应用界面 +User->>RenderEngine : 触发交互事件 +RenderEngine->>RenderEngine : 执行事件逻辑 +``` + +**图示来源** +- [DesignEngine](file://src/DesignEngine) +- [RenderEngine](file://src/RenderEngine) + +## 模块化分层架构 + +项目采用标准的分层架构,遵循领域驱动设计(DDD)原则: + +```mermaid +graph TD +A[表现层] --> B[应用层] +B --> C[领域层] +C --> D[基础设施层] +subgraph "表现层" +A1[Blazor 组件] +A2[页面渲染] +end +subgraph "应用层" +B1[Application Service] +B2[DTO 转换] +end +subgraph "领域层" +C1[领域模型] +C2[领域服务] +C3[聚合根] +end +subgraph "基础设施层" +D1[数据库访问] +D2[文件存储] +D3[远程服务调用] +end +``` + +各层职责明确: +- **表现层**:负责 UI 展示与用户交互。 +- **应用层**:协调领域对象完成业务任务,不包含业务逻辑。 +- **领域层**:核心业务逻辑所在,包含实体、值对象、领域服务等。 +- **基础设施层**:提供技术实现,如数据库访问、文件读写等。 + +**本节来源** +- [DesignEngine.Domain](file://src/DesignEngine/H.LowCode.DesignEngine.Domain) +- [RenderEngine.Domain](file://src/RenderEngine/H.LowCode.RenderEngine.Domain) + +## Common模块共享功能 + +`Common` 模块是设计引擎与渲染引擎之间的桥梁,包含两者共享的核心数据结构与基础功能。 + +主要子模块包括: +- **H.LowCode.ComponentBase**:提供低代码组件基类,如 `LowCodeComponentBase`、`LowCodePageComponentBase`。 +- **H.LowCode.MetaSchema**:定义所有元数据的 Schema,如 `AppSchemaBase`、`PageSchemaBase`、`EventSchema` 等。 +- **H.LowCode.Entity**:实体管理与动态代理构建。 +- **H.LowCode.Configuration.Options**:配置选项,如 `MetaOption`、`SiteOption`。 + +通过共享 Schema,确保设计时与运行时对元数据的理解完全一致。 + +**本节来源** +- [Common](file://src/Common) + +## 元数据组织方式 + +元数据存储在 `meta` 目录下,按应用进行组织: + +``` +meta/ +└── apps/ + ├── caseapp/ + │ ├── datasource/ + │ ├── menu/ + │ ├── page/ + │ └── caseapp.json + └── testapp/ + ├── menu/ + ├── page/ + └── testapp.json +``` + +每个应用目录包含: +- **datasource/**:数据源定义(SQL、API、静态选项等) +- **menu/**:菜单结构 +- **page/**:页面布局与组件配置 +- **{appname}.json**:应用基本信息 + +元数据采用简洁的 JSON 结构,关键字段使用短名称以减少体积,如: +- `"n"` 表示名称(Name) +- `"id"` 表示标识符 +- `"pub"` 表示发布状态(PublishStatus) +- `"ds"` 表示数据源(DataSource) + +**本节来源** +- [meta/apps/caseapp](file://meta/apps/caseapp) +- [meta/apps/testapp](file://meta/apps/testapp) + +## 学习路径与扩展能力 + +### 初学者学习路径 +1. 阅读 `README.md` 了解项目背景与分支策略。 +2. 查看 `meta/apps/testapp` 中的示例元数据,理解基本结构。 +3. 学习 `Common` 模块中的 Schema 定义,掌握元数据规范。 +4. 运行设计引擎,通过可视化界面修改元数据并观察效果。 +5. 启动渲染引擎,查看元数据如何转化为实际应用。 + +### 高级开发者扩展能力 +- **自定义组件**:在 `H.LowCode.Components.Defaults` 基础上扩展新组件,并在 `ComponentPartsSchema` 中注册。 +- **新数据源类型**:继承 `DataSourceSchema` 实现新的数据源(如 GraphQL、WebSocket)。 +- **主题定制**:参考 `H.LowCode.Themes.AntBlazor` 开发新主题。 +- **存储适配**:通过实现 `IAppRepository` 等接口,将元数据存储从文件系统迁移至数据库或远程服务。 + +**本节来源** +- [README.md](file://README.md) +- [meta](file://meta) +- [Common](file://src/Common) + +## 系统上下文图 + +```mermaid +graph LR +User[最终用户] --> |使用| RenderEngine[渲染引擎] +Designer[应用设计者] --> |配置| DesignEngine[设计引擎] +DesignEngine --> |生成| Meta[元数据] +Meta --> |驱动| RenderEngine +RenderEngine --> |展示| User +RenderEngine --> |读取| DataSource[(数据源)] +DesignEngine --> |连接| RemoteService[远程服务] +RenderEngine --> |连接| RemoteService +``` + +**图示来源** +- 整体项目结构 +- [DesignEngine](file://src/DesignEngine) +- [RenderEngine](file://src/RenderEngine) + +## 核心组件交互图 + +```mermaid +classDiagram +class AppSchemaBase { ++string Id ++string Name ++string Icon ++string Version ++PublishStatusEnum PublishStatus ++SupportPlatformEnum[] SupportPlatforms +} +class PageSchemaBase { ++string AppId ++string Id ++string Name ++int Order ++PageTypeEnum PageType ++PagePropertySchema PageProperty ++PageDataSourceSchema DataSource ++IList~EventSchema~ Events +} +class EventSchema { ++string EventName ++EventTargetTypeEnum EventHandlerType ++string EventTargetId ++string EventTargetAction ++EventCustomLanguageEnum EventCustomLanguage ++string EventCustomScript ++IDictionary~string, string~ EventArgs +} +class SQLDataSourceSchema { ++string DbType ++string Sql +} +class TableColumnSchema { ++string Id ++string Name ++string Title ++bool IsPrimaryKey ++int Order ++bool Filterable ++bool Sortable +} +class ValidationRuleSchema { ++string Id ++string ComponentId ++string Expression +} +AppSchemaBase --> PageSchemaBase : "包含" +PageSchemaBase --> EventSchema : "包含" +PageSchemaBase --> SQLDataSourceSchema : "数据源" +PageSchemaBase --> TableColumnSchema : "表格列" +PageSchemaBase --> ValidationRuleSchema : "验证规则" +``` + +**图示来源** +- [AppSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs) +- [PageSchemaBase.cs](file://src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs) +- [EventSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs) +- [SQLDataSourceSchema.cs](file://src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs) +- [TableColumnSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/TableSchemas/TableColumnSchema.cs) +- [ValidationRuleSchema.cs](file://src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs) \ No newline at end of file diff --git a/.qoder/repowiki/zh/meta/repowiki-metadata.json b/.qoder/repowiki/zh/meta/repowiki-metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..939f7c1fae403c3605a7873d064064853e189cc0 --- /dev/null +++ b/.qoder/repowiki/zh/meta/repowiki-metadata.json @@ -0,0 +1 @@ +{"knowledge_relations":[{"id":1,"source_id":"68c38938-1ea6-4aff-b602-f7491d11bec4","target_id":"203a66f3-9cc8-41c3-9d34-cb84dc4d84e1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 68c38938-1ea6-4aff-b602-f7491d11bec4 -\u003e 203a66f3-9cc8-41c3-9d34-cb84dc4d84e1","gmt_create":"2025-08-27T21:42:52.9643252+08:00","gmt_modified":"2025-08-27T21:42:52.9643252+08:00"},{"id":2,"source_id":"68c38938-1ea6-4aff-b602-f7491d11bec4","target_id":"53dcfe8a-34fb-40f2-a47a-3b8a495f457b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 68c38938-1ea6-4aff-b602-f7491d11bec4 -\u003e 53dcfe8a-34fb-40f2-a47a-3b8a495f457b","gmt_create":"2025-08-27T21:42:52.9669347+08:00","gmt_modified":"2025-08-27T21:42:52.9669347+08:00"},{"id":3,"source_id":"68c38938-1ea6-4aff-b602-f7491d11bec4","target_id":"b95cc9b2-554a-4589-bbe4-a3bfb6fed2dd","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 68c38938-1ea6-4aff-b602-f7491d11bec4 -\u003e b95cc9b2-554a-4589-bbe4-a3bfb6fed2dd","gmt_create":"2025-08-27T21:42:52.9695784+08:00","gmt_modified":"2025-08-27T21:42:52.9695784+08:00"},{"id":4,"source_id":"68c38938-1ea6-4aff-b602-f7491d11bec4","target_id":"62c2f61b-d498-4f58-9b59-3580830c6560","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 68c38938-1ea6-4aff-b602-f7491d11bec4 -\u003e 62c2f61b-d498-4f58-9b59-3580830c6560","gmt_create":"2025-08-27T21:42:52.9716694+08:00","gmt_modified":"2025-08-27T21:42:52.9716694+08:00"},{"id":5,"source_id":"68c38938-1ea6-4aff-b602-f7491d11bec4","target_id":"dabc53e1-9ef7-4796-8918-42b5b9d8b678","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 68c38938-1ea6-4aff-b602-f7491d11bec4 -\u003e dabc53e1-9ef7-4796-8918-42b5b9d8b678","gmt_create":"2025-08-27T21:42:52.9742487+08:00","gmt_modified":"2025-08-27T21:42:52.9742487+08:00"},{"id":6,"source_id":"68c38938-1ea6-4aff-b602-f7491d11bec4","target_id":"e5fc9426-1569-40bb-b2bd-e1cefefe726f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 68c38938-1ea6-4aff-b602-f7491d11bec4 -\u003e e5fc9426-1569-40bb-b2bd-e1cefefe726f","gmt_create":"2025-08-27T21:42:52.9768752+08:00","gmt_modified":"2025-08-27T21:42:52.9768752+08:00"},{"id":7,"source_id":"779db891-224d-480c-a1f6-cd45f05ec24f","target_id":"be91fa0a-2dc4-4738-868b-55ecf9d024a6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 779db891-224d-480c-a1f6-cd45f05ec24f -\u003e be91fa0a-2dc4-4738-868b-55ecf9d024a6","gmt_create":"2025-08-27T21:42:52.9795383+08:00","gmt_modified":"2025-08-27T21:42:52.9795383+08:00"},{"id":8,"source_id":"779db891-224d-480c-a1f6-cd45f05ec24f","target_id":"e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 779db891-224d-480c-a1f6-cd45f05ec24f -\u003e e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","gmt_create":"2025-08-27T21:42:52.9821321+08:00","gmt_modified":"2025-08-27T21:42:52.9821321+08:00"},{"id":9,"source_id":"779db891-224d-480c-a1f6-cd45f05ec24f","target_id":"672e378f-57c8-4f6d-a79b-730b4780238c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 779db891-224d-480c-a1f6-cd45f05ec24f -\u003e 672e378f-57c8-4f6d-a79b-730b4780238c","gmt_create":"2025-08-27T21:42:52.9852865+08:00","gmt_modified":"2025-08-27T21:42:52.9852865+08:00"},{"id":10,"source_id":"779db891-224d-480c-a1f6-cd45f05ec24f","target_id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 779db891-224d-480c-a1f6-cd45f05ec24f -\u003e 295c6fd6-65f8-4c58-af2e-ab08d27d07cb","gmt_create":"2025-08-27T21:42:52.9878578+08:00","gmt_modified":"2025-08-27T21:42:52.9878578+08:00"},{"id":11,"source_id":"779db891-224d-480c-a1f6-cd45f05ec24f","target_id":"7246ad3a-a609-41e6-8dc1-da8275970ac6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 779db891-224d-480c-a1f6-cd45f05ec24f -\u003e 7246ad3a-a609-41e6-8dc1-da8275970ac6","gmt_create":"2025-08-27T21:42:52.9904412+08:00","gmt_modified":"2025-08-27T21:42:52.9904412+08:00"},{"id":12,"source_id":"6d7453ba-7542-47ef-bce0-c4dc101327b2","target_id":"bd8c617b-ae78-4032-937d-682fe7e7da0f","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6d7453ba-7542-47ef-bce0-c4dc101327b2 -\u003e bd8c617b-ae78-4032-937d-682fe7e7da0f","gmt_create":"2025-08-27T21:42:52.9936008+08:00","gmt_modified":"2025-08-27T21:42:52.9936008+08:00"},{"id":13,"source_id":"6d7453ba-7542-47ef-bce0-c4dc101327b2","target_id":"78e9f6aa-4c5d-4c0c-bcb8-8453feaa64cf","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6d7453ba-7542-47ef-bce0-c4dc101327b2 -\u003e 78e9f6aa-4c5d-4c0c-bcb8-8453feaa64cf","gmt_create":"2025-08-27T21:42:52.9962183+08:00","gmt_modified":"2025-08-27T21:42:52.9962183+08:00"},{"id":14,"source_id":"6d7453ba-7542-47ef-bce0-c4dc101327b2","target_id":"9baaaecc-9cac-47d4-a545-225ac807ccd3","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6d7453ba-7542-47ef-bce0-c4dc101327b2 -\u003e 9baaaecc-9cac-47d4-a545-225ac807ccd3","gmt_create":"2025-08-27T21:42:52.998851+08:00","gmt_modified":"2025-08-27T21:42:52.998851+08:00"},{"id":15,"source_id":"6d7453ba-7542-47ef-bce0-c4dc101327b2","target_id":"ddd86ca7-139f-4e74-a6fb-9c30d5dd0678","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6d7453ba-7542-47ef-bce0-c4dc101327b2 -\u003e ddd86ca7-139f-4e74-a6fb-9c30d5dd0678","gmt_create":"2025-08-27T21:42:53.0019401+08:00","gmt_modified":"2025-08-27T21:42:53.0019401+08:00"},{"id":16,"source_id":"6d7453ba-7542-47ef-bce0-c4dc101327b2","target_id":"b56a7e73-74b0-4c65-8370-64bf96d9fc3b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 6d7453ba-7542-47ef-bce0-c4dc101327b2 -\u003e b56a7e73-74b0-4c65-8370-64bf96d9fc3b","gmt_create":"2025-08-27T21:42:53.0056368+08:00","gmt_modified":"2025-08-27T21:42:53.0056368+08:00"},{"id":17,"source_id":"e8a7501d-f01e-497f-8f10-78d0c36dbbec","target_id":"2af2d914-b932-41c7-9c4a-1f0cfdc60c40","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e8a7501d-f01e-497f-8f10-78d0c36dbbec -\u003e 2af2d914-b932-41c7-9c4a-1f0cfdc60c40","gmt_create":"2025-08-27T21:42:53.0088219+08:00","gmt_modified":"2025-08-27T21:42:53.0088219+08:00"},{"id":18,"source_id":"e8a7501d-f01e-497f-8f10-78d0c36dbbec","target_id":"366036bd-0220-49f2-93d7-3cddf12e2540","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e8a7501d-f01e-497f-8f10-78d0c36dbbec -\u003e 366036bd-0220-49f2-93d7-3cddf12e2540","gmt_create":"2025-08-27T21:42:53.011973+08:00","gmt_modified":"2025-08-27T21:42:53.011973+08:00"},{"id":19,"source_id":"e8a7501d-f01e-497f-8f10-78d0c36dbbec","target_id":"44c1635e-bafb-4913-8696-95dd5b196c3c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e8a7501d-f01e-497f-8f10-78d0c36dbbec -\u003e 44c1635e-bafb-4913-8696-95dd5b196c3c","gmt_create":"2025-08-27T21:42:53.0146644+08:00","gmt_modified":"2025-08-27T21:42:53.0146644+08:00"},{"id":20,"source_id":"e8a7501d-f01e-497f-8f10-78d0c36dbbec","target_id":"a2546f28-856e-455a-8793-93bb03349eef","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e8a7501d-f01e-497f-8f10-78d0c36dbbec -\u003e a2546f28-856e-455a-8793-93bb03349eef","gmt_create":"2025-08-27T21:42:53.017287+08:00","gmt_modified":"2025-08-27T21:42:53.017287+08:00"},{"id":21,"source_id":"e8a7501d-f01e-497f-8f10-78d0c36dbbec","target_id":"a2051317-8410-4e35-a8a6-42dcf139c6e8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e8a7501d-f01e-497f-8f10-78d0c36dbbec -\u003e a2051317-8410-4e35-a8a6-42dcf139c6e8","gmt_create":"2025-08-27T21:42:53.0199283+08:00","gmt_modified":"2025-08-27T21:42:53.0199283+08:00"},{"id":22,"source_id":"23649ef6-2714-4508-8db3-da7c79f0758c","target_id":"a6823e8d-6215-466a-82f5-4894c0ebf4ff","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23649ef6-2714-4508-8db3-da7c79f0758c -\u003e a6823e8d-6215-466a-82f5-4894c0ebf4ff","gmt_create":"2025-08-27T21:42:53.0226108+08:00","gmt_modified":"2025-08-27T21:42:53.0226108+08:00"},{"id":23,"source_id":"23649ef6-2714-4508-8db3-da7c79f0758c","target_id":"f240d134-002b-4d5b-b243-3352574496bc","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23649ef6-2714-4508-8db3-da7c79f0758c -\u003e f240d134-002b-4d5b-b243-3352574496bc","gmt_create":"2025-08-27T21:42:53.0252414+08:00","gmt_modified":"2025-08-27T21:42:53.0252414+08:00"},{"id":24,"source_id":"23649ef6-2714-4508-8db3-da7c79f0758c","target_id":"87b9f03e-2fa1-460b-9cd7-7c9b1a540f3e","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23649ef6-2714-4508-8db3-da7c79f0758c -\u003e 87b9f03e-2fa1-460b-9cd7-7c9b1a540f3e","gmt_create":"2025-08-27T21:42:53.0277288+08:00","gmt_modified":"2025-08-27T21:42:53.0277288+08:00"},{"id":25,"source_id":"23649ef6-2714-4508-8db3-da7c79f0758c","target_id":"9217137c-b4e9-432e-8821-cc1cfecfa572","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 23649ef6-2714-4508-8db3-da7c79f0758c -\u003e 9217137c-b4e9-432e-8821-cc1cfecfa572","gmt_create":"2025-08-27T21:42:53.030347+08:00","gmt_modified":"2025-08-27T21:42:53.030347+08:00"},{"id":26,"source_id":"3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed","target_id":"a5be60ac-c5cb-4af1-9cfc-693a5cba35e9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed -\u003e a5be60ac-c5cb-4af1-9cfc-693a5cba35e9","gmt_create":"2025-08-27T21:42:53.0334819+08:00","gmt_modified":"2025-08-27T21:42:53.0334819+08:00"},{"id":27,"source_id":"3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed","target_id":"e3b30f07-1b92-49bd-8078-fe657fc7b881","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed -\u003e e3b30f07-1b92-49bd-8078-fe657fc7b881","gmt_create":"2025-08-27T21:42:53.0361255+08:00","gmt_modified":"2025-08-27T21:42:53.0361255+08:00"},{"id":28,"source_id":"3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed","target_id":"459a2113-22f8-401b-ab96-6aece5f7a9a8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed -\u003e 459a2113-22f8-401b-ab96-6aece5f7a9a8","gmt_create":"2025-08-27T21:42:53.038779+08:00","gmt_modified":"2025-08-27T21:42:53.038779+08:00"},{"id":29,"source_id":"3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed","target_id":"e2e2ed9b-ca7b-4806-9218-d12e9d0a39b5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed -\u003e e2e2ed9b-ca7b-4806-9218-d12e9d0a39b5","gmt_create":"2025-08-27T21:42:53.0413925+08:00","gmt_modified":"2025-08-27T21:42:53.0413925+08:00"},{"id":30,"source_id":"3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed","target_id":"c0913d8c-1c17-4764-9624-c2f356bedde7","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed -\u003e c0913d8c-1c17-4764-9624-c2f356bedde7","gmt_create":"2025-08-27T21:42:53.0445645+08:00","gmt_modified":"2025-08-27T21:42:53.0445645+08:00"},{"id":31,"source_id":"39c35184-e954-4764-8812-b1096f985fa1","target_id":"dedb4619-395c-4c14-96a2-4221606cf927","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 39c35184-e954-4764-8812-b1096f985fa1 -\u003e dedb4619-395c-4c14-96a2-4221606cf927","gmt_create":"2025-08-27T21:42:53.0471987+08:00","gmt_modified":"2025-08-27T21:42:53.0471987+08:00"},{"id":32,"source_id":"39c35184-e954-4764-8812-b1096f985fa1","target_id":"35dbaf11-1833-4a9c-840a-39d4976a19a6","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 39c35184-e954-4764-8812-b1096f985fa1 -\u003e 35dbaf11-1833-4a9c-840a-39d4976a19a6","gmt_create":"2025-08-27T21:42:53.0497958+08:00","gmt_modified":"2025-08-27T21:42:53.0497958+08:00"},{"id":33,"source_id":"39c35184-e954-4764-8812-b1096f985fa1","target_id":"aad8a2bf-f757-49c1-aaf7-7ca32a2cc846","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 39c35184-e954-4764-8812-b1096f985fa1 -\u003e aad8a2bf-f757-49c1-aaf7-7ca32a2cc846","gmt_create":"2025-08-27T21:42:53.0530008+08:00","gmt_modified":"2025-08-27T21:42:53.0530008+08:00"},{"id":34,"source_id":"39c35184-e954-4764-8812-b1096f985fa1","target_id":"868ef220-a297-4fb0-a5e0-382e83443de1","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 39c35184-e954-4764-8812-b1096f985fa1 -\u003e 868ef220-a297-4fb0-a5e0-382e83443de1","gmt_create":"2025-08-27T21:42:53.0559944+08:00","gmt_modified":"2025-08-27T21:42:53.0559944+08:00"},{"id":35,"source_id":"39c35184-e954-4764-8812-b1096f985fa1","target_id":"6a93a0c2-0e22-4aac-b5f8-af48c5df4f60","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 39c35184-e954-4764-8812-b1096f985fa1 -\u003e 6a93a0c2-0e22-4aac-b5f8-af48c5df4f60","gmt_create":"2025-08-27T21:42:53.0586299+08:00","gmt_modified":"2025-08-27T21:42:53.0586299+08:00"},{"id":36,"source_id":"39c35184-e954-4764-8812-b1096f985fa1","target_id":"7d6f2d5f-0063-42fa-8b17-51c320a8726c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 39c35184-e954-4764-8812-b1096f985fa1 -\u003e 7d6f2d5f-0063-42fa-8b17-51c320a8726c","gmt_create":"2025-08-27T21:42:53.0610623+08:00","gmt_modified":"2025-08-27T21:42:53.0610623+08:00"},{"id":37,"source_id":"be91fa0a-2dc4-4738-868b-55ecf9d024a6","target_id":"7efb18be-42a0-43c5-9071-793ae14345e0","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: be91fa0a-2dc4-4738-868b-55ecf9d024a6 -\u003e 7efb18be-42a0-43c5-9071-793ae14345e0","gmt_create":"2025-08-27T21:42:53.0653223+08:00","gmt_modified":"2025-08-27T21:42:53.0653223+08:00"},{"id":38,"source_id":"be91fa0a-2dc4-4738-868b-55ecf9d024a6","target_id":"7f4eb3e1-598d-4335-9db4-42b6f8884e26","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: be91fa0a-2dc4-4738-868b-55ecf9d024a6 -\u003e 7f4eb3e1-598d-4335-9db4-42b6f8884e26","gmt_create":"2025-08-27T21:42:53.0685165+08:00","gmt_modified":"2025-08-27T21:42:53.0685165+08:00"},{"id":39,"source_id":"be91fa0a-2dc4-4738-868b-55ecf9d024a6","target_id":"9a174422-341b-49bf-9737-68c0f3b8bdb8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: be91fa0a-2dc4-4738-868b-55ecf9d024a6 -\u003e 9a174422-341b-49bf-9737-68c0f3b8bdb8","gmt_create":"2025-08-27T21:42:53.0711517+08:00","gmt_modified":"2025-08-27T21:42:53.0711517+08:00"},{"id":40,"source_id":"be91fa0a-2dc4-4738-868b-55ecf9d024a6","target_id":"afc306cc-496e-4a79-885b-5e2a3ce5ce0c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: be91fa0a-2dc4-4738-868b-55ecf9d024a6 -\u003e afc306cc-496e-4a79-885b-5e2a3ce5ce0c","gmt_create":"2025-08-27T21:42:53.074309+08:00","gmt_modified":"2025-08-27T21:42:53.074309+08:00"},{"id":41,"source_id":"e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","target_id":"d96544fc-e306-40df-bb89-0b75226e938b","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e -\u003e d96544fc-e306-40df-bb89-0b75226e938b","gmt_create":"2025-08-27T21:42:53.0782155+08:00","gmt_modified":"2025-08-27T21:42:53.0782155+08:00"},{"id":42,"source_id":"e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","target_id":"25299769-7c0a-4c56-96c0-59a490d2bb25","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e -\u003e 25299769-7c0a-4c56-96c0-59a490d2bb25","gmt_create":"2025-08-27T21:42:53.0808054+08:00","gmt_modified":"2025-08-27T21:42:53.0808054+08:00"},{"id":43,"source_id":"e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","target_id":"364fde0e-2314-4e27-85ea-c6fbf237999c","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e -\u003e 364fde0e-2314-4e27-85ea-c6fbf237999c","gmt_create":"2025-08-27T21:42:53.0839398+08:00","gmt_modified":"2025-08-27T21:42:53.0839398+08:00"},{"id":44,"source_id":"e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","target_id":"5a86510c-4f6f-4b91-aa4f-cd2603b2d4c5","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e -\u003e 5a86510c-4f6f-4b91-aa4f-cd2603b2d4c5","gmt_create":"2025-08-27T21:42:53.0871112+08:00","gmt_modified":"2025-08-27T21:42:53.0871112+08:00"},{"id":45,"source_id":"672e378f-57c8-4f6d-a79b-730b4780238c","target_id":"1b85f38e-97fc-4e44-aa30-989a85c2fbdb","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 672e378f-57c8-4f6d-a79b-730b4780238c -\u003e 1b85f38e-97fc-4e44-aa30-989a85c2fbdb","gmt_create":"2025-08-27T21:42:53.0912866+08:00","gmt_modified":"2025-08-27T21:42:53.0912866+08:00"},{"id":46,"source_id":"672e378f-57c8-4f6d-a79b-730b4780238c","target_id":"3d72c130-173f-45db-9c86-5e237fbcb4d0","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 672e378f-57c8-4f6d-a79b-730b4780238c -\u003e 3d72c130-173f-45db-9c86-5e237fbcb4d0","gmt_create":"2025-08-27T21:42:53.0938816+08:00","gmt_modified":"2025-08-27T21:42:53.0938816+08:00"},{"id":47,"source_id":"672e378f-57c8-4f6d-a79b-730b4780238c","target_id":"92e0b8c5-3f1e-4dd8-b277-f452145fb591","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 672e378f-57c8-4f6d-a79b-730b4780238c -\u003e 92e0b8c5-3f1e-4dd8-b277-f452145fb591","gmt_create":"2025-08-27T21:42:53.0969721+08:00","gmt_modified":"2025-08-27T21:42:53.0969721+08:00"},{"id":48,"source_id":"672e378f-57c8-4f6d-a79b-730b4780238c","target_id":"ab5b8917-63b0-4ebd-b91b-0bedccd70d32","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 672e378f-57c8-4f6d-a79b-730b4780238c -\u003e ab5b8917-63b0-4ebd-b91b-0bedccd70d32","gmt_create":"2025-08-27T21:42:53.099655+08:00","gmt_modified":"2025-08-27T21:42:53.099655+08:00"},{"id":49,"source_id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","target_id":"8b57fbd0-087e-4c09-ba79-5218e329a623","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 295c6fd6-65f8-4c58-af2e-ab08d27d07cb -\u003e 8b57fbd0-087e-4c09-ba79-5218e329a623","gmt_create":"2025-08-27T21:42:53.1038209+08:00","gmt_modified":"2025-08-27T21:42:53.1038209+08:00"},{"id":50,"source_id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","target_id":"60c78c83-1a21-46ae-b6ce-44a88fa601b8","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 295c6fd6-65f8-4c58-af2e-ab08d27d07cb -\u003e 60c78c83-1a21-46ae-b6ce-44a88fa601b8","gmt_create":"2025-08-27T21:42:53.1064232+08:00","gmt_modified":"2025-08-27T21:42:53.1064232+08:00"},{"id":51,"source_id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","target_id":"0f76c6a1-57f8-4f43-b402-c4937982fec9","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 295c6fd6-65f8-4c58-af2e-ab08d27d07cb -\u003e 0f76c6a1-57f8-4f43-b402-c4937982fec9","gmt_create":"2025-08-27T21:42:53.1090608+08:00","gmt_modified":"2025-08-27T21:42:53.1090608+08:00"},{"id":52,"source_id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","target_id":"9bd29bc7-2900-466b-a317-283f9ac41226","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 295c6fd6-65f8-4c58-af2e-ab08d27d07cb -\u003e 9bd29bc7-2900-466b-a317-283f9ac41226","gmt_create":"2025-08-27T21:42:53.1117356+08:00","gmt_modified":"2025-08-27T21:42:53.1117356+08:00"},{"id":53,"source_id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","target_id":"d8e5d7df-fe8c-4f92-8832-8414126a1cea","source_type":"WIKI_ITEM","target_type":"WIKI_ITEM","relationship_type":"PARENT_CHILD","extra":"Wiki parent-child relationship: 295c6fd6-65f8-4c58-af2e-ab08d27d07cb -\u003e d8e5d7df-fe8c-4f92-8832-8414126a1cea","gmt_create":"2025-08-27T21:42:53.1147293+08:00","gmt_modified":"2025-08-27T21:42:53.1147293+08:00"}],"wiki_catalogs":[{"id":"4ce5331a-49f0-439b-a805-1d5b0672cc0e","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"项目概述","description":"project-overview","prompt":"创建全面的内容,重点介绍LowCode项目的整体架构与核心价值。解释该项目作为一个基于.NET 8.0和Blazor的可视化低代码平台的设计目标:通过元数据驱动实现应用的快速构建与渲染。描述设计引擎(DesignEngine)与渲染引擎(RenderEngine)之间的协作关系,以及Common模块在两者之间的共享作用。说明项目采用的模块化分层架构(表现层、应用层、领域层、基础设施层)和领域驱动设计(DDD)理念。结合代码库结构,阐述meta目录中元数据的组织方式及其在应用生命周期中的关键作用。为初学者提供清晰的学习路径指引,同时为高级开发者展示系统的可扩展性与集成能力。包含系统上下文图、核心组件交互图,并引用实际应用场景(如caseapp和testapp)进行说明。","progress_status":"completed","dependent_files":"README.md,TODO.md","gmt_create":"2025-08-22T22:18:36.9521624+08:00","gmt_modified":"2025-08-22T22:26:29.4503107+08:00","raw_data":"WikiEncrypted:0MI1/XkBoMl0lTbK6t0Cn/+8FdvqrJ62ianMLvZj02elJtBUgH0Ns0veIx1WPtM9wwkxI+/XAqHLxJLlHB8wV7ojrH0+b4JMz5OewwhBN1FRu9XO+QlojL6nQsImQgg+MrHOl+ukWOpTUzjh5Xdpj8HPqGvY3WPYGX7ZB6sYfNmJXliOiULL9WgRqNL6noxP05TvsKI3UsVnTPG8revHVNP6nQEwbL/4A+/P0pLiRFDC7yrO4vZZwGgrPt+Q6vZ8J/7xAqt4Cy9Cm8Rbc3FYuMU4heC9ehT1G8TwcK+Wemmr1JWL0kwOJl6bGz5p57bFCovkmBU2LzZ2c45zOkPmWYlptUkGK2EThldhnyouiPM2NHJ1BXZLrWvuNPaY0nBJZeZYQvlz8ZA9R623nWEGCfZeYOFCLUORQLr2ioasdpU+BGsaFjMhoJRL+sO9HhZOPn8bD/PXM9YaEzMmzNA0oYnz5937ZHlal4tApHa3tViV1eVqhBbm8vmbV8hDv/GmA1xYQOaa2PUbQ9UmYLd80mO3lJNt7BGeid2dgMkymSLMJAaGPiDOWT75a1v6rZoGqIvj5yUdgsWJWUmzTzyobcxDj2fWBhIbEOulDvjkWRLKMDf+DdYw47BgdtqkQ21trg6fVlJG3fS0YHlnRS01Be2LqLJ4oxaTCy4YLMEYCJx2+91OdaA7UaQBH+P0MIsz/jKs2nj6jb0co7yMdBJXxj3LF4ENAdQcrNPvhlx5yqtNjev9gaq1wfWP0u1tyR02NK1bJfGSre0makud/aFr9IKs1kLMnKfRwkrnjbqqFyRe2X4Ljoi8rCx5xw1O7u+dbyy7akYBEIPSMZX0HxsU2WROtq1yZtvSBZZj42GY2AQh48npRCXgyz5MJw2Fei14swlOskHJ5lonbVik1OVkUid+G2X+8hyfiq9WVPGS8GzpDD4SDY7Xoc2GeebrEc4rM0p0E3yeXbU29mmGNdDQN9hA3MA1ntQ3LkQw+328S8OtpDmRpqjKUJlR13+8xaNjtE1ANgmXHJwvUAwNtZGgIK7dPnvUcsKHnmxWkFOmAadwp100wYefp25/Al0/cgVZ1B2YvNM5wTWpdWhXdeHHW+tQzfHY9J8PYwiTbxib60DeA626sdcKVHrlizKl4pNlR5DFq4DF4GJdd+hB9mJsIyMoyJij0z03vCvxLO0WDz/hxhzayBBjj01oh7sCuYGQLH9rkKG1+LrE4ii9IS39zH8UMWwvhp0ATlsxDQV5XwUyIZttYhn3nLrItW3zAJMU/KrLEObgwzuPdnKvxiRcCFBBUj7KQx2rQEdFN0oSZQxoIaf2SJT4KAXtwV5gJhlnpUR0vWw0cGpnLkY3pda6trG3LrI/VcnnB4Afd9gUQV9meP+W6JZFZiEfVbh+pugv"},{"id":"c91fe434-c407-497c-b0a8-28a8d97f9bfb","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"元数据(Meta)","description":"meta","prompt":"深入解释元数据在低代码平台中的核心驱动作用。说明MetaSchemaBase基类的设计意图及其继承体系,阐述元数据如何通过JSON文件(如caseapp.json)进行序列化存储,并在设计引擎与渲染引擎之间传递。结合代码示例说明元数据的合并、校验与版本管理机制(如ObjectMerger.cs)。描述元数据的生命周期:从设计时配置、发布状态管理(PublishStatusEnum)到运行时加载。提供完整的元数据结构树形图,展示其作为系统配置中枢的角色。","parent_id":"2574726c-e59a-4bac-8854-59598d892537","progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs,meta/apps/caseapp/caseapp.json,meta/apps/testapp/testapp.json","gmt_create":"2025-08-22T22:19:14.0939913+08:00","gmt_modified":"2025-08-24T21:07:39.1910297+08:00","raw_data":"WikiEncrypted:ipiHJwUuYvCfl1rnNs2kD3L4xYR0PQCDr3mfEr883NxMhWMsXvaHfaDtVc/OlZTrgueC1yRnHooY4OuxGz9RUwTHiXyUnTt4MjpMiUE8YSpXoYloN2uGdL0qNu1GXzhxDjMTCFh9aR+Pw298EylFP0/mGDRxGNJNxoNHtHPaufBGvb1KtgrjMrEtBpmXhO/Ea4IsJjtKotqLkJ1+BSPxSbK2pqR3voMb2m+JsIN0Ug7IzaaaAEqcTyHhma7P6DgqfawxbaRlGohraOu4huC8B/XS9drOIviYinj4c09MNbUo32/CIicm05whyvr+Hl1WmOvdC4OTUZ5zuF2l94d+WgoPI2GrI6WZS2iiEeKcJ23BdVea3wbPpjghxVRzm8rW7iIJKDafgM2Paa6IP97MiNscts2/6gJnLr+E6EatTkKw57NhgH14FLg75tDrJ4yIoLql6TLuoRbQKhcXRSJZQMmViRg0BIQKyZPhN5TOu8DMoZs/ioHfMsCPdV/JJuVCiPLI4W/3u5wkk7T2TS7A9WYAolwyHsJ4RLB1WMq7M6Ox3t7KMY9DtGxSxmXK4mnDD998ur4RyvYdZYyustVyjp6J4F2u6lSB8JUGLQSJ2tW6LtnjA+byKrnAyI/bo9IK7BRrfRNi7fdA2lh7C+rQ6VEKBX/lQErBqDt9etdkgstc6mHU1ad7NcR6EudXTy+fDS0tUd687X4Wz3Ch8IpFeqZzalhqBxu3JVzwdxCYH7Txt+MP72BckMF1XZtQma1/LszCdlD9KFVxE/wzIMTCP1ZdIh1okbw6/G7KrH9N+4IbJVMISsqEHAKL5G74a9kXJJkPOhI+5x0FuqO5+KFkLIRuuQNuUJqoipeh4dKO3XwsiLtRYzbIv6cMZxT1SeFoQSiT0W9BHVt+gnO/TfI2E3ctYH5Kxtab9xkeQYjk5ifSHE/Y4QTSj4RTxGsh9IhuNJJyZgfjFqK3arxBu7BApXSOskNAUXMJHV7L78Jzh9YivXI+YxSas1h9epKa+xcKFKaUaSz77h4ZnDFi0sgkA8s3szs0kP8DFRCPVW8Qd46X5R3SbkJLTmAzZDv4KrJ3WG4obkXOoVQqFP1WufHEOg==","layer_level":1},{"id":"be52f1c4-850c-4443-ba95-8808d1e5b997","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"应用服务层","description":"design-engine-application-services","prompt":"深入解析设计引擎的应用服务层(Application Layer),重点阐述AppApplicationService、PageAppService、MenuAppService和DataSourceAppService的实现逻辑与职责划分。说明这些服务如何作为领域层与前端之间的协调者,处理用户请求、调用领域服务、执行事务管理并返回DTO模型。详细描述服务接口定义(如IAppApplicationService)与实现类之间的契约关系,以及AutoMapper在实体与DTO转换中的应用。结合代码示例说明创建应用、更新页面、配置菜单项和管理数据源的具体流程。解释服务间调用关系与异常处理机制,并提供典型API调用场景的请求/响应示例。","parent_id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs,src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs,src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs,src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs,src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs","gmt_create":"2025-08-22T22:19:49.6122986+08:00","gmt_modified":"2025-08-24T21:10:06.0900367+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAb5ZMDsxEcXfWLdzWsoQ5KgcdHGPwwpLSNNVqHJ9cLhs425HUm0GFG8XWaSllUxkzoG40IsD7K+28FMSfWCIBJM5GJJHxBK3IY0P6Lnhbb5J6AAhyoOXVIWw3Kqq6Ahqc0og+34sfYjL8vENvbW1Z/aYIfXYaBS3mdwGuIn47nFkLrDwrt2lHh8ENwvEdA3UB78oYaFmaWwiz1Q0HHDUak+3xpxAsr3epcJBsmgfTjrxyXGEknEs2gqg0UDCG2sUh6EYjVy1XQWRz17mW/yv2o5lXFP1jkPKbclTRX5z1aQx6w7nVQ3ASohe8jdMvRkRPZj+BRFqFouIjykTfTOeG29pNdEcZX2bCv/tAdITCrO+ZcRQLOFwxOtoCn/0B1xhi+y1vJcKlZSU4g0mnkX6zZbBqLRhpd1/rdejomcckY+Kek4Zy9Oiumj6XHEOYNQ9b7lhWbQdq6BOSLH0AFwhZW0C9B3vzOBnGfy3rZb53Pe8hwPVDx5Ohto/BQdOh5xP5RWn3YVsDbSegsr5dcLqEsBJTJtVWN2+QAnphWVg4gEZ0arZd1ZbZElKnx+l+qPLsHZnYrY2r7JB8VSy2L1bZ4Wr/rtk4sEWhOHTLDDr2GbZiZ6ioPV3xRSuLteXKYwICKEX1RSRi7EIq3dzCfzrrPC56Jk9woXT8J4lpF58paMEcRm+alZ4e4vm1QH0FsBNHGRiuaaPyz8Xn/m/6ZZ6x9ysijqbBjVKsrHFuX5vSCQR/qGjYyXBmcq+nvCgRvBbAftocRwufyTBmJjqOq5JL4sCzwgpY+P4XHsClliKyCfKAE3Odx2RzHmjX+nNT/IuOlukUYCIav5cmXfRvgRJgutlQjUkAXIDg+KXI7xT4Y+KJrHdkrxdVKuK57TcnmJVYP7OJEDLNqokqA8VBH5P/c4DPxhPkjvuuRxgwaIdw9gz+hDa16yCExOTCH5cJbBC7mNSSckqyQwdYztPErijN57UjTzf/HE0Zfs3/Lj25PlIUAfLnKXTPNq6R7YwnEX4fyO4N8/q5RTVFFqzadk6410fYqx5ztJhYgrLHUgfytMAEo2O8SCaQ2HDDJuKKriIAA5u/fpeANbKR/DRMmPUkkj6DOGPeVkgJc4DWmwOW8Ve8bC9fbWh3L6kxsTBsIAZBM672+9GxQwB3xC5p4EUWgP+czDGT+DePDAEeCmNs/r9iOGQhXIY/KSiOnhRbZJgRfQct9Ho3juGzHTZjM3zKPCWh29VFk+R1434XW8fWOTeFaE0p4TabqMqpJL7TyX5BUYvAhhD30ye+dxmkwPKQwaGS80sH3FXqZHHOBxqXhbUdPm9/QILSV3RVItI8dtTza+fcnS77+rHc2NBINKDU8ex64oLzNMu8W2B1qlCm3QNmGCQVSuiUk1nzCXUxeiTVPI7Jof+fQx4wWFEk99lUaxZbxQO+TAvgU1b+4QB30KmvWhbVuwABlvSqvjx4zpFpslwFJ0W6ietDiOKdydphA0RwkAh4leQZ7txqvYXL0Ck6OOAtPCYNZZDkiWKEHobjv7AX+mpDBO1LrqzjLfhvtH6ZYYFIIYhnURF7zK/98IGrkZvRA0enntXHeXYWdUxPdj2o4OqPjrpmJI/E5QLV4kvB2vv5nQWkE51xYCeitjkEKeW0zhuMZJX2OOfyPq41UjdpoeGAPiOTQA0SQt4NF+QTKAbOlQRtXroYuYwp8doB1xv5V6p9kkL4hj0Vr1Ff12JFrxU4qm38I1aaUgysKgEQK1YnP3EJYyNfglDUvDJtkbuGbbU6Xx65yKa6s8Mr4YUsan1/Lj44aQ7xWMXNvCQFNzVFKwiDPA3/RGNA1bczP1r5VSbu8y/g5ZJwqFcF6iHdAQQ6E14/SLPl/47Up2egcl089VNQmU+tsZNfJsKsM0YJPbswVbLffffQ/NOuUBuu8d8pHRkVfrjaanpWKD+hSkxfIYNxw47Xe1Zqu4VI","layer_level":1},{"id":"7107c49c-e77c-4166-aa50-ed136792a235","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"渲染引擎架构设计","description":"render-engine-architecture","prompt":"创建渲染引擎的架构文档,详细描述其分层设计:宿主层(Host)、应用层(Application)、领域层(Domain)和基础设施层(EntityFrameworkCore/Repository)。说明各模块的职责划分与依赖关系,特别是ABP模块化加载机制下的初始化流程。解释如何通过依赖注入整合MetaAppService、数据服务与存储实现。涵盖启动过程中的配置加载(appsettings.json)、数据库上下文初始化(RenderEngineDbContext)以及元数据服务注册。提供系统上下文图和组件交互图,说明请求从HTTP入口到元数据输出的完整路径。","parent_id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs,src/RenderEngine/H.LowCode.RenderEngine.Domain/RenderEngineDomainModule.cs,src/RenderEngine/H.LowCode.RenderEngine/RenderEngineModule.cs","gmt_create":"2025-08-22T22:20:13.2884522+08:00","gmt_modified":"2025-08-24T21:12:09.0202829+08:00","raw_data":"WikiEncrypted:237Hp7b+m+6V491ZOMBhPJcWOcYfUe8McuTZCHAa3Ym5vXv/IETN//R9X3Fh0OwUOiblYjdhlZM2wTjpwCszyrBGb/0fHtgsxrfozJOtJzkNJz4Jt351QpmwGsdb5dKe8pewY6jtQ3Qf+py7Oe6xYVBMEhpX8Kx2XyPt1tB24ka7abu0lkllroC2ZLIerI/CvGBJBrmV9+jmBiLhp77yYDIb60icVdboMd8YNp+kr0/sfeqiru+KkwSLSJlKEnQbH++/DG0uZZVJqv5sxtoObZ1j4uKGaZEDZ7xUmWtKVyMddqrqmQPkFUJF5ZWBRuF3V3RFDyldROIT1/Wd50qVIcF5LPsm9OH96uAZ6368JwMEKvOWdx4aLdf4oRw4yG3TLkSIsDMqIyaKSMT1K4m3DdAMA/ZvJ5aZDyHHClLgJtWFCPTKrzDLLIcF69uZY3GQBkRCjTQLhbIJbxkMpXUlBNGfebdQpancGE42k80dWQExJkqFhOdvUKUwR3hyQeddpHaUFvYPqNXVXNIS+hcM+BlteD4lOyouV8aBybykMAk7pXZtJVnRs/34yzZZ1Q93TDMuxkyXPb3Jvh18GYFTS/TnjiTxvunLonE6/jm8ymgRAay3OWr4CjBUDX5s0OvKG2txWiEGEmFTT8wdu5MFk4kMOqVXdsCNlyeOUMoKHJp+cAW6T6eZ+W6KxV32z6PncxPGxi3k0H3PnBVJBDjZSSiYSpdi6yDodX3FGAqLMvj9ygV3Ya4vF0AuPxwyILFUtOjlhFjlUfcXp5i3J8DpNfVOIfuelKPyWTFG6DEThxHNuyVrBVaZrMnHilokHVry66556gNWM18YPg+28hebGac/Ins0h2mkVcgmJzWT1IIOcFoDJCm3XkhjjABVhgXPRMmLoYr2+KbBNul07LnAbJp5idD/SXUU3ZwEMNEAuHfWCyybOGgp62RUgKhDDhpi+6XR0WfGYdHqnrc5jkZxqELk+siA57YB4yekBXB0vHHdppi41txpogM0PHSF9HpASsXI0kvRjO4v2lHHhPWn7GDdrUHz6AYFtsDCKXwEvEdeZeYmU1lKkSKLWhqARlwQI3Ka08foGX+8azdpoX4UMFd/w2g8EuiSuMqOnxcoYF5xOptCRNuw8Gk2dC6lEBzoUn0lC54MJ/oQ/XZN3ikFfpeFWOXd4qsgbpew5rPYrz9+ElDS7Sb54J0um/zRAUkrA9qsnDb9fr8Ko52IZPWiFWkOFVB9G4ZqjwHRCjJmZJT/sBfzD9C15XX8ipc2uSPF5M/ppenS+8Mh7OrqnRHDkTwkGrLaHIw8mVsebYvj+Dni2DBvon0ezv6Sm1HQoG2imxhDPrPeupSlVIWB6X71FA==","layer_level":1},{"id":"dd4fca38-9892-4566-919f-c085a60e4f8c","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"应用元数据结构","description":"app-meta-schema","prompt":"详细阐述应用元数据(AppSchema)的结构设计与实现机制。解释AppSchemaBase类中定义的字段,如应用ID、名称、描述、发布状态(PublishStatusEnum)、支持平台(SupportPlatformEnum)等属性的用途和约束条件。结合meta目录中的caseapp.json和testapp.json实例,说明元数据在JSON序列化后的实际格式。描述应用元数据如何被设计引擎写入和渲染引擎读取,并与其他元数据(如页面、菜单)建立关联关系。提供完整的JSON Schema定义,并举例说明如何通过API或配置文件扩展自定义字段。","parent_id":"8aaaca53-5075-4175-a837-be8548ca26c8","progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs,src/Common/H.LowCode.MetaSchema/Enums/PublishStatusEnum.cs,src/Common/H.LowCode.MetaSchema/Enums/SupportPlatformEnum.cs,meta/apps/caseapp/caseapp.json,meta/apps/testapp/testapp.json","gmt_create":"2025-08-22T22:20:55.7848282+08:00","gmt_modified":"2025-08-24T21:13:59.3612691+08:00","raw_data":"WikiEncrypted:Psd2PAUn7U1fsjlFi8lxezoQ5L6ueRuKQsBhhTExyNRgdBF2avXzuLmhnTYNrCzDZmGvFmgX9FMzeGrpOlSwwP2BBiY2CWw3Vh9UfuTBXdpRlweJY8h7pfijAL2qGU58cDSDTQKtHYf0ZzVucNcjM1W/dz/zszFQ5tlqxBHD/EIGSEmorxFdfUrQ4xxkw3df7wjmiP0l8taOXBdpDtbcu+37Ts36RwlQRY7M4MRGn3vhlFNwL83lKo3UOhi2/P7+EJHGRGdFAOy1Hd50a8tfg88NGkxc55JIHjm+gzVvpGQReqhyRoZ23Ppx+rp+IDmWlgaWYzovE1+TtgViDcR50zz+d3svuBUzq2sN5LaxmT9umTymxGOxywHSzYGO7jSOKoBJAo9vUUtizb/KZiJng2pGfCGsk1jliPvVH+e1bz+f7y+ciGZbB9VqaqVte0jWRF/ozNk/HceWLZHuIiwSaekKGrgUJa7Y3z5X1+Bd/ZJGOjUtFIzQBKODVeSzW8kvzU+6gOZXmRYZ0AnKSGclz+NoV3teYerdVGNf/t6bHLHhUpEur+4T1L88xvi+V+Sgr1yiucpSXdvlXBK01sgxrIv+6NxVsdk6whtp5Zl2hCoiqLUUpnjdvwBhPuH1/crWWtDM94a5wGZ4vhpxIHaxO3rz9ZOGqrEDE1hGhO1t1GGQQpM/QLS8btnOYxdMJHsgn3kbQ8aIeS91GCWzip1a0vwovfC2hg0bgiH+GFq77KUJwzxVclGhZ4E5YHDSqZyerOeAsFHj2dzqKlTXZ0gjkQW3Bosl0IcY4adhu7UOwk6hhY6XOqeCGPnQIK6Bu8J8HsudGZy8edrpfHapgVPtMZiV1FkfuRbRjN7caDBP7ZxAklHDWsl4QeKWt5DfwDUN9NsnvwxGLfCIP714ZmeQBk+NueH7P97t/JK4q4T8LFky/Pj6VvoR/FZuhY1Cnbt4g1Xgs90G+/xAEdMMnJumOpBRagy66BJRJRm5xgaIHklKWTcL7US6l2YfzyGZWVv01SIml9wkBiRxkk64Xv/vRs/3/2iXFf3OsqJlAP3GD6NBxyLhTndap2tTPQWRVr23uwWSs2Xe8yNWKktwcxeQAo2JxARXhapg7083XKVUoOuUU4pyEqpI8XCIHOk6FyjgIsYxVRlAn1kKVwmRk9UP3tMPfRXvHgCxjulEWz2jF95px1iJpxyFvKBBb45+/SlohyW/WlbJoyfdfErJ2fcZ3TYnGjjcyGvHk3XsDrNl1ljHK6HoqhDRpmS7vPrS6/499710z8P3+eMpXAx1LBjLLU4m3aRm9gACrPo+KWqioSTMVC4BwwBN0VZ4GUrY3Ydcz8cjths2m57YzQlVXX509w==","layer_level":1},{"id":"181a7e87-3336-43f0-9838-c9aa9e51900d","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"自定义组件开发","description":"custom-component-development","prompt":"深入讲解如何在低代码平台中开发自定义组件。详细说明ComponentPartsSchema的结构定义及其与ComponentPartsAttributeDefineSchema、ComponentPartsEventSchema的关系。解释如何通过ComponentLibraryAppService注册新组件元数据,并在设计引擎中实现拖拽支持。提供从元数据定义到前端渲染逻辑绑定的完整流程示例,包括属性分组(ComponentPartsAttributeDefineGroupSchema)、样式配置(ComponentPartsStyleSchema)和事件响应机制。阐述组件碎片化设计(ComponentPartsFragmentSchema)的优势与实现方式。结合PartsDesignEngineModule说明组件面板的加载机制,并指导开发者如何调试和验证新组件的集成效果。","parent_id":"1e1f9cb3-49a3-430a-b3cd-3b2dd4bb2603","progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs,src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs,src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsEventSchema.cs,src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentPartsAppService.cs,src/DesignEngine/H.LowCode.PartsDesignEngine/PartsDesignEngineModule.cs","gmt_create":"2025-08-22T22:21:28.1469581+08:00","gmt_modified":"2025-08-24T21:16:15.0643159+08:00","raw_data":"WikiEncrypted:VrTOMK0P24YINQ3w81YokQ3ploDggpzAyJ0ZA0KNdOiV47rhj5z1KqSd1ZnOJIAZCA4vXZHFwWltUQaS4vdrWDEaIzzJvvTlP0hid62Dfxf99aipFJmopNLFgUPCC0bWJYa8PfmQc/0IXrYt5xYNYgHyyPhTIvBQmPglR64WFPwyHeuivgGZ7zeK8LmLAlnjtkA/b365wdTf4TOkE4ZcyDjPh97ldJzOBrd9qi+gOoqQbhyFFT5kcxkK+RsQldqpxomty42q+OdxWCoCRvH2xoBeY45Wy5u15JAJ+5KYKalHyVVerSPkzKNQ+YFF3+0lOuyfxl1WnWgbFCQN7/TQDNLD6KLpea3XLeOPGAvBCAGIRbn0hM/K5xkL7H54uPLyTjywbpeADG1SBkyTudiMPmv9PNJ22A5ZValce/DLRrSil7RRAgabkd/YtgN9xwMvGbg9d1gwCN/tIbW/qlIlmVA5C3KYRfA6RVuKXFOl6RFyQCeNJgYrEjSnDaLzmyT0jExzHcx4xu8g4OabFN3ugG+AcxLUQJyLqkiEvKxN5aoKOADfWYea7rYDXOQRpCW7drY08rJ2wed0zKcpjTTEr4yfpncnf/vj7Ug1/yQ6mMOFSx9RKbgzxhDpRKOeW7Fft0xryJ/ZYxXcT3/vFU0L7mZcz7CPNBij7JteK6XrNpcxX5dsJJ3LRjf3KNVTp7Cep4llm2ULi6eJ0mmR3xtnDcj3hSWMybi9BpQyZZ4K40SN7XkqhiI0g+9F58zC743dISeL4d81+z0z4p+bozTIoKNx+4P8XPOKpM+5MjEbpQi+6Uh/fqEIyr/F4nSl5y1WXo4swrHz4miAVEN+FyFGfwEaAV87DUyUrxRtBRNnkJU2ds7v/4xiXSKKV0Xla0EuHeLDO/jxKXqknr5gcQ6FLc+LKyJC7Lt+ZMgEUORACzuaupBx87P4L9B54eY0sQiH+t3a4f0AZlDvkAuuwZvzzNVxNBEeZqFmNeS84rp7NJbcn4vQ1JnfO3mJ2yRKPWj7Rf3pu+04vim14rb3natPzotPS2cIY2n0zBE5QbFRiNSgoBushE5CNOw7pIPj30pI6OEPKcSChcnxuyol2wknKS5eyIA+6IXfCvTw2B3aQrlUS7FPVsPFLR179+MCGkYTpookurDskAFUEMVYzWSGh+LKLu+TS1JRTsX+mg/ArtIykGr9zFQYHXsiOfI1kVjKQ/enK3sPtitHBMi9VgZkRHpQ0ZL+135oBaYN74V5aRiRhLM99BBcL3STEwWMK5u2vrZiv+pEc3I4wmXysxNXZVmbjJG2q81Z34iA7rgju4qgtDTuFqs1UymcaEAPFqqusjUc1uylAuQZzfnwXCPXCmQr+SgtOEZGuQ9insXLudrPGUNZwZZX1is6NV7rbkK/tAz/kvGvi6/bn/tbmSTWdviakww9ZfSdt1m8anOs55WeZrCDw8dbKpZatWfV5rCylurogJ0CnB6HDohy5CXlMzKt20BBSX8FyWGDYH4ZKslFwAI0AmAXl4+kwpMVzuh+DDzSed140Yb++oGH68vo2OU58j/Tl1ouHUMP2FAkrkdR/7w0QC0N1DoR9z9H2BHua41ne7eNIghT776Pzh1rdZuwCjCWRosVtjovrQ5Cx+6DXTv2U96tnBzzZgI9iA7AZ3V0w1I4txvrZWj72coMVcJxOq6MD6Hz2d56B9ccFh6IqcayLDAhC1/QTrm3PPP2entz+lyMXgYIfTb60FKDkWNUdKEpczVrobNItKraJDaS2w5cfRxO5aoGd2PEVzjiPpXoWVdbaXWeglhBmzedhg==","layer_level":1},{"id":"5f2e137a-01a9-4e46-b8f4-e6693fedc472","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"环境搭建","description":"environment-setup","prompt":"编写详细的开发环境搭建指南,涵盖.NET 8.0 SDK的安装与验证、推荐IDE(Visual Studio 2022或VS Code)配置、项目依赖还原(NuGet包恢复)步骤。说明如何启动DesignEngine(设计引擎)和RenderEngine(渲染引擎)两个宿主服务,包括端口配置、启动顺序和前后端联调方法。提供常见环境问题的解决方案,如SDK版本不匹配、端口占用、HTTPS证书错误等。包含验证环境是否成功搭建的检查清单,例如服务是否正常启动、页面是否可访问、元数据是否加载成功。","parent_id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs,src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs,global.json,README.md","gmt_create":"2025-08-22T22:22:00.1269733+08:00","gmt_modified":"2025-08-24T21:18:04.7066685+08:00","raw_data":"WikiEncrypted:mJFb0eo+82adP8NAeq7d4LBCxC5w9J+0Fo3COLpkFPtchA2M23BEYjMx3U/os1FqhftXGYTEHLIXsC6Qr/8FaA1TXUrzFzx2qPATlj0F+d19SMXrufZ/+QACQ927Cd1jb+7L9LcEBYD9YGAeF6mfU8rr631Lyyf2B5GY7slTF1qvpsI+LINoHvAnp1jgh1e3h29fIabIGPtd5bRn1bh+F/aVidD9tx1R+lXNaVMD1ZKsOFSZvDsDCGdTs64HF8wIz4eFx6cgKDfaCitSr/4QH6JF9rDkRY4McjLwl6PLvxxsAkzhfKagEcLV4z5u2rQaymKdIeh/phVO9okvZhOhhui+1lzlrJW6irx6dZsHZCUobM+/Pdx+Wq/tIosaOsRI3kxjIo5BOpBeNqvVCPlcCdpKBuQHeGEM0NuSdKK3qYkSnIs9TddkzoIWKVZ9+z1OwIwjl5Rsx1/cXa+aHjo/ELNILQ/iqzLSpz7U6SQYzTbnbnkIg5fw/rHORzoVoLGqlsccr5BWttgWB7xCSagWSZVKsobeqq8dkvO8RP7y3UYc8Ku0O19PNXVeQR4BcndTaR9x2XcSRjhTqzCeYjMSju83EXvfv2LtiqPnAlFMgOL5uc42sDYyWsiCCz+gzt1F1+uvgItyWSk7GGM9+W8bj8r0zMMP+kv3NlVNKD2j/oQL6408geh2tcBLkdQkmBqNpQA1aKrXyHl3xvHx84/PNieMOJbsYorcKP1ZLGQGSYJUNKAoV+rHlAcCoq4FLXVqYyJng81pqjWy86HID0I/xfXjCI1NGpzlfCka3kJzvGn/+uN2XXbnaX5lnSulXea3uSPGvVyCmQDbxl+5N91ED+Ufw3HtUYZA/2q8bOAbzQgajGZPGBw82MoR4lkjvKZs7WvFTAI76kIf6scLh5OGHe9j3D+SByvE/nJfwZAM3HYHiH852FulgQ4lEeXCNOZp2FJ3siFKzOfTNRdrT0k5H5LUEcl/M9ilHIGVrO5R6IKRmsJGdpuUY51C3gZ/v632R2NSjq+J9SgYjnsg3IxTppy0GHNIGMl9UU4Ge1mPwapJHRjBr0RkCocyCuPMAgECh91m20Uxst3FAuZrz36/qjIKu5b+aRPRmixlrU4K65PGdj2qALPADsbDf+BRBCYfFHN/MwfrfWfuOm9dhGvkOPtBzEURNAqalrd6/a2E9JM=","layer_level":1},{"id":"12a7dbc7-c445-4d73-93b8-fe711309acf6","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"多环境配置管理","description":"environment-configuration","prompt":"详细说明本低代码平台的多环境配置策略。解释appsettings.json作为基础配置文件的作用,以及appsettings.Development.json等环境特定文件如何覆盖基础配置。分析launchSettings.json中定义的启动配置、环境变量和调试设置,说明其在开发环境中的作用。对比设计引擎与渲染引擎在配置结构上的异同,阐述如何通过环境变量(如ASPNETCORE_ENVIRONMENT)动态加载对应配置。提供配置项分类建议:敏感信息(数据库连接字符串)、运行时参数(API地址)、功能开关(调试模式)的管理方式。包含配置加载优先级、热重载支持、配置验证机制等内容,并给出实际代码示例。","parent_id":"87d35f84-473c-49f7-8192-185a0a489619","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json,src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.Development.json,src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json,src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json","gmt_create":"2025-08-22T22:22:31.0439444+08:00","gmt_modified":"2025-08-24T21:19:46.3911462+08:00","raw_data":"WikiEncrypted:mJFb0eo+82adP8NAeq7d4PvS+Rjh9QHdTsA6hOFISIE2OpV7GSZFqTgDV0ZOxmnSlUZYzkhAMkOWSqdeJpon3MB+7wDHcF6tqtZ+/rHA+WMuIYrFhfbR9tT7xn4Y+UPzZncazEsqAcTDFHZJHyrORPsFDHS7W8lNJ2oREjjx+hd2MSv0m80Qox4/hiORw9XzRka35aL0EAD+RALfbV0CJ4QIqWoWoa3nVJKpb1GhQrerNwl1KTdje+iXB6g66oQea337MbYkUXMpTIaBoJKOKVHqClOAqOACOYJoz/czs5Aa9r3oF9FgyaIXiCY1/+nF+1LdIeJKbYHC/b3V5+IUWRbygNvSwksHeasP0nCRmfEbUZizYJV9J5kPe18uReuc79icLAo+sbU4UK75qpbzYnGSm8aAbZ9o+XhX27CcM1EEPPO6DKJk4SVFuTnZ6HQkzvntsBjAFCoAyCvOgnkmeoB7BdVZvmNdbzKA8n2n2MuwdcE5+6KWysEsN44VTEG92mSOB0QEjyn7h6KlQPR0nnSQHoDLun9G819SYt++qPetvzVZuDJ0AbpXMd5jxC7uNO5pENdGe78FcKKot5/+JXV2PFyEnf98j+gieJbC88GBsgC4xLJhmO7/l2Op+axC265BNrAG9zjbL0VcqQjOtm67gPeyADODrsVcfwnVEZqmNWggYiFwpO3DZIg8apyhDzKJuBbAUpqaRZneC2wX7u+zykwHuaZcD8bz47vsRXNFEsLHwlwVtEDkCdrOoqyuUZxS6WoNBSSzqeJiuECDAKyGCi/dYXa1ctauUKP+ZZm1jkFAzExzDa4AvES8pk/CWCqota1jpjChwc1HJDt323ECqycx8wAvmEa3Tbh8vRmfcZLg3nNtcmEWZC31qUXbiT5kstCf5tdH0xfYhcOVr5dh1V55gcMc6j+fI4z0KljFYICHrLDu4M4A5WiXVXiYOvRjTmqJXy0bmpOWIgYkhPEZLjjvawh8CWD2sBhUyMnKNDYyHRea7JDMM2wzNKOfZmwdDBGpVuOn6hQBp+P910flkiKUs60T5CjZ7RwwsEpXT8vkTKPrNSvInaN3Kb+Bx5sdfiCOZDmw+FlT3tinLky//OcYU0tEK/y+kLnT60URArwq0R7EWss/KQTcJ6xb9UDU0d3FIpeHWQ/vtsgK8yewcVTfC8hjPU2h8o4YdU07bc5o7FiBkNX4bEbNq7vL54x66+aegwq/Ruy1DH66jc7whWsWUorKIOdH2ZaJV8euGhJwySc36zgSB9qBF9tFIizPYXTXswYevAQqxoU6yPvNWvVajuEZcuUomuvQDDVhAobcOoKi6i/qvWVTvhUDPtm+7I5nkLjUEqLHdVWJ+IWTzcBti2wYc4HQg4jxFEOSiAqIguwyi6uPzOzQJmOnE1mGNGPvyT9KvG2shBqYEbqArLcKFww7EN3a7GyO6+6c5cSO2rVS2mfOVnj+ED9dFWoZ5w1Mwpe7zHHxodNmC0SdOrHmTtY0YDkRNGavsrjXMgqrp6N8I0GDw8Rb540GGaDw5tcpwa3k0SYNBJn3bMSIgqVcrZrbeAJ3JEX0/aI=","layer_level":1},{"id":"b855cf0a-08e5-4801-a00e-adfb1366fe60","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"应用管理服务","description":"app-application-service","prompt":"深入解析AppApplicationService的实现机制,重点阐述其在应用生命周期管理中的核心作用。详细说明创建、更新、删除、发布和查询低代码应用的业务逻辑流程,包括与IAppDomainService领域服务的交互方式、事务边界控制以及应用元数据的持久化策略。解释服务如何通过AutoMapper将App实体转换为AppListModel等DTO模型,并处理多租户环境下的应用隔离。结合代码示例展示创建新应用时的参数校验、唯一性检查和默认配置初始化过程。文档需涵盖接口契约定义、异常处理模式(如应用不存在、名称冲突等)、权限控制机制,并提供RESTful API调用示例(如POST /api/app/create)及其请求/响应JSON结构。","parent_id":"be52f1c4-850c-4443-ba95-8808d1e5b997","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs,src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/AppServices/IAppApplicationService.cs","gmt_create":"2025-08-22T22:22:55.1498802+08:00","gmt_modified":"2025-08-26T23:26:44.7149042+08:00","raw_data":"WikiEncrypted:CRyLPL98HjHCACMUI2CbRKABnOzjbIxT4yuy4zYT55UFYoQPH/LC5jAt0+qqVu1Ka9wxlKOsnxN++Us5mZaFcDxDeIVPEtjlmzLX6Ah1wkj5dXGClw4YsAUfYTcLoSNYxspifQZ3toywGqLfvCwY07KjMWjSi8hriQvujRk18JgOPe9ILmY5xGVbK4NpPfrz8VoSPEo8PFXDRgHWPvjoNsepcLa0YniLXee9dSswyf9cIBvvICutNTxLYigNobxAw7ZyK6mpkEP/B6cOjBqzH5t311zIXRExhblmQctOljmxUiwVYorNjzgpvNA+jK+bW/ac1wsiwt/CfwMtjQyAhcDAL1AKCAZgUpvpirMgbOsiA4dV1O05OFbC5vG8y+W96mnXs1Hyywq5voqEp+I2fY2lM9Elz3PuwUxai0ZDglQoOmPi/TDZz24E68VO568Fo4QgTYcP1c3XmwVIYHR2x80cpAecboaBBPRNS1yR2BzuK7tppqwCN0QCuFwXTBbHgVayf+jxUJcXFIs8DY72eRdst59Cj8Y401Ue55quhyr4eTz6wyXFCyavkGpXQn2VRXlZi2GzYNU75DoJP0lk4zZJyoayywrqqE8sQKSFsmR3LIuqE6W4OPpVuJ+bnkORoBV/4D0YBGv44Ozl9rYp2euGlEVxdshqOlpj3460MB6IqZAIj5IjZ2Ca5NRzW6pzu/cDiT5vhsaU5Yvyn5jZHu0pYSazeKqBkfHOxvdn9lFMN64OWUpfyRV3UxgN9G5swaHKb8MN6F3m9IIAvOKLSZvI0Jyjr73ikQWZGvsG8RjCR7FZ+YmLJtxBem807P2EtrN928LsVAVZYD2vO9taBg+FJX9LuGwC3sK0JJYYXwsQhWDrXaHn+qwc57ruFoQFg/rpc+U/+CCQwMmqjA3ZoxTo9QXmWRT40+i2E9gcZDp0TVmefgeSN+HOQtxgTjrXJ3xf7AMoCsufbAZV1N3dgf6U0K6GqIbk499ZsIMLDV81nvrpaH3hIwWTfD7phRPXPapVaj70xv2r1E0BVcki6ZnuCklxKm/TlT+EmrI2IMIJrprVRjsLHQ9xD59SDXV5dncbGvRfGL8g2OY47VMeLtYs/2Wi1Fcp4qDPAaOjeQdVXd2x2Jx3MFTC7yOg/C3zgRcRNZZHCoiQKbDoHgmsZcd2pWJv7du2oHem935UvAr8tOn2n8YS5xRItl7m6gfzqNTtrSyRkeOJeO7Y3lgfs6c8S44iUe7XCoBN21Z110hI+2/ifqmwbOhBUxVTrNY4cwIoubDP/fcf5m0vryGZOl5dfLQzBMb2g5exwMOLtJhXaokpAANliSHp6bZuWLgiBAXVM8ANM9ue9cQ4DAS5X5tcTsP+iiDGFqS/NsS5OB0S28lKx330ivlN/jPHebzCvK1ghIczOk1L9G6JNvwpa4QlEazmw13+l/QeW8DMadm0ArXKN6T11WPtS83AjGl2MXzQ/v85Tvwps37/bKWxulTwxBMmAKHvPnp+/RJrKi0=","layer_level":2},{"id":"8b6b6943-fb5f-4ee2-ac0a-f92d0b6128ae","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"应用领域服务","description":"app-domain-service","prompt":"深入解析AppDomainService的实现细节,重点阐述其在应用生命周期管理中的核心作用。详细说明应用创建、更新、删除及发布状态变更过程中的业务规则校验逻辑,包括应用标识唯一性检查、元数据完整性验证和状态流转控制。结合代码实例描述App聚合根的构建过程,以及如何通过IAppRepository实现持久化操作。解释领域服务如何协调应用与关联实体(如页面、菜单)的一致性维护,并处理跨聚合的业务约束。提供异常处理机制和事务边界管理的实现方式,确保数据一致性。为开发者提供调用该服务的最佳实践与性能优化建议。","parent_id":"e52a6571-a012-4e2a-b5d2-e5f94c01d367","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs,src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs","gmt_create":"2025-08-22T22:23:24.285957+08:00","gmt_modified":"2025-08-26T23:28:36.9866127+08:00","raw_data":"WikiEncrypted:LJHl9pztjdPxIjEqOpz6K9OI7mOd3njcQAsXuzoS+lSTPvUiM6kA59ZzijlztXn02B7kc5kiwDY94qB4HYNVNsVFJSk0XXc2glkW38c0TywORUSUHaEhEDTXmg2R5DYM+Zf7fQWphNqyyeFIGOKF8OaTU/98Cxii++pku60wZ2KBjAKIcF/QoYRIT3FStzugtQFLCgsHPRzc3IND/Q1caqvoZxJ5QiEVyZE/tCJ0ppuy+fIlja8tY5bkGHWK/3HRL7Gvl9uiGGDRFWPnE1syO7pU3Q/0tSdeIUTGrOrlYJqzFUCmA0rjnuH7oqZL8xAeXZgEBLq3K5XExK/2/36WatX/Vi9gAN27LcQNRmxjNdzs4SPv8qsPiNQR32wu/9GjGbMwvVhbBDJjWOO7bNotEP15WjRjtDGJjqzNolOc5m0Cm50fbjpGZhQ/ZZkGwoxXZaHt8sg3XAjc8I3fBtsg2PP2jSXoKqMpiF0EilDxSRn3oQMpCfptOmqgxS/hoLBcbWFjXXOsx2JozEvcqqtMJGSstV13PQnHL0DJgBu6GFaj1hYxYnbSScu+P4jbd+DHUJ0+lm13rwbdghsLtKQgnBDdPRI8WGfuneQnZMTTIp4YUxIeWn1DpcrSyyn3j8gqCcWqp91LhIa5zTmD7dxhSP6SIfF4o/eGETYFo201t+/bn5E9gvlE37IId3F35GPdQ1wxWv8eRJGEd3R37I1+d3r0HQmyEakYFVS01Gp+uNtsqR0G6CFzgBBxJVGx5occ5wTXIoxXZ3IO69haXPguGid7by4ipoy6r9isigLqFW+3wyliCNati6NMvUXDo8UJqYhQNzjmpxon8mVdE2O2Vs9CjKwKCx8cCdwDAedIQ4hRUYqi8v6wlpqyVMSCaLNgQVRCoMv+SDt/MP58EWe3oUjd8I4qFawR0J7inkvsqnUhnAcR4pZMoUCxG0rkq1L4pdLM4OnTj+5ZOGsKOzO3ExluJLQejCyCzXiwS+UQZG/7Wqt2bsKeLnk04PcRx9Eiya/ZX5zugWIkOObNXMGboZcvckyfYTOsUeWElzAbgbeKH2zMOp6tdeArdUrCXD1KAZ+jCAsXKiPK2D+/oLz2rBDlTH/t3mcDL0L1TgMbxLxGyWpYRPcp4XVSxuBgaYeJ/cGk0ukBiTyfMhvXiAO6HTjEtJElUgFkiiSiUV9ih8jb+uki7gZJ6EAVbHI1xR92fMk3UVwqnK1dEtFnph5m15tvWFSWzjMuNdhcKS18sKRVhiIGTNc2SXJJCCkPiFJCXr5qdETbDYxr4wwhwUijNLUlU2v+i4YURAVlp2vhD09MP9RnuzdKj9at4NvpMKbim24hQJA917CMUs9VXSEM9pMLsk2mzSRnHGfC4V2XTaDCXpMz+d2GsABGHqZfruZ/H2ctmUmDhdhvGybXd7VmC0i8Xgm+GHNwHbXYIUsgKvE=","layer_level":2},{"id":"000e986d-7fe8-4380-9e19-31b9b9d2cc93","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"JSON文件仓储实现","description":"json-file-repository","prompt":"深入分析基于JSON文件的仓储实现机制,重点阐述FileRepositoryBase作为所有文件仓储基类的设计原理,包括元数据序列化、反序列化、文件路径管理与读写异常处理。详细说明AppFileRepository如何实现IAppRepository接口,完成应用元数据在meta/apps目录下的持久化存储与加载流程。解释PageFileRepository、MenuFileRepository和DataSourceFileRepository对各自领域对象的文件操作逻辑,以及如何通过约定的文件命名规则(如GUID.json)维护数据一致性。提供JSON仓储的性能瓶颈分析、并发访问控制策略及适用场景建议。","parent_id":"d3062028-65d4-43ea-a57e-3d6daeb99be8","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/PageFileRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/MenuFileRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/DataSourceFileRepository.cs","gmt_create":"2025-08-22T22:23:50.8326526+08:00","gmt_modified":"2025-08-26T23:30:45.6564165+08:00","raw_data":"WikiEncrypted:AVAOdQjLI+XtwglRpHmEtety4E+fKBim9V3g6yXwNCQfvFqhfNlc2yBTpHcAC+cCU35RGqv0tglECbZhBy8ybPA7DA2+EHRAb+dMJLOCDuBwOPpFIyeWEKwPIPVHH9JdInRRCJRY0UNa5rfM02tQa8imTZO2AVemtAdnBvUse/kCHm7zyehqFPqsSslSg9kOKnsiMYPOBk7i1YE+ku8CvsCHmhsZ777d+Nok+XVf122VtCJloVYJCzur7NFEueyMjLYCKJMPkEnsHC48RHaSHrUkir7URipq4U0f/8YPYYPvdwSEFp1VCaOtkJsAoLEPC5jsEGBtqcMnzkGE9lcSB8LaYjygbWreTgzlbRUtHXOtVRu3gP5/i7nnxqjjdEPK+6YfFPgVzwt389eO8MAzNwN/KsY5ywLNEWo+WSAnIzRI3TkOouiXz7JPqcN7t/TwNJmO3O2XQP47xuGDzR+iflYfH1h+Z8bh75KDwVlvFtDcrguy1GZ0qgJO8muBPFTQQjlvv9NxdDrFrKhY28F7znLWitNnq8T8ReHRDr+UYlRau39Esl6CrJW6+NjybDwiu+k4ZX3sFHbcaeuEHO7Dt1c8bcUwaRWHHb3VzPH1DV+vyPwVzwHhPjr8CtxkaKO6DCU904B0wvVr9CZX8wR86I6Q994JiiNBSj5AicN1N5HS6fqmmQRCf0SFsUmdtBXtMmK+hij6G+8sp8j486Ww7IDZjVuMaE8Ic/czuszWp4rhFVcrg21w3h7d97U7HkESJUTayj8xHmtC0roNHGNs9miqKn0bfMCYFFxalaqtZfyQCJ3uGODmJ+wKvoUfISdAjuvSWGD9/Zc76PI3uU+7fKNxdhOLHFlKpAUkoz3Nc5JClMW6GtB4fwHq08ahfneJw8URws+sH1p0gBgnSmtLgmZP/GJO6mI/tGKn8Oc2dHhiP/uG62j1dyof22i4z4MamIDMtvB+xD0vOpjPExVEOXqF2NOh9fbFaejn4udeVan23L9+1xOx0j8+J1W9aGjpyBuV8QWRrS9UgIzCRAfwXQMv7L6+NhWHbzlHcsXJxGjQDa5FTP/6etaGQFx1hoD4cbmI/rVOylksGwIrYnJMg3KHxNBcN7SDQMsa3l5FFpduE4pxNDzO9UsBSDQNjxZ/UEzr292SpqrVEWd8wRV9ZS0Tc7dJvtss29dhaJmcByvXvFfmq2yKKw6qW21HvwBOktTgmjFNCqDmuNA3BzXIyG2p+3epgMVoB9WJSDkFsnUnzhZqqTflUMnPtpyPJzPb7+nLZ62Rrfpmc0gssh6eIHQzneQ2udDbiA80Y0EM3MNMTrYDSyuZv9x5+MVnf9e5XLTzt6Nk7NTv7xrt6VWAQzHIugAijgMjBhCQGGJWD3j6N8gL5D6g/XAIUsLJEjshrVbzYjnkbNdTuVE3pBfOCbrcX35TOH5hVllWPJOPLt9gA/vJnEPMSg8gJXf57qVN0RDO+VRlP2k/OMeBNqyrD1KBCd0x/WBGORdyxYszzDGr66kT9KYtDuYC1DvfkQb3P8fa2mZQNO/BYziTxDBOMwxYFjbwsmOMSi055Y233HpaIcZcG+R2a8djGYCjoFfM4/ZjnHxTeGnX7GG8yEGlwqp5PQJX8ngZfPbNmLdEBFk0cINShIrMivk59MX2bM0O5aoNZKfZqhu66tMQlgiP0IKArlw4zKvuYrP4PCT7Cca4VvtBcsOtl6F0svxEeFGX","layer_level":2},{"id":"561256df-d655-4d28-9bcf-d05100719c92","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"拖拽项视觉设计","description":"drag-item-visual-design","prompt":"详细说明DragItem.razor.css中定义的CSS类如何控制组件面板中可拖拽项的外观与布局。解释样式规则对边框、阴影、过渡动画、悬停效果的实现机制,并结合Blazor组件模板分析其与DraggableItem组件的绑定关系。提供实际样式应用示例,展示不同组件类型(如表单、容器、按钮)在拖拽面板中的视觉差异化呈现。阐述响应式设计考量及在高分辨率屏幕下的适配策略。","parent_id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css","gmt_create":"2025-08-22T22:24:15.1241192+08:00","gmt_modified":"2025-08-26T23:33:13.5016607+08:00","raw_data":"WikiEncrypted:+FpslUp3zw4PdI+nRbHmfsTkN0i5r20bXhQNKLUbNWIfL0bUyQXX0SG1DKbOPciRaaGNaWN/kSHLffeuFsWGapGOqsy+jfNkm2zApQyU3hjTg+wQ8atiskcOsGU3Ig9G9PwU/m6gBUXzSd86Negf5R2GFxon7MOsX0j+JD3Lj0uVvFkyPVuDPlWmNSHRYE2DbLANvLP9ofl46EwgRSCvJeG7ppH/2BoFW65pg6Q5RZol4wBlI3uNJJ3Ef3xzqKgXHuBAMnJVN9U5eNvAlvD+I10SPGbOUJfJrRG81gBN4D1cL4U5tRyS+Z+6qU/z6f8570sJSZ6bJCIt21NORGHGs0r1G1btcW1c8t25mT0uaHT4RuFbRUYonaZm3BmZSKKmIAge4xLez05hU7NI7uCM8SPnMtZKwCbzL/IkGjwZADx9GesqvhmK+kFYN73MbrqhMn0mR3kfjkUyctDsqy0bXq36bOJTTYGyV0ZNpBu3Fg3sDzMKqd+RjTh207+RgrcqrlaaX2BEcpCH2mMHqDyDZ98HCzjiiVRv/WSOCBjQgIV5Uh0NJH8kn0Ci5baS3JszxchezDD4tIBeP7x+7+8147MgnI8ijIwbQBHfOI4HhIohQbVVrfBpszU4jNSu7TuEJrD9PWMs91fgniJ35OY0l+hVe99cCeAQaRak2qWP4R0gt1orpZwyPZs73zrumJXKV43JwxOcgN281mtKeJJojBUsqECq608tzqi4wBX/7ib7SJaEowFvU3f/gk7XRMvSQfBv2i4re7RAWw/abeyL7wlqdkKvW1e1o0Vmya1QB0w3NgUH6FZZM4iT6QzjuR8OQJXwv+nS31fb7WyFYAy26V9c6DZhrEKORVc0dvhdepANre1zaYejCe16XLrnwOZOwcIWZ4TfDxLI8Re5kDrU/aIZYPlH2x5n0iqjd9ZmiH4IQ3qv0DyjIBqQmMvJdJKI","layer_level":2},{"id":"8d73d789-bb4d-48ca-b28c-4969413d3977","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"技术栈与依赖","description":"technology-stack","prompt":"详细说明项目所依赖的技术栈与外部组件。重点介绍.NET 8.0作为运行时环境的优势,Blazor框架在前后端统一开发中的角色,Entity Framework Core用于数据访问的实现机制,以及Volo.Abp框架在模块化、依赖注入和领域服务中的应用。列出主要NuGet包及其版本,并解释选择这些技术的架构考量。说明JSON文件存储与数据库(通过EF Core)两种元数据持久化方式的技术权衡。涵盖前端样式处理(CSS隔离)、JavaScript互操作(如elementUtils.js)以及构建工具链的配置。提供环境兼容性矩阵,包括支持的操作系统、浏览器和开发工具版本。","order":1,"progress_status":"completed","dependent_files":"global.json,src/Common/H.LowCode.ComponentBase/H.LowCode.ComponentBase.csproj","gmt_create":"2025-08-22T22:18:36.9547016+08:00","gmt_modified":"2025-08-22T22:29:01.1277966+08:00","raw_data":"WikiEncrypted:w0CkdCdnXCcvlN5xOpiEhEX3U68GI0Ngj6azFMJo9xQD0Nwsj9XajeArLn33w436LuYJWl4xP0dT9zLNODhOpDcrSiFiPXg3M+bLCl2LK1f5PgNl8FRREWao1de9Poo/km7mpw7c+Sho4b7nzZBpsHEejPSA2KTLlMw0r8O4EUoVoTkVvsY0xw6Wzq+N6DYn4sGo1qHleDd5eYEWb8KSePf70bwRoBVhVRrVhL1D5FQhX0f5Mu9mtcgpoETF0na2L+Kl8+atwZLvnkfenkG7sFpInjZe2JaWp3n0/+wu1WMZuwmEbFc4+6mJXmSZ6KVflSxB/jnZtmcA2Etq3w6xpWKJkKtr9E2eubfXz39srlw0Jp9wLd4R5b1Bf7NGUT8NqcpPPjWQcXHnsupGDzNbONEFf2qycZMyTla8h/G2lPIoCnTAaCK3jW1ZRznE6mMiICmZfkBsiwRcPZhQ2QMKJNdK+x0MQ5bnhy4Y1dW5MGxwO8WfQRt7iHclQyCdQ7pUjQnFDjsjlLywFG4S/NG8Pm3/Fnbc5CadxL0JeySCnL+CQsVSeHikZCtrvJQvzNKOXZyNBLp/koGOKYozAEAGSrzLmxrRuCM/5goDaPPK/aeCJh6SkmZlo+uaYkdtEJHTsH+ighzLeHwa5WKu4BHsS1tp6xauJYDeAhjrOtysVwJ+P/t9gdTnF/rZo6xUqsctWyJ6KbjgS0JiKoywdD39oUj5WBSp6glh4+dSvS5LWMYcbff9xaVl/RY8dP4nqyHsG5xYUuHuNgIRSkB+ezbx6Q+gOrc7J9Sfvr6QOmSDT5hBr/A0Fm0chZxo+aLSwxenwyCg6hR5qnPsPQ/6oiAgNNO3tsaztVUA3Jug73N5BogU8kaSROJorfWVcTrK2+Ri5fZHyzsjIRGkXgnpIDpWI7wP1r/JzF+8+tlK8f1DNcCI6boeWHaD35rM0rtQ1yYF8zs0xHJ+HL3snfvjcArEh1W5+cUERynQoa6J3wp98bJH8ETORdfnHsuI2Z2X4vwMbpj3Io8FuYn01h/gXUwWyEYzS2xh1ddiVQvB0rNkrAEwnY6K9b4zsQQx5xj7ipdb3eHkV3OzZapGahpGoy7QHJh95mr1Bc/92f3eJ/MaGw/HYg12AIYi7rLyz/Lgi5u4w+pXSbLRrhol/eU/6EXcN/4o7/yISQFazouMaJo5j1WceJwd+Fk+9oee9qJwddDysbO26m0+s+i/GkmxeHxeUA=="},{"id":"3be754e7-9541-435a-8ccd-d1a749c5053c","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"应用(App)","description":"app","prompt":"详细阐述‘应用’作为低代码平台中最顶层容器的概念。基于AppSchemaBase类说明其属性结构,包括名称、标识、平台支持(SupportPlatformEnum)、发布状态(PublishStatusEnum)等字段。结合caseapp.json实例展示应用元数据的完整结构。解释应用的创建、编辑、发布与删除流程,及其在设计引擎(AppApplicationService)和渲染引擎中的处理逻辑。说明应用如何聚合页面、菜单和数据源,并作为独立部署单元的边界。","parent_id":"2574726c-e59a-4bac-8854-59598d892537","order":1,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs,meta/apps/caseapp/caseapp.json,src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs","gmt_create":"2025-08-22T22:19:14.096611+08:00","gmt_modified":"2025-08-24T21:21:36.6764004+08:00","raw_data":"WikiEncrypted:oHWTaao6VMAqvHzIzzRyIysdD6EhVI+AY0E10f36kg4lSBTHO8Sj+0DGwo5ENLbvSPyzldEPWHl1m31H78/h3RZVBvzlAvAyO+7HHf3IwfhBRD1cT7z0YZt7/827H+YgLSEWPS+mxOe2dDpEtBSHJ9Xt1qFQchUObqt1hxVLky95LTgRb+Ff3JJsGQ6zi3RgVUWH0bHSkAZDtKTmpKRnT/SISvCKEImyaFnKOSwaIaIlohvMV6BCaCAV/NNAs9yCAJaETYw3ltQdsI/l9gYd79pyOgZF320y7V6NRwvJvjyOUkLV9hyipsXjplMmLxX2x3o1bp2o6KQcO4ZSwc8hhUu74cx4eU2kcB7+dJ4C1ZqLEl4fia5WRrRcoh6ipFtNctw8Uf/OsOv08lRiv/KhIpvcWwerF26LbuZ8kb831stPXTm344dR7M3xTVisWE0KfJqPghqfRVLUYei3cgq+sLPBR34wLpSTzC5/dngFrBQd8+Gc/Ju/1eH12mRQ+3NdJbCJK+qMtJ67WeV6tae9kdIfwWKWF4JRRh9RPx47IsrP1CmSTb/0z11wz1nfCCZbHGgEAi1YCbaj+YFLpnkJJVvRodI5fmCtjRxqyhn18BJOhtWdYypkLRjccJ6hMC5iB3K68hQQ8phmoxufn53Ec3zSFrGrzGDcYl7DDPJNF8SXHHrldAJQTG/7mumkJVEn9wVxD7fHVGA55R8QZkUZ48ReUnxl4qfSSNMfbJz+An1HDjqTMPJhd0ZD899txn0Eltw0Z2ALSMdoymgdvNFMc+lnvmZx0jL4Uwgykv+Ilx8VcYB4fCseKgcHgJiUH2jfRKiJeNGA8PXQ7IbVoqIWazfzz0p0N1gN+uK1bS5g9Vm9xF27E6B5+g/90/Xsud8+ImQQkEZUkLICE54ncGmjNyDTazqWAsX6tPWUN7+K218iT2D594uoyitXQ593dl/tWnoMApSLlaoer52kJ4+gNYamYyHSq6/yjAWIEPNzn0InlruFV+Ns5BgvzYN9c7mVXR38DJGjxCjiv3HvGSa5kogOKNjAOgMHra5v2+4VImwgehpC9xxC7B+48OdXikJO3QXLT3oYIyzVVNAJpZLgCRHBkQlU6EuOPR0O8a2KCac=","layer_level":1},{"id":"e52a6571-a012-4e2a-b5d2-e5f94c01d367","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"领域服务层","description":"design-engine-domain-services","prompt":"全面阐述设计引擎的领域服务层(Domain Layer)架构与核心实现。重点分析AppDomainService、PageDomainService、MenuDomainService和DataSourceDomainService如何封装业务规则、维护领域模型一致性并协调聚合根操作。说明领域服务与仓储接口(如IAppRepository)的依赖关系,以及如何通过领域事件或事务边界保证数据完整性。结合代码实例解释应用创建时的校验逻辑、页面发布状态变更、菜单层级结构维护等关键业务流程。描述领域模型(如App、Page)的聚合边界与生命周期管理,并说明领域服务如何为上层应用服务提供细粒度的业务能力支撑。","parent_id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","order":1,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs","gmt_create":"2025-08-22T22:19:49.6149126+08:00","gmt_modified":"2025-08-24T21:23:19.0201749+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAb7Y9N7zBsWD4n0PkLjmQhxGHM4fTgGZuvs0ZM+mMl5Y455XXqa8unVeXgthHgLFr4ejjfVD323LL3vdKYtHziWiRFo4IxPes+m8fdPv7LIg+MZX6uNoocQId1Fye20HYSRRUlAEdLcxYdaIqrzmM4OrooECT2qUFdIMCiEHwAuP5cekAgUCVB1xKc8DXX5F5snSdREPaiQHlslOQJ28ylg75aBuO7YwrTtu12+G4S3HgZc1FOJ4ZRUAtuZAlHm3fzxLvyW8HR2bqVcMWU3ir1Zzp1Lk/jTV0c1F+qupmydRjpVy3RpbTSH/7QA8Sjv4rpFiQ6Brn/zhJn0teMXNkS7vb2/6i1bssYuPhqJeJ+pv9VvrGuWNT6mzoqu1iUmGqywgAzOM+iRUEinV62vPS60Qr7lE0Ip1XizVeM9eQ7xaoJERuy+sjqs+tQvsZwupas0Qg18It2cX/NYFo3R7/IysRoIut+ad4O0EGGQ8TK/llpEe4dKf9d6VjTTvQgcfzuv/6ff+9CTl623WJnW4jVhh2Q/vROYJUcj6oLKYPKZPk/yVJohGrMfqDH3YsH94HwLTBYaVN/OfQj3INmBNWND9sP+2tEUwQ+1S18JaBRKFj3YoVmSV8Gbq5RCNEuYQVAymfI9Phh5HFlSt7fMZszdH56BH/eTL7pC/THZ09MDRNxSPssAR/k+yCHJSfbnfMe7R0LMaqp4238KTMwM9x4zzFCRJyV9lDdQrFa3g+TPX0MSDw6zZghfSpSESkuC7vtU6JWXHIeEw61spAy0eE+0lSsPpbyGmbUQR4KtguOjRc0eP4T5Ji2zELlzu26aDikjmRD6xuaYw5ZZ25iyUeymyQ3HzI5WOKKcanw6MEZYmmTDgs6W+9I7CkAxjjTaWFPBk8FWb8mg9zcGDbOz2tJuFD6Ap811mJ+1I7B90xj6RIA5ZnFiE+XNBmeJB0vriEzo4/RaY9v/t7ZGmaH5o/DEvgCVkoAgSj758yynSt/p+lnygWQoO4hgSmPND36tlKxoOgBzJT9vAIeaIWtN6J+V+/4/vm7aw5icLQmqdZO1PrpIOXUpR9gApSmlToLzhAHX4MA5jk90FsjTvskEeU/DJJOMV5cWFuqej/yPYAGGjCjplYP0WnowstS4noc4oSGER//q4WSLsK4/QIlbDHgRggbJQuYK1tJbt8uC/yFVTq0fZ9w/FpKciM3Q4MKmFdzOyjEFIwtjYkZbcQFtVP8kjv2xp/m8Am2JGo+kD69AMYXA63K+re/rxVQdim6Jg0xeImm5c7Er/ZMsCfVEL/Hipdgs2HzY7/HceSXaHwlGc82a40k4s8PZUmfGVqiegain2EHKfKFzdHC2oSU2NppogMdEzOGEchvvwXzd3XALPxnvhHQ6GnVV+EytBZySkdj5eBsN9k1VoxgN6mElYjQ/F1RDP7Me7sfO5pe2mcQacghQ3FA5glZzZ85Nz6bI3h50vLCcebsICkNbNYYR5xRpFNR0bIvTFHqRfv5qmyD4Q2RjgG+ZSYOCLfEYRnXiFNchKKMfWzGXWphIpQ2kZYHF/HIgcMJwH+E0TNOZG4Re593C0hOsB6lPDHkmzH8IWE7DikuxNGT8wLcsF6Vv/iTq7DdTpo7n0qOHRganZ1kLqcXEn5MudFtqNmu8yQXUyTcPu4OX73ALncweckIJnMmTiVUBmh/JQmsdkKNGtYTcUl5hf4R7LpwF6xPW+1c8jeHdauqiookN09hc9zGBuF3OjvKsEmdFFihw0c2selmcoLiNpoWm5FP1SzusEVsdFbFb4/jKuJijLF5QVBEDCXXfWgGeqmqcw4CvkS70LVrWKMl1G3QBTaWOGasum+oNzyJwUq2V8IG2XY+pfUMeRigYT4/C4Y9vwsy5SyfjfWkxzdNYV90f/3ICjUmpEBAC+FQcAKvvSXlaZuMSerF0GM7NQ=","layer_level":1},{"id":"ebbc53b5-bf0f-4abe-b35d-ae36efe39917","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"元数据驱动渲染流程","description":"meta-rendering-process","prompt":"深入讲解渲染引擎如何基于元数据进行页面构建。详细描述MetaAppService如何从存储层获取AppSchema和PageSchema对象,并将其传递给前端组件树。说明PageSchema中的组件列表如何被解析并映射为Blazor组件实例,包括组件属性绑定、事件注册和嵌套布局处理。分析组件实例化过程中对ComponentSchema的依赖,以及如何通过LowCodeComponentBase派生类实现动态渲染。提供一个从JSON元数据到UI组件树的完整转换示例,包含调试建议和性能优化策略。","parent_id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","order":1,"progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs,src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MetaDomainService.cs,src/Common/H.LowCode.MetaSchema.RenderEngine/AppSchema.cs,src/Common/H.LowCode.MetaSchema.RenderEngine/PageSchema.cs","gmt_create":"2025-08-22T22:20:13.2913526+08:00","gmt_modified":"2025-08-24T21:27:41.8246179+08:00","raw_data":"WikiEncrypted:GGNwjtiljNFju+SNlD2vZt2JX2XQc2VVv8R3JgjCLwl96uJI8EPiKJyQfPETOViToLGInIDGjtOl3Msh3iKzM7Op6gsQvlMMvSjsd/OhMOrHVgk+8nv8aFvRUidoNjOeucm95h/h1UtcdGAsd3gSF5qoeyDBH+AzKksw3Z5QZ6Rg0dsqAXvbtatd9W63uHJ+bGcckKxAdXWWCGmlBgCsaSU8R/u1Sq5c831Jlo7FUVnOnnhnwN5EHa7finDzcLVhPYfQ50Dx8bK3AlTMiT1sv0ZGd/njI3gove2TeaP2yBgDkNwpEw5aBE8jJAROaY1YKskJ53lhpvOHbdpz/KaNdKy7+LkjMnnmZvez+AYqOH6n/+U6P/XN0BSgCiqcAwOjpyRpTjyq3RyokP13ZLa6735mugmGqJvN2umwY/BtMsTANFwHSgIVknbzgnqcTlwrmMaPtnHP+1HfwcmfXKCo9qohHfTcA9UTCmEixHUcpe7GwCuVQ4N6pUG43rPqqKOaRRvHn646vcyT6RH7J3Y8+1jmu947iEVzFEja1kJXnHl3dA6GCnNosn16uiPi+DmMuddj7iZ++/hiJyTYI2EMNiS8quQL9zJhUD7l43jg97yYMEDhRS6auuq4V39nss8B67kTQYGrifsyYAGx/INxxZggTsSsBtZL4qn2kSn/V47u7VkUgJ9WbxCWvT9Ogq3CqFGa4IoRsCdPdYuBLpLTrlc9ESmESHdubkyb3wHt/EzeqfKHgY/tWMt05z1l+WX4bGOA6qX+VxR6kgsbqoqCOtrcig1F2jcu69PszXMKfFXAVD7i7aKnB99twJ47IyqSNuX+u4eAAqdcObYlNB5MuzPZ16dJcgeTBbN2XWT7WURDoWgztNvKdKVj/z3v0EatErAVlqNFWLTLaWWu0/T4PbkXJDw5+jJpOKcTsNE0bYUdD8mhFXnUxEPqSN4NnUEAXtjmS4oNZJm+9IjwtMeCG60dXZnuzVrrt2MG7lJEWL+DgjCpJvynfNfU49oV7L69PUXL2Zhf/xkUvIW19wiwfWJG/ZZNjEU+1/Sp0qL3lXZC0JbLeRUwuqUV0+D2CY6TlhLLIgwZJihk9n8V5OFFPxUgvVcenrcH1ETPS1K14CB/s+rRtCpu8jKvOCm19ehug+KNdtBYWgxXv4ngiJmgqxXM+5RCGlArKlplevo708nxxf37hDvrSU6HPCSlcpg+niqCga/omRir0PHY+XcTfpe6t1P725RcNvof/+X/bqzhjiRHiTHZNLQ1y6vae8eH7FQYc9cTyiYht2DDaI25dWlL69yG/1CGKfZrgolza94rhJ/4EZrRgtTgO/mffu1grnr1JmoolAPnx/MCEb6Nogxbyv4bhtyIFVYjN7A4G94=","layer_level":1},{"id":"5ab4ecd0-2c5e-449f-8d8b-b54169ea1de7","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"页面元数据结构","description":"page-meta-schema","prompt":"深入解析页面元数据(PageSchema)的设计与实现。说明PageSchemaBase中页面类型(PageTypeEnum)、布局配置、组件列表、数据源引用、事件处理逻辑等核心字段的作用。结合PagePropertySchema分析页面级属性的定义方式,包括初始状态、权限控制、导航行为等。使用meta/apps/caseapp/page下的JSON文件作为实例,展示页面元数据的实际结构与嵌套关系。阐述页面元数据在设计时与运行时的生命周期管理,以及如何通过元数据驱动动态渲染。","parent_id":"8aaaca53-5075-4175-a837-be8548ca26c8","order":1,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs,src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs,meta/apps/caseapp/page/0lgu6xpop.json,meta/apps/caseapp/page/2qceiqni.json","gmt_create":"2025-08-22T22:20:55.7868937+08:00","gmt_modified":"2025-08-24T21:29:38.8184453+08:00","raw_data":"WikiEncrypted:xFUyDUZ1oSw8n9uU7tanTNj4SHDCMYw8FPBgYVoY7fhJCO93d57PotVyd+mf+L+az/gUi7VYiz7/v6ZHsuKMj/ByUjJOEmZ3I1CTsysQSdBUk2/SsOXGktAEzflmOdgEo+j2pFyC5HRE7OnUiBYQBbxQHmg/iidV027uEfvyEtUaNyGbFTpNFncO2RcbOoTZk/9YbcNsU4Oa88hHFAKd9X6iXo1LGitMmn3tjEaYX9fgTQFDiZ3zjwzDugpYcsnEK38d7i4ejF22bqt8Rqj+Dg6AVZkCpVvZSOc//cN5gjABC6xCxYKca6fl2Ccq7p8BfqwzVXeSoxa6Gfdmlcps7n+k/mPO0SEUq5SL79DFjPi/G4idRZh72aZunAtdBPKX8Vqx/HgbgWLs1unQ9nfvsdTKlZHf1uAgE3krSCcJKg8PF0YqrZdyXUwHp3PrCtZNjiB1nKLOdRYtCWpaRmxYsFpfiQntPpxAfqMaX8MkAYJgMOXRMJgJgJ8jeRVsqxb1xFe1opln/QsaH12n3e0Gtg4EJVb9OYlePjtXOZ4VmrtH8b0HUlITdJ5SE9EcvM79XcbU3m+wmA5392K0LnjYZEB5q7k0qjeuhkTYQwu8102/WBEMlvuj25kO+RWTT2hQ92NUY5kjMTmK9npr8v23pA+s6KSg/UdEzwcxNrVdkbtDQ8tHU4D776Zxum+3URute4F4xU0MRdOMb1rZPQlt9rSxlrl27IMNJAXVNXToUApjOJnnis7uOtTpFh8rYn83HLmdJmBKMFcde3HexNCIMzhEXiRmUiyabDYy8mBVrRmyUE7lPHRbjVj8dooj8a2hdQ6C7aajOOLLubNGgpSq3tLl1ef5TfRXtP/P1JPNQOt20cbH0BBOFIe27AkVl6FP4D2s3jc3XwWDbxD5vCB5vCHlxMrhBrcnLpVeyLfzzE3S7raH/08Az1ERYXfz35HreMkqVQETCn3+uvnx8NfeSiTeXyy/82ZWFLdNSlROft8uL1ePwTZGOgr+fMHg5eHC1W5rE9DFA0R84unlJSqPf0Qu5TIrPJ0A+ErE7QdlZncZjS/nXsPbXcnzb2/fHCqQ2E0XnvFjSLsuG3JjSqJLRR2ecDCWp+xo/DppSZbU7mndaGXN/tHJZbkPK/eJ/82fz1uzeYgWPCHtSwjBN/FW0HuPtlFgoAfC7DI+kcFK+D0rhfxogZ0g584eg7Odf+OMOMT1ab/dW715ii9o3gFaN+H0EwJVvOFr3pf9i8lnczgZelf1C78xzkyvdir7C8Q7OJthfBLEMVfzR6MhiNLrSTZ4X/7MwWhCEI5YYax2Ztw=","layer_level":1},{"id":"34d1c9bb-bc55-42ce-b93e-6e0e210ee024","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据存储扩展","description":"data-storage-extension","prompt":"全面阐述低代码平台的数据存储扩展机制。分析RemoteServiceRepositoryBase抽象基类的设计原理,说明其如何通过泛型和依赖注入支持多种远程服务协议(如HTTP、gRPC)。对比JsonFile与RemoteService两种存储实现,指导开发者如何将元数据持久化从本地文件迁移到远程API或数据库。详细说明AppRemoteServiceRepository的请求封装、错误重试和缓存策略。解释IAppRepository等接口契约在领域层的作用,并演示如何实现自定义仓储以对接第三方系统。提供性能优化建议,包括批量操作、异步读写和连接池管理。","parent_id":"1e1f9cb3-49a3-430a-b3cd-3b2dd4bb2603","order":1,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs","gmt_create":"2025-08-22T22:21:28.1534021+08:00","gmt_modified":"2025-08-24T21:31:27.207229+08:00","raw_data":"WikiEncrypted:yP6vl3GzzNMVOI7+ToNUFd1zLJDCrozCLFJSuv5/bW+BJRrGvpqh6tL9rEvKY22GNwc1gLq/KI2o9xZ64aEDbKCZT/1Do9HWXn5Z5ogGBwMXLDvm9KRpXUcbK+c6gVIgnLcjn2ZP1wgg+ChayQ9lCP50i4GCMiue/msm/iAMrs2Y5l2pIZZ0kyu3XXF040Qcksrr4kQQw7pZZ2y0xaATVNWzFyRQDpEXXsJ4Zr567ZFuc5RA6ZPfUoPp2x5FLSPe24oOfBYmnx5CvjcEJenk8vJMA16waxpRuzmjBqPFhYYgSE6AfjXPientA2zCfREJdiWGTZzMiCocU9PpnD+w5gX1GQK7mMS1RC36Baeo3mrcV0kGGs7hmfm3vfn8RnwJKzxv69FEoiFp7WSS7vd2W5Vea/Gp6twKrlYmuzqyRIB1PyLgBcTYpu2eCtrRgbwlhw3RiAvJTLC/HdQpdse2/r++h1BsECbVxDnNKYwrTOfs0gS+hgJHR6zUeghAQn9NmXwX/RVXwqWJyCBWqnYui7kCNKtcD6FGPlgJp4u6lpWC/LsshHw/p8gN1lLQ0Kv++C6JO64rigRv9g6BFSbw0KwJCfm2+Vslfo79zeWo8FPH2rGltbagu55eMC/6cN8vR00fOS7VMJQHH6KOl80fw44ZPj3y+MZT8cEB8ryJ0j63sxN2U6pNTtaqdCsFXrsoYbFrc6d4e08H3DU7oYVEjvj5HUpDdCfiZcBeiLG+YLGsEv5qHte8gkeYwYLMoH5f8xuAijZOSZ6SnhtdPi1bzZShx0wuNB8SCiOY2wriXFf4n9sc4I9+uMGyXnI1w2xMgL2u7EZGCSItQWM/4US8tyyPuOEoNE2gof9P4yctSDqd3UJKl5Dqdfqefr1uMUgqNwZJw+EhpRI3XaQtYzOoA0RIm3AaaQfPZrRJFNJL0bgEQSSLDPY+MALVOG0ry4mb4JUuqmLa55Eivlk/Pfh2Ofq+zgPx7nxWW0Lp0uSy5uKhsOR3Woleic2lBfNsQTz8Mf/EzHZ0if1XiWaS+Ae+lptnYK/EuBTJwUkHdBK/P95+aHzIWVo82/A+AL6jQR3ZXneQNtsrht+wpBkn9/9a1rojvEeQNSfeWoOhn9R1RJtGTAahCtH5X2zfGQ09rOlzyIxUH9Ghv1t/oe4aLC7Zcx+aRjWGe1bLPqAzKfJYmlKSz34nnILi73rjPxGyD9dsxlBthudaPYKCtvfM0Y65i+JaVt7Za2blmWu3LchO5CPL8H4vwGmLerHp6wmhpJXs9uuHq4IOfMu4Y+xmnydSPl5U8ClRX3SgME7HhXYYNKn5FHFXfKmMHp3ZmzNkG+SEmwl+TY2fL0sX/Xn1rOP44hBeUdSbE6RrgVX8mprdlqxmFiBGvk1EISxOvqt5ZERnrkgtTVrg6y68yowxwEx3zwiE2GbBzHji39UN/dVh9PzSuAHWSU+F7KRjvOpUxlV45COBa5SIqAMdksjHt+j/sOuZe9cOG+qW+bzIVyVPXGyMKXG5lBgC9tbdKQXG/+xiBxFGCH8f1Lo2ryYaQXa3R7Cfn5gkGact8rmZYtNzjY8gp2m3lML6+LK66vWbyYqMT4pjdxZk1Sptov0BEQQEhQ==","layer_level":1},{"id":"f6ff38bf-eeae-4883-b8ee-0fca4824a1e2","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"模块开发规范","description":"module-development","prompt":"详细说明基于ABP框架的模块化开发规范。解释如何创建一个新的ABP模块(继承AbpModule),在模块中注册服务到依赖注入容器,配置模块依赖关系(DependsOn)。通过具体示例展示如何定义模块的启动逻辑(OnApplicationInitialization)和关闭逻辑。强调模块间解耦设计原则,避免循环依赖。提供最佳实践建议,如服务生命周期管理(Singleton/Scoped/Transient)、配置选项注入(IOptions)的使用方法。","parent_id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","order":1,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs,src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs,src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs","gmt_create":"2025-08-22T22:22:00.1301216+08:00","gmt_modified":"2025-08-24T21:33:21.0476095+08:00","raw_data":"WikiEncrypted:MaEDad3+dpW6rLlXdYaTGUsVTZDIWF0UMBpfgwq23HbUXh74NXn15jnt2c5Czi31bDQIybRyjMDKAzKFS7XFIUvRFBbg5AK8XzHd3lyzFHILrlHDVEew7To/FdoCQIVU3ZD6dJarZLvbZZAlmFJ+t65kpUYyXP+nnWl2P/XV1TNqKKJ2yqbhjP4MlNkt+n+dRZBpfY0ex28yKZOKNO85GTYIfhAsKcxrw9OyFoX6KBm1DiOL9RedI0Zmz+cuVwPiSDhC590YYziIk7bZLrMpwZcHfRgQPIyRbhgNm8e6xOtJPiLvKSCkNefjthnc+3t6d2epkMTPrDT1UYdHBjZnKiyhf+nRuILUjDh+qzOow34kcbpj+BJDfIPral/L6eJu+Q7SZRGbAMT1fpUIf8K6I/5qiuueQtbbVikyeBfblocH+74KXSn/7z+gFbDh04juCf3G2o0TUVouUi0Y70fMGMSBTLK4S+cv2+qf6V5QHmAm5xVAe/tDXRZh87zAO0ky/oGjqwqK1fItHOKKtaBjlxGfgfUbZBv9ADAbinTBlLE6xMIFtrQspnQ6ebNjdWfLypsrM+t/hrRRkEBnchU7QoOnnTP6sO9tFtFalAx1VUUdgnqrC6WyxwUiWgEFhVjr3hBKHv6KZtPebY0np3vVTfbMuxbC4ZxwoLwj7C5tbXw+35cJHYPR3H9JEXRuchGS92NmjSuVaAX80kWCR7KoN/wczBRKllFyCU7WKBecK8gNkAOQBWSH7/NM+VorbBhuC7yUIhALMnTC1eG7wgR5c7YfTW/o29wQ5iSmwVCUnfsmxK6/c1T6GsJH6A2utT8iT1FsHP+gU5AZMNNSQHJbXFanyPrvrIy9k13I2PbCBGtHUw+hnWnLorFeEkRFtmb/1wdpKz3nkTMKyM2aJVQaCdizM9DLyXSBMTT3a9bMdAMOJplcgX+KxIJk66sTfaYLLUDEPtixxwk4EkXYF2xsEZwFsxmuc1hLosWKIZiDAWmC8C9v8JTRKhudSQT/oufJbkn1+Ei0GDWZgfuHQrCpujHdrBD8RqNjdVRSeAWUHzbUqStaaLaNqsN06a01TOeo9321ZXYU4kw96DByJc6ox48KtGzdKpMavnpfcIj7V+hyNCyeNijHGwuYrCYofHk01AzHopJ9GstIhY0OVsyVdg==","layer_level":1},{"id":"cabc80f8-c5bc-4872-98e8-da742ab3e679","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据库迁移流程","description":"database-migration","prompt":"深入讲解基于EF Core的数据库迁移机制。说明H.LowCode.DbMigrator工具的职责:如何通过DesignEngineDbContext和RenderEngineDbContext读取实体模型并生成数据库变更脚本。描述迁移命令(如Add-Migration、Update-Database)的实际执行流程,以及如何通过代码方式调用IDbSchemaMigrator接口完成自动化迁移。解释MigratorDbContextFactory在设计时迁移中的作用。提供从开发到生产环境的迁移最佳实践,包括迁移脚本审查、回滚策略、数据一致性保障。展示如何配置appsettings.json中的连接字符串以支持多环境迁移,并演示如何处理迁移冲突。","parent_id":"87d35f84-473c-49f7-8192-185a0a489619","order":1,"progress_status":"completed","dependent_files":"src/Tools/H.LowCode.DbMigrator/appsettings.json,src/Tools/H.LowCode.DbMigrator/MigrationServices/EntityFrameworkCoreDbSchemaMigrator.cs,src/Tools/H.LowCode.DbMigrator/Migrations/20250225020741_Initial.cs,src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs,src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/EntityFrameworkCore/RenderEngineDbContext.cs","gmt_create":"2025-08-22T22:22:31.0465342+08:00","gmt_modified":"2025-08-24T21:35:25.0569088+08:00","raw_data":"WikiEncrypted:veTYwq2y4io5qXerCTrkkH9ryxDJ0NroguMukGrnBDccbI7FhPTNCbxlVVf68ZQ7KfURH8uwOskJP9/hVNfPa2xd9cSNsPIzdQzd2Qm/nQPqlu0qG+AZBAKtQsUU2/7oln6yQPYIkJFjbVRWVvEmxbsiNoH6ZgLSrqHumPZfHJ3rTez1wnRbpjxn1XQlun7nXVvBtrYiX32sd9YWNMJGEviOIZCuVPPJTOOWHlYXYvTnKmZOwO6XsnJUI/4bR9B/A/+s3qgokHNUEP5XVN+ZVgDvU4eWGlpLKI/D8d1m/5PZODc/QcHj1ZxN9vK3Mbiyj19LD8aIJc98MnH637EH4/lV3JJ+bWPpu3hHtwNKy2jB2wAYqI7zkFFZZvo1QHF/b6awe7dq+fPoR08wfq1g4CTzYLRlTmAX3lAKYcV0SDtHlX/yeJ3+l1COEhYCltRm5EzODS7V9YiQgfDULYKy6BaFwnJ7PsyJ67HLnFgFvsw34cvPGbL73jw8Syz7BRpJ0oUT7CkBjye4aHG4CFADp+WnapP3Vtia/O0FcE7NLcqM98rIFhurMk42Z7ccRQ9hFD7deOP6ZRsXfo7s9ZKwZv980iSLOO0plwfvCZIfNIa4GLIAOLOURZT8nmuMlGQz/JHWaDaUI/9PfrzLAt/ymgDhfFItR7UPsIfij+xcJbWaIAzcbH/tkeGucNWRJFgAfNDzjfSMlCGd4GYNk57heB4fV8uM/ESYz18AH22ThIQJ26R3gytUIegfzRB6gs2upfcX8HeRELymihG4IN6fxDsa/vGuGI/WmI3/6uBbkQJhEh9p7jx+8Hs5XlE0Vk96tkdPRRGwdl5qZW17Q/zaNljAu5v5VuGqshRDvBlqliUhrTvEe6nleUHdF/CLyjY6GF8Td00mT7JCgKZBb2761yPhcvgTXJg8LExzmZFiHFlMz85ywi8LdYVmanKsBBGCQKt/5h23eOBtYQ1ZW5yyq2WMYXzbFPbbhAn+eU15hXQ8KVy/vPoCaDrFB3h4I5sIesR57i3ROXZktLtngedW6DcotyAgvDSpDPP4sKI4KYkC2RomLf4aKWJqB9D/nmu7O5RO4Xw8LsZaMwPiTy1yMzghy2LTBnMYHWPHfuyT9uWYlE2XEaVqTIFxYDh1pAL6XDMTbwHM0mszMeM465MfnsxTHv9xWif+pTLThVWCWHydjopSI+rkuELMMdsF418KCCfunObeqd/L90cwquZG2DXtSvyzlVlUaV83Ytt4pF6l5dsiTK4Ong/LH+lImyFAm4NgLp2xG2jFrh64pUs1DZ0ks0mqn4R6TL4GwtcJMWH9PaRBWYeyfuNB6RaDmUm1XHH8arTkRm8hE8JQVstfiqKicEmT05grlRJdCdiU7lmc2wEiNs/t/nzKPNX06aGEFm2g7xtNVOmLo5Amz3VsZWa21/5m/1Nln4+NGo5qtIMqKy5p8M9LLBJStEoljUAgQnxHThsABLblavIyli+0+ApK/fSAWbhWA/E0u88r7LDhxmL90FFbMgT0UK/8Ef1nwNwnUSNqyoVXQn22CoXTfKgfo0sDVFeXZaSpD2jqhpPCKQrunmq9qx4z4a65fUm4iJlCzuieQnS29vJGizqtQ6q3ewd5rZC1J0EF+orX8AC46V4dpGtXsij3emgZ7XaAPF19ubYROvTo8e3KhGz8Pg==","layer_level":1},{"id":"c79a4d61-8b8c-4eb3-ad97-c40df1761a32","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"页面管理服务","description":"page-application-service","prompt":"详细阐述PageAppService在页面设计与管理中的职责,包括页面的增删改查、发布、版本管理和元数据操作。说明服务如何协调IPageDomainService完成页面创建时的默认配置生成、页面结构验证和父子页面关系维护。解释页面DTO(PageListModel)与领域实体之间的映射逻辑,以及页面列表分页查询的实现机制。结合实际代码分析页面保存流程中的事务处理、缓存更新策略和事件发布机制。文档需包含页面类型(PageTypeEnum)处理、路由生成规则、权限校验逻辑,并提供典型操作的API示例,如创建表单页面或更新页面布局配置。","parent_id":"be52f1c4-850c-4443-ba95-8808d1e5b997","order":1,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs","gmt_create":"2025-08-22T22:22:55.1524889+08:00","gmt_modified":"2025-08-26T23:35:42.5741729+08:00","raw_data":"WikiEncrypted:g312L3FJqcJLKW6/idEJU8bJkhsqYBEEaqHexm+zmd7HmTDc1BvsX0o0DDDvQsivd+6d5kG39a3PRH/U/51rjVslGiVHahc66BPUvnMkfwaESAU1s8l8pfwCfIbSDjjnSW3oIzopbW/fDkQYzh4pzJr2a4SXJBiuN9RMtP3w1Mb0Qtl1wsZvv8QNnvsRRGHZaQXy1VuhUWSHZexUXRrG1HRHiravjt45tnYPYnE7vPYyHDwE0hOHKlXjAuFwhoBAVojWcM3UHfHl4wrmfr79fKQL/e2yGwTlp9YMqIXWEoRVoE6CWrQkxFXNY53gzymHSUWKaMM8z6C7WXuSMgpz7RCd5SQ9Wzw7nNpUmYcHkCSrkaFqeZCxKKF9JaOF8JB5pKGCpgtitEsJX0xLuBofcdtXK7YihW0mIubT4YFTl0+p6KWOfwrv64gSmneRlG4EkBwSdUaAsCI7aNn5kgVxRUQJC1bt2JNtN5gr3GDTVoJSiO6NDlMWtytDLyUX2Ko70yHyToIm+cg8/8ZQqFockl6M3ai50zHt2kvvc50MXcNS91kXRNm6E/RWWshd0/8x5sleUtC0nfNPttU0G0xbqvlVvEswr2v0Kq8fUM0mbApHv5gf+4SdqD1L+/Rw0lMp8pI68NFsW3NmyvLZW7E9j8TCbFWS9vD0SbZJqLikFZNbWTRiX3yN2F259RO6joD/ogEwAOzq5Vd5n8FvX78ONStQGVn/epIJso8jHdXxKllgGL7sZBXfau0KDliM31zolV2MKwiRLallasvKslLE1hdK9cfzeKzgZkeOOnjnrQNBRVK74WWoUlnuRFqFfCzFssUtte3xKJWyArhBTr5fQ+u63pvBTEZ04kK7S/JqC5Bh/W5V1Gi+Ry0m8XpbLPjbtLDerCAEwvY22BZU89g36O28CbxTyua3h6d+YAIXLQm6MO+I9urdYIBXh32983N0YsCNVLFBiobZxJTf68fa+D96z9X2/W/oLyMGYFqY+9/JUhbnu5BGznnKCkApRw8vSK19f+cX0DnpGEMMDZVDUC7oIEgZ0q+jdeKcd1Y7ZTydLOP+textQGHqNOVjRwXjjTmQI9spj/fd1sMT+BKfVgJMGVPRFFyr14MF6cBr0hru5S8wapq+qCJ4hygckNyBm62Cq1ET5OUzjkyHS6YBWB29ccEkHP7nHY9aH6m4QNlPmmVuq8IjCnBwWeQiC6E4jABG3HYhhJZA2nnrhB02ji6AgFTFzRWPga+3IB7Bvtg=","layer_level":2},{"id":"556efd3a-d209-43f0-b47e-da1f546c0a8a","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"页面领域服务","description":"page-domain-service","prompt":"全面分析PageDomainService的业务逻辑实现,聚焦页面元数据管理、类型控制(普通/表单/列表/报表)和发布流程。详细描述页面创建时的结构校验、组件布局合法性检查及与所属应用的关联验证机制。说明页面版本控制策略、状态变更(草稿/发布/停用)的业务规则,以及如何通过领域服务保证页面与数据源、事件配置的一致性。结合具体代码展示页面聚合根的操作流程,包括与IPageRepository的交互模式和事务处理方式。提供页面批量操作、依赖检测和级联更新的实现细节,帮助开发者理解复杂业务场景下的服务调用方式。","parent_id":"e52a6571-a012-4e2a-b5d2-e5f94c01d367","order":1,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/PageDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs,src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs","gmt_create":"2025-08-22T22:23:24.2885852+08:00","gmt_modified":"2025-08-26T23:38:04.5408999+08:00","raw_data":"WikiEncrypted:1px5xlzrP8SAgv32YR0d1ePOWOj2mkjM1GPhIzTTGJ9Qy+Lz9lLcWWrPHbP9XIOcx/UCZwmfH/MZVNM9LYTOFCQgsyOwx0AtaqWzElzgWyUQaPNfWg2XE/ed+2X0EU5GI7B0jID3MC8xH/hgdhGJ2OYrwgn+HND53ju2QgIxEMMM4wg2bMkn2TAh98L+sClmgUUQuEp+KFfIKh+I2nM3EBirBdaIXYxWaeV5wZJrQWyITUjBBQJihUygs9PCFxeqZChNAeIEpWuOYggrzw++OMlSvdCCfvkWhJHsr58RcezLkxNbL27uueTmgbQCUBi7epJeKoqRQlu3NjMtipe9spQiJokTXyXlVG8uhkC0ARnMmeHr8T2jrsGD8QTH5JOI/koJf824+ReESz22bkEfWvdhEXbdtXdWArtYruCx9awzT3VAIikoTngwFKqmL4jpM+tvZMa5ei74LPoUhxnCDY9EnPq77JAST2FQ7Hlpn1FdsMLNgQdAjsawOr8rV0dJyoDPa0Q6Eg0GBe8J8DzWmFzpZx0tKEzICiDmKtmlaDyxjWQGFhDBtUVCQh7hxozAS9Af7my/VsRjkF3OlTn9l5vSugny+m5LNCiHEwdGPjrk5gxC14IH7d80PYmUY6s5z/PHyVgm3tdurAKJ5FxhrEQQlzY6/QwUEIT3Y5pPN9v66hje242lnwV5pV6i3bfAQu9wyAYLf9UmrX0d85PHcNbidb7qtADKmngkdDP5dyLSFwdc+NgOlmsP8tB1xsPZS8d7Kex7uK4q4ucXRLpYOn2O64g3QnJHXw9Zh5++n+0A83gUofaflo3xd9sVH73WX1bWyTI497XzWJrNGsJX//DZW5pbObJDyWvk2Zk0CW50lkyM0AftvEiloMaUnUJNEkaw9MaDcgafEQ+Y+VOmNUMazIVbZ4Ym5diUKizFE6zANgcJnuv+53XkxN28oTn2AYQgx05Xw+pO39AG/uMCumsyfXa0b5wljDVBcbOYtQOZXvuiPQusTovSolCx3CUKEuQO46IPOlmKzKXthlCzEzrMHZ/4EfM37oo4i5nPQlatALCp5Y2vzqRQfmup2waEK9Bdo50J/XJSXuXbjyBBC6oet84raIag20E7nRGwKhzhxGiIvHQE2T8FnQJWvt/mtozGoUrhjHz8PgSNxcOV95JjFZN50jq2YHEGdPzfQM9lGlUDkNDKdFkV6n8BTf0P6MT+Ris6o+KtIIu3QWSh+5rtuk8reg4+QpxkRWyIQ0KbJjxFtRm/Q3IHNkFdjyEyjtXrnC2BFxkF4xZOA8cdKF4DzDLRC0wddz4U/6ujgTSwj2cq171FxYBjLiZmZr58BhRJMhgvVvHeLd78zlW2OcolJgoNvNd2L4vUGVMg8wLaumpILtkZsKBuhsJpjWvcVhGuqnX3g8Cn9Ra68B9xjL1duUx6Gs1PaPm6BiYbx4s=","layer_level":2},{"id":"e0974464-a4b6-481c-8d66-bf594443d515","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"Entity Framework Core仓储实现","description":"ef-core-repository","prompt":"详细解析基于Entity Framework Core的数据库仓储实现,说明FormDataRepository和TableDataRepository如何通过DesignEngineDbContext访问关系型数据库,实现表单与表格数据的CRUD操作。阐述DbContext的实体映射配置、查询优化策略(如使用NoLock提示)以及通过EntityTypeManager动态管理实体类型的机制。分析ReadOnlySaveChangesInterceptor等扩展组件在数据一致性保障中的作用。对比JSON文件存储,说明EF Core实现的事务支持、并发控制和复杂查询优势,以及相应的配置与迁移管理方法。","parent_id":"d3062028-65d4-43ea-a57e-3d6daeb99be8","order":1,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/TableDataRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs,src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityManager/EntityTypeManager.cs","gmt_create":"2025-08-22T22:23:50.8352628+08:00","gmt_modified":"2025-08-26T23:40:38.2187903+08:00","raw_data":"WikiEncrypted:ZTPPzUcX1J8ScuC9WpDEEkx3NJ8mcWzOMRPcI6Jk6+QjjoFEc+uTO/N0MD5Q8cqC49fDn4rKM9f7lNwHsmNthRUHZIl8IqF2oLW2NAsb1GivS6InRguq7UZpkgfusbheY0oFRQ3P8wad7DR1uvOtNPUBU1i1dvwhW1HNyBOhu96LtMGdprEQFgSoBszs1mU+CLzYmY3+ZgVtQFr7CJdxK63qHJukwxh8QI59ucI0gI2AkvNmK88pl63elTBWom+UVG01oqy8yCxsvItrWB0uAySHpfQZfrF1ym3L/il3Gj8f1Z7BF8U8G5lOIh54Ya05ctQ/zppbhawDPKnxoIGd2SzMGF3PcQKGjI7aYsHQdLPgI5bgj7fINt8dN3YWZ+H90/1NUwRzyyUxoPIept6ACnsnFHUoKckoFeBaTabTbfb7svujwLwPYO0zgzAxjnxU0rJ7xbJhophaD8ldxD812CnEs8jNXomX9NYm4qE9kivyakjM4hnzpB5Obze7O8kGAB2iPUplIdmvFO3KRto2CM2GN4DeO/E6Nt/W2DOtzMOtblsTfoan1jJjGg4gefTtP3if9QnyXVbf8O1Ozla1u4mYJC+eVjMrI1oGF+nWBu3+r4gq1eDaRyEWMEMf8ku0qiO6JpL3d+Gf1Y6gO8s41xvRxZZnVzuWs7qn0ugN/4QijP4Xep1GS7s1nAg5fmoEZsFHkQe1JGcOHJ96G0cOs/uPG6XyZ4aMetEjgsK1lUb5BGZgkAfcDXNbe43CgoxFZMLuD60F7+0HXwKvUuHgwk4y4xeWbX5m7KfhWx30i+SsV7DTQDRRw9f+bXHAGNhKlG1R4qwuvACk60XImuipdX8hxOhrAkA2xzGDIjoGhwEXJAFPWLx+i8bx8LHbcs5rKKwDe2PWvM1jHQeZWXvZUHRoajMaZ0pF2DC5VCdy115wzQrmQQtojLbjMzErM0CxJF3lftoeNRm2G7OsIRJdjXLcdbH60TSYydimi9a741Ck1d/HpvVQZiBoz8HxyhG+ividwIrNP8/UpuIYdDO8xpN130ZmUw0lmrrANPRDszlPWoP7TkqPXDr/xSzw5mwewjblBBusdscSn+Mqhtzw3FmqsRg4M9zXURLMmkagoqLBpnimq5SGGqsFB9uEdtnF+We4/nxrYQ25XbPoWlqA4x3JXgQuOfPlPhh0gkXSkQS3rvVh/WSnklOl0fOjw70kStHeJaXE1k/sMlVMQYUN2a09IZ33LsNXM5j6CJ7+gGJc2+FS+Wm6FcVF1pKU/PyXyrTNk1D6ZeWv1bnnW2bn8gEgdye4pF9nLgD+sPinjq0ZBaZ7LBwhUFMOO6ADT/HK+giwwwePbKWOH48mRfCC2u6PRA8c4+gCQ0gBm6VGk9MNIav61i4iOelmY79zlwYdNyTwNwKP5JExlKCGP/eU9YQ1SwgVH3I/lF6n9tD0u7AGzbEblq8JX1EPk85FdWvacmafCxRlmHESVsApzpKfQjF9d1lF/xtgptA22gizRU49291vE2rznU6x1Iu0lx/GoewWJhKKNQH7++hlIrWVafVWv+bfO3Q4td0FrGvMH8c=","layer_level":2},{"id":"27bc9d6b-fba4-4279-9212-dad801474040","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"页面属性设置界面","description":"page-setting-ui","prompt":"深入解析PageSetting.razor.css在页面属性配置面板中的作用,说明其定义的布局结构、表单控件样式、标签对齐方式及响应式断点设置。结合SettingPanel组件分析CSS类如何与Blazor的EditForm、InputText等组件协同工作,实现动态属性编辑界面。展示页面背景色、尺寸、边距等配置项的UI呈现逻辑,并解释主题变量的使用方式以支持未来主题扩展。","parent_id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","order":1,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css","gmt_create":"2025-08-22T22:24:15.1261792+08:00","gmt_modified":"2025-08-26T23:43:18.3489071+08:00","raw_data":"WikiEncrypted:yT67FnPxQAdV4u81DFXxEUNTs6Qhg2xG2OXH1ZcvCIKkkdCV/qnrmRN5CFWiYlgSkUFPMvY6PiW9OAEm1h5B0ww3/q8QeUkd9dBxHjSfM/BuXwIiEPp0EBqhGIfHdfEDCr1TsUkxv2wAf5zfTG6YaLCVK1vqwDxjTf4Py3/rGGUNeLLlh4VM+EY42ckXFvW2Y62SJwsr/d4zfvn/pw4hfQOz6v4GX/3c2V5CQaPYKHwiPOMID3WwozFbAmZDvW+Mu+vQKE0f0sZ3jMwu/UnWU0V1ateMkrazn5/GDOTfzN+R0UefXVmQgnJ9+GbHtGJ/3sajcIuTdHMVUJm6lnx8ouwBuw9D+UUHIEhYE00l7h/lOSbSMxOOFz8xfqPdzzh91h/hJAEg6wHww3OzngSsfymbKHNBMoByOK5zRXoRzKxBFPZ1hsb4bS1TC932iH2zmiXfhh/Yu/MKTn3Vz3skZU6pqvSajFMgmQFYO2zKnPxgfQPxvq/wpKV02syxcc4wHFMV8uRdH/Uzfar9RiKGsJIDW7iRpfomWRBefKiaKYGD9GpvCnG58AshEoi/YBdPcA5prO3x6yuo8tefdQsWB3QKLBkZA5oGn4/OuMYlQRvbY7rhqMwNm59xeKLQ6VWM8kMSAG1dCO70dM82+BzzsaGLWw0stkfZMlor1+kih3hRgL4UpT1dE9Kb6LKo3U9qQnstS3bn+yJYggr1jvnM16YkCVHogp4QhLF95BOhEhlC2tVMrOE3jRUdj4f4JJkkX4syWNUU8X/D+jUjUBlquhCDpwEvQUMhq91QRK2h2/Z1H3Njgx9vaUe6H7nFaJ228Pyfg0q7M3PF2S/+y38ZTuw3dXcGBWkx97gTl7EZrnn/ROWz0EH5mnE1nT1rMHeZM2+msfjyNrOq9Uvfs4C1Rw==","layer_level":2},{"id":"f3b960b1-9f70-414f-aacf-f61651e56944","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"目录结构详解","description":"directory-structure","prompt":"深入解析项目根目录及各子目录的组织逻辑。说明meta目录用于存放应用和组件的元数据定义(如应用配置、菜单、页面布局、数据源等),src目录下Common模块提供跨引擎共享的基础类与元模型,DesignEngine实现可视化设计功能,RenderEngine负责运行时渲染,Tools包含数据库迁移与元数据迁移工具。逐层剖析src内部结构:Common中的MetaSchema定义核心元数据结构,DesignEngine的Application、Domain、EntityFrameworkCore等子模块遵循分层架构原则。解释各Host和Host.Client模块在服务端渲染(SSR)或多租户部署中的用途。结合实际文件路径举例说明模块间的依赖关系与解耦设计。","order":2,"progress_status":"completed","dependent_files":".gitignore,src/Common,src/DesignEngine,src/RenderEngine,src/Tools,meta","gmt_create":"2025-08-22T22:18:36.9568282+08:00","gmt_modified":"2025-08-22T22:31:18.8938142+08:00","raw_data":"WikiEncrypted:vEO7Ijy2dU+nEIDHKdZkAfwFWhgNVyNCKalPSpB9ioLOdKPffBi32fMi+4j681gqrfBOWMFvQhGWZDfiAZKk7lcHdNCTHJNQfrGuIdTvX2gojAJRYuT/CYdXxxY53ziTXjLD974sbXtCEslziJ9/j8SfLAzvmaOKvy59j442YoVoz8a1Xkg0XTwJtEiNxMDGM9rTCp8cocYn1GWYEE01LvBqBReG8aCKRVjcDkmDEgCCR1DkVD/3PYroMkbaPRAJuhuKuQCt3xWZdTVXCpc7q5xT+Wbtv1ajw0huhiVKeqIqSi4FmgYf63eLreutoU2RBokBZvlFzxOT3QR8O0hEKBUGYazKXhpSKMppGYuP66kxEh1mCrcF51C0aWPpL/A3wJBJOAoAJqhmlxiO870tGjWim+b5drlv5bh2OEHDc2FAuS85sfit2feDOqOZilWctvd0+5J3dFEoxKHsJ54g7FhV3O4ZR7jPG2h2twLwBhSOYKRzWoHFpMxpaBupkzEzrURD4fXOsIoMYN9//iX03gOCigATfzELzNHo557nBo3jB0L2Jjx48NlA07/JltM5D5IjCJUFHmg/SxBTbEct+FhHz6RGLoBKZlH6Ab013My60AJTvKSX3NRfuHvwKmXak4OmDIZ+2su5DUHRgWbTmEGnahpylc6gLCKxfslb4st1czx7sw7HfBVHJJm7w4x7oaVKSUEfKWHgjcfN0++yWI5kjcHR29vNtsMpLtfwPwpgzUzH12eloVHswMFmfsJalymkm0/6u7Y0mjmhZyH8RZN9fWlFdruZ1uqdpniFKXDUTiYbMa9/PW8LKXM8Svcy55/YC0ptW6XocDl0gI0qGmEDUXVmSFZNbZRPPHH1K53xlZXzsLK7ThuKExVbKQlRHqj38M/9/lOvP2VRjYg/TOb6Jq1hoDEtrwCfXdzDkvLU2tAi11x8sD5e4fWYGVa8jOsmGU4HPtUzJI1mVlh+S6fpter3xvZWSwXqc1LYR7X5iznxDRJQSAX/npsqre5oepFH87hT3xIpOPOhM2hPr4nitzQ20HKl8cQo4Q3J9BKAShi53NHxQ1LHkaU5eM5M77Mp9NqUDuamDxiZfkVMOi6KKFgvl1L33dsbl6RhzYrCnlPLYhdKmN3ZqTl3/GowBmOA2ETEs0qy5/K54s9ewI3gCKBL7e9sq9KaWxCocTvJVSO22RkyNvVvYjK1Gd5NOLXT6b0acDfmM5t7113bKooKAe4+s3Q8ppI36/iK63a76lHUavOdm0nzAnlWbQjTBbm5pht9SgT6yj5xOoml0Q6LjtqzOieaiTUm/MKYX/o="},{"id":"248d9c53-8364-4f15-a960-a9edec151baf","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"页面(Page)","description":"page","prompt":"全面介绍‘页面’作为用户界面基本单元的建模方式。基于PageSchemaBase和PagePropertySchema类,解释页面的类型(PageTypeEnum:普通、表单、列表、报表)、布局配置、事件处理机制。通过0lgu6xpop.json示例展示页面元数据结构,包括组件树、数据源绑定和导航设置。说明页面在设计引擎中的拖拽构建过程,以及在渲染引擎中的动态加载与渲染流程。涵盖页面级状态管理(StateHasChangeSchema)和生命周期钩子。","parent_id":"2574726c-e59a-4bac-8854-59598d892537","order":2,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs,meta/apps/caseapp/page/0lgu6xpop.json,src/Common/H.LowCode.MetaSchema/PropertySchemas/PagePropertySchema.cs,src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs","gmt_create":"2025-08-22T22:19:14.0992248+08:00","gmt_modified":"2025-08-24T21:37:16.4327025+08:00","raw_data":"WikiEncrypted:hs2kp1nXgqq924ZM+fNnF5YiRZCzZfzvZ8q20UapABN4WMWkd/o39vozntMJ6D5aMVQVIRXUarkWpBQNWO8vFes+fe9JTJo55Es+6YT+2Fz379s3Fw4pYs0mSyIt56LeT6atrarQ3CeW6wkiyIU4Zpf8nBBtIPs9ADlUt3jQvyeQLvBN3oJUMgOA2e3b5lpSaiJLN7dcNhNRx7cboRh1iEkYeu2sDx4zUGCe4IFBtm6O29YiBulS7fq5VY2+YKiZ4cHAU8V7d2zzYG0tinHSVlNZPey90/p0hYEej9r/e3WKPb/jFiTmPI0XZKAf2rtutx0mXLDqaE7wMHbAcfLZ5c35Cck4j4OBEH+JZdtUOCorDYpZX/zb3bZ8+YRHp7SAdWMsoUpJplM0BFVWGxSmp5PWCNHL5gdgvc3KsqSY6fg10TFf9+tlfanNWIivBVDDomRmM5/V7CTNrQKqqPJ1Ag0xmVzDxEuIl5qbDtVrJZTjOQKcvAnN1FQsr+DyIUoNd1GtwZpaMogWj5vm7JhcylWObim8vwQw1n/qDjHNkTlw9kiYbtUMltj8jJndOojlaN4QSIaDWMIoz3iqwZSJDC0quy4vfZnCK4yS1M2q7LRz0HRTOgOp0dfzu7WMxV8dI59zB88UloEHSkQKC1ye8Ma23iMwi0C64RnlSTk7rnOVz4GsENNag8Y5DcpxNtLraZG92G/DJIHDcWih0jTcwMNW3cipmXej2BsBf/1MAlhI8vmm0l0cSkSlICf+JP3nufZN8YepKjsiyrb+dYzqxCrSGna5xUK1tOUk/hScdFE3IZpQZNJzY/qFYxGifph8O93TKSN8oragRpZxK5PsLEZpFgNCaJqh3bBZymgq5Uw2DJuRmhhhllk36751qcJvFe2OG90Mxb4Q8WbEjlo2FumUo0VVTvGAB2+z2nP2q3Z2YuPJZlx0drj+VuLqlXhMtAWC7k37W2sTkWxhxTGpg8/ytT0Qc/ENaVNIto6/pK1n6LTaK7WdDxLgmi6046H37WWFExD4EqBiLeD7mcXsF7FJRZ5gJBGB+PBUHKkFUeE3IQUNT2GtXJOGiFn1984ADvnmdOm4rVLYupZiwflLiMhFI5dWh1qjkCBY4XM3JYJuZAvXuQmt/8gApKwpegP+LrdxzWQkpcJMZdABS+Vph5MkK7xHn0/1wkhucT+AsBA=","layer_level":1},{"id":"d3062028-65d4-43ea-a57e-3d6daeb99be8","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"仓储实现层","description":"design-engine-repositories","prompt":"详细说明设计引擎的仓储层(Repository Layer)设计与多后端支持机制。分析FileRepositoryBase如何作为JSON文件存储的基类,实现元数据的序列化与持久化到meta目录;阐述AppFileRepository对应用元数据的读写逻辑。对比Entity Framework Core实现(如FormDataRepository)的数据库访问模式,以及RemoteServiceRepositoryBase和AppRemoteServiceRepository如何通过HTTP调用远程元数据服务。解释仓储接口(IAppRepository)与具体实现的解耦方式,以及如何通过依赖注入动态切换存储策略。提供不同仓储实现的配置方法与性能考量。","parent_id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","order":2,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Base/FileRepositoryBase.cs,src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs","gmt_create":"2025-08-22T22:19:49.6174774+08:00","gmt_modified":"2025-08-24T21:38:47.403416+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAb/OHnpU+CPDqdb6mtEoX5EnfCqQQE5UZMsvMeLeqtHKvt/5eS67SRRCiWS+xv9LDxY/F4X58KA7NSgqPEvUt1X1NWAr1Q4LkkzaWTJ9pCwQjmzNL/8dAFLQbDBQARJBYrD5o5BZnQNIeZvN/zUc0lyqb4mlMD3k023ZRcHwL7o9vXv8zOs2vXuqVqbhUcmeersG/TZlXoKanw2eNimyL3vJJnNwDQbTrGX6CB9I9OutTHuiNkKIIhh0jTkTSiLORNWRALoQVQVXndo6qR6QLyXn+fMJjk/mJzw5cD/3OZ+t9NWbU6WCSbFCIVzFUSMicx33j3Vfmg+a7IUcKj6XKmkTxARUlOmvedOYve5+7kCp/kF5LmNyylvgu6E93eqy6+PFm4HE23N7/M3teBSHDyk3teU9GIdzVjHWUynGFqdbXTpG/Ois2y9taHA6ORAgupEhQuVqXipBgWGFeKCWpoALMBzEl3+31niqsW+tYeQVrS+QrViF+bPJa0pkZgGv7sTnNNiTS/ULxPomIhNAEfujHAccElu5eeYlziiT0vNluxNBjDJO0eTKwLuydY+k/HgHTccnVdjTLA/oNx4+dkfmMqm4aqX7Y5tuRi+lq0fhfA68tN0HzhtSu9GOE5qoThNkxBY7r3gV7TdvKnAf/72CCyxrvXLHUqcFQeBZDoG63LrxHKu7c31d5H8YQ6+6fN/fnyHxo+byAFB+pHxcsYXtx6ljUSW+PgxelNjfVx2s+0qIMdNsJj/CsNsSjaHfxuEKLyFmhg6+ITIMwqZlei8WjKhBQ9jMd6UrK3sxa18ulYiFjuOYDOTYFT7Q1A54x0HLo6SM2zRPKUcV0gtXP2hX4TfXpZ9VkukM84c9SOzDD6se0VfMiIiu04p055QkKY54VRya4qKki5xd9dN/oxXTpSKs98J+Kj8FR8bgGpGVl1uVkNVyF6dp7uI/ctafl3yhpnRerVyexFNKs7QkJWyZSw8ZYNzq5/0n3+3cY+6Vqw0BEUvK63wBimA51Pg42r/saFU+FU7d+ogDSBmFKGbytRXX3OPHuZDqJf27t3hP4GnKR5SV3+tjc875SAchFFBPQ59/agqU9+yPVkcJYOlomgPKavfOJWnbAm7MQJlRp0dWaNHqwnzS0Ou7d4y4tto/CC5D9WD4wg1Pipf2j7bVd+ARNhyZ5OixnBYp2MLkH5ioAfQh+Y75ohPgi5BKsfHxRc7b9A0Gbk4NSpEdh8wYP6/S0A5ccBgXqnD8mG9FDmgdUSkuyNKW8AR4Co+FxsTe/EuM/eMsuIxUIANOyMbpsHf9upgDyacVVsr3azn7dA81TN/qWYyYcNPEoVuMjubeMIoWJr9pp+S2Jv27o+ZIiWFW+0em6bTbyPJ18eSVPPK8Aocfyuy6wUvZvCXW+8UHNnAYDwr4eIikNpsggbmxotnmYZcF4v4yOLJR2BuL75tOHmeg413ZDwYYauyhJUKpVsR0P9ykQ1j6x8k3RQhsX0IAjZCq0/zBaBP346t1GwUpVWcvkXGpe09dH0y4zrU122feKvA6l7rno3kjnG0eUQxUp20vYaaCUY8qZaE3u2b0q9dhRcF89cwpLlhLUOP7rEh7FsQ3DuovmSP4ifyzB9F5rInqvONUt0na2PftTv2sAEenSSG4PYBJnNWgc8KNLQ3byy7/x6n/XObtYXooafGTKso58vjm9blv2hCLlcjjBqUudf54V2DOEzyP8fBVdtTjxPMW9lF0Yo8JJLb9tH+fptSktvGr2vYgNQgOCTC1ZHgEiQqfi1sf8v+bT23gbURKpauPX98GGDbVhuNw=","layer_level":1},{"id":"bc9736a7-f157-41b1-8432-687da240a40a","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据访问机制","description":"data-access-mechanism","prompt":"开发数据访问层的详细文档,涵盖FormDataAppService和TableDataAppService提供的API接口及其业务逻辑。说明服务如何通过领域服务(DomainService)与仓储接口(Repository)协作,实现对表单数据和表格数据的增删改查。描述DTO对象(如FormDataDTO、TableGetListInput)的结构与映射规则,以及AutoMapper在数据转换中的作用。包括与后端API或数据库的实际交互流程,异常处理机制,以及分页、过滤等特性实现方式。提供典型调用场景的代码示例和错误排查指南。","parent_id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","order":2,"progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/FormDataAppService.cs,src/RenderEngine/H.LowCode.RenderEngine.Application/DataAppServices/TableDataAppService.cs,src/RenderEngine/H.LowCode.RenderEngine.Domain/DataDomainServices/FormDataDomainService.cs,src/RenderEngine/H.LowCode.RenderEngine.Domain/DataRepositories/IFormDataRepository.cs","gmt_create":"2025-08-22T22:20:13.2934656+08:00","gmt_modified":"2025-08-24T21:40:22.7675143+08:00","raw_data":"WikiEncrypted:M8uljGDGJ//mcfRJly0hh9KMI5CVsxe51KDtEOnUfi2LUmDIXKjDi77qnuoUYxC0fZta8bQfN7j/ws+5/HnoILrDbUBtCqsSg48N0jrVO9fE3hPFGMiAjhdu5b85zKLGRM4iNOv+ImxIwCBrTMX3bfUSgkFpVbNpF25mEMnExkfA46YwGRC1GJEXtFMZXFnGhGrevBprURKcRvEraOa6QZTOkXnOTecRHRtajkqRoGVZrgrlCX1yrs5wNYVq+wrHlsMIgX6CURTQbbqSBE+r3WUdm0Pv90qyIAEULcoxkAJnjYqtZMr3v8uUejlSbFnBYIKd/hemA14dpFyRJRdRAzjtnXDpzJ3IPisZOZcVTAks2UXhKglGwhtELLLs5ig0Yc8hIyYPmZ61iOaJCx6tiIDgvAkm0e/UOseaorTw3JnyD0GHQSGrA+4dP4qBpm96JyRC5HNlkS355gqRocc8zqe7Fv8i1MYD2AgA58+yXl4v0/frldX4cBn9CPV5/i4+RftjXkWYJKtEAe5yudn4ojgAHApjT63KfDqdq1FESbeRqAjhd9LCFaxgAIc1Vm7GOYBPYZ6SNSW4syDxW7WavXcN4Fr0teO0gPs7SN+gUNSCa5vgA7mrnMK9TNuTINZgf1RvBQGpVFr3M7mUzDH9ieLtVI3ASDnnikiJdbnpVjBHA2NCUECc1wFcgD++vSstr1XIESb5XzZ5bWtKuJTAA3PDgNpBFb/ZdXqNxtxTRYvC0teHZsvX79aQR+vCaB+ywd3DiqySj1GlJHyHnMM56KQpeffjTIzbKLFKTM+fo/6ffF3KfHs/uNq5xahGZp+xpY2jC3XbTYSlJTWVOdBPS9rU5gUNPriglP5KsmvGOaEAd5hTUZonD1jMW5poNGnJeUpydNXHvVSP72GGQlIFzFSV6z99DzlKdWktWEClJeuTJSlqTEpnHtAc7LHQnsrV44HEqjaRanJMY6MsYR3t4XZk+1gkcdAO+mOPnMaqb67eYP0D2gEO3jkFaR6Gnvt7yFRu+AuR/3v6gPGSWrb0K188QPA2hlv0+v4xn3xAMe5W8o6BSMh7kgHU+PVES+q0MncCRy70YC00eU9ACU/3VR4BRgcC/xnRa33X+uzXY1IVa27C3VvCaivdZI7y54fDlgOB8DrePrdiJ8F7Oq/0qO8FuE6pIYURSYV1RXadVQcfMkoObHhGislAGrQ3N2TlMY1/h7Y7HJy8Sx44Zn1TrljxyszcDivedsYCf2zG6J9OZNGdUjz0CU6OG4hQ/nDhOu6zKCqc0wygavTM5ZRtq+WbWkqFjWSjjo1OmbMCIOoYXIsYQDYyQ8qLEwwlt4Rt5G+9hdOmSQV/VhoGzKXI/tbOV6lBMpR4gpshZvNx2h95lQ++FlPJpojnQFtXOBEIVxa67RKpQPvZNGCpYzsHdyzrGiHA7zpctsWBRqXdccBSvuLNqVKwxcMMIRCke9IndttDwDDP/bX3GdBtQssuiQ==","layer_level":1},{"id":"72ac7e91-db1f-4263-9b47-b6784e8b08c6","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"组件元数据结构","description":"component-meta-schema","prompt":"全面解析组件元数据(ComponentSchema)的组成结构与配置机制。详细说明ComponentSchemaBase中组件ID、类型、属性定义(ComponentAttributeDefineSchemaBase)、样式配置(ComponentStyleSchema)、事件绑定(EventSchema)和验证规则(ValidationRuleSchema)的设计原理。结合antdesign组件库中的JSON定义文件,展示属性分组、默认值、数据类型(ComponentValueTypeEnum)的实际应用。解释组件片段(ComponentFragmentSchemaBase)在复杂组件中的作用,并提供如何通过元数据实现动态表单、条件渲染等高级功能的示例。","parent_id":"8aaaca53-5075-4175-a837-be8548ca26c8","order":2,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/ValidationRuleSchema.cs,meta/parts/componentParts/antdesign/52391a70.json","gmt_create":"2025-08-22T22:20:55.7895053+08:00","gmt_modified":"2025-08-24T21:41:57.7379369+08:00","raw_data":"WikiEncrypted:4Zqjl5aZEo1Vv5NKBpebToINWPA19SmYdJcZ/omRYIi4Z8ZOXT6DkeXZHcBkuEXWCaCZ2PJNfjDd6wPl5Un5f46scYIuYbC78MW49WxS5a4ZPofikmfp07jBjQw50qMwtmZLBaYDAlo4q9psGT/0miyJcUXGcssklkHkn+hZ5+FmPwH5PmHUWBbL3qqM6s9m3Olqy4ibWc0w/BHM8v5fvsaTn2MoToNZz7m0DgTkuT4rwnNOAZfPpgkglOd3ZqtiEN+DdIJ6Z/PyqssNtkufC5DdcO/ID/58QFJqcB4n4AB6Gqywo8RHIzGb9W/rTi1igUPT+mhhcwWkUk4cGLEfR4Ku16M2u14uzXHe7opacKuOqdn2ezJlExyhG5kxP0vuVZtOSROoAbpSkgv+V2CT0hGmE5tCYz6bybVPR+HRKz71oX51SDjMvwMvL/BbdreZk4Wid5dOFZHRIKK1V0lcXmpnZmvAlV43cAhqG+SKKW13mXbU7zrAWvib+RFu6dy8v7gPvna64BwMRvL2ZEe9mSRQYyZIEL4YnbBJ9IplIevyAckJOMG4Fy/5IH1hdqE6KX3szNqZfKqa0Sutf6kU0zI6IRYiYphwmKfIuwblanAeOOFvSDGMIz+PifzSoKjNvjkHeFKO7DDUwTzZPBKba4EOpmiXsEHKCoWGsi4bXyVwP1g0SV9KfIle1mO4M28lHEQ2tJTGWYULASJB6P3kgnUnRmJBkD3AEfnjAAPb2znt0HgDlkeLHlr1t9iBzXoaibaVnqbHyKJvXfqeDepbhZnETEiwf+sn39aW1fDSa6uvUe43v5xycWbz4IiCqXBbs1Ue1fCaZZflprZvlj1j3Zm2B10RLtL73XNEP7bsvdI3ZMB+TJJ+KeKOV+JA4sT4S3F/6qPp7iK8t8P3nv6dkl8t8uZn/8DySjCXK/Dgj+0tpyPRxFPXh/a+j6qOKatT2mEN//I0tQNhs93OAqyI1A8clOyoeR/6ZmpqZt9VCVNhAWKS7xbvV2V5gQQpYBDsC8wPNXdpDZLy6X3tfnBtxKnIRKAr5nksEvYqqNPu5yEDuemdjOYZstWc95LIsoUYdvznNg7rWPRqkZZ3Tq+j0UCIysG/oKGx14okSAUfT4+fb+2LlTQoabVXcoHLPApvPhEWBlhfgPo4K9ZPRHvoYnMCBMajfY3ikdjMIbjNkxfKvokK7j2dw1IW1FrA+tnbeHeD41RF5ljERRmnngjUeW7WaTKnUAwkZ6CpaYXeHABBUTN4YTQpS/GnkFGCnkwDXpvNXLGad6qdpY0nJ8c3nRFLFklLpO5EyjXCAzq4HwEIMSTH1XH7+Gpt56BNLgK7yV0nSbZkv5AGo+RSHOjGx8l+Bun1ZKMPmH5DDgLesao/z+oAPjSR3tVcAnNdkHJ3OG4o88pW6u8A75zi5VNU/S2LMNBl1bfnvzhgQ15cJ7VDYjf9tMa2EXSI3b6hME2+WVxwLbMnPH+lamdYjuv0NVJlKOw7X+iZh27sqp61fvO4mq3NZ+dtrcPsaby5DhQIH3BFPwhMTxcMEXCl5vDVzaT2SBu07wALITrO61gbvRf4BKCXmeFDfchT14D28scZS8cQyvDd+u1AFObEAXS6Hw==","layer_level":1},{"id":"6b51305e-fed3-40c9-ace4-74ffed8613ee","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"主题定制","description":"theme-customization","prompt":"提供主题定制的完整技术指南。以AntBlazorThemeModule为例,说明如何创建新的UI主题模块来替换默认的Ant Design Blazor组件库。解释ThemePartLayoutBase的继承机制和组件渲染重定向原理。指导开发者如何映射元数据中的组件类型到实际的Razor组件,并处理样式隔离与全局覆盖问题。涵盖CSS资源注入、JavaScript互操作集成以及响应式布局适配。演示如何通过模块化注册机制在启动时加载自定义主题,并确保与设计引擎的元数据兼容性。包含调试技巧和版本升级兼容性处理方案。","parent_id":"1e1f9cb3-49a3-430a-b3cd-3b2dd4bb2603","order":2,"progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs,src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender,src/Common/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs,src/RenderEngine/H.LowCode.RenderEngine.Host.Client/Program.cs","gmt_create":"2025-08-22T22:21:28.1571612+08:00","gmt_modified":"2025-08-24T21:43:59.1398909+08:00","raw_data":"WikiEncrypted:MxodVyPG/Qm3b50NiN9IZsCNNUZ3nQMWcDViVmGOLpbX3nLuIisZDNo8Rj95fXNuzIOJmx362I20kPdai9x/XXHgy7LqntkrhHEUAlqSVksdqcjAPl2TkbI+ri0cROLhb2uzMqOQZ7e4OkkGhRMjNgS8fFeV51Esl9OuEP8FTQ7rmL3k87FwpOrStvhEOARVXpCk7mEqaGttjHNo5C9c2XToITRLBE0UuZChyolpfN6Y/u+kEcMDKmFGSkBD9uXi6WjFs+xMXZxqobMO1Nojv6Cy39lAd/30hhRsktAASmjc6idWTGPLRooOhvKP5X2X3IRx9nXEv/qJLcyYymNxh0uzQQclWT4Us9pBmIM6Meeh06R0iQlqd7u2Ifxm9LXoZDGaM2igYD0iwL3w4En6R1pH7uIexk3XVOwqFmhAPxf69qP/u6dHlTidQsb6yOQic6k+cKoBpTYgWk/Kgu9pSU5+SWjpBMIKdcxg6tJzIefcTqP4Y0Hd2qr6KIy+YEmnmeUTpJB81datmVGIevCuB3OgAIAYVxfQ5OhzNAi8Wej931R7lAxF1oyyVmkkG1gVBS7O71NqbCIixu8uKtCki8bP563EvWBgRKi+qh6vu55geRZMZ5lg+7gOX4HrTQZTR2oLdxdATSRHJqjNUbOUd6pzc/XuGRNTbjCpa+llfL0KR9kFas9hMBrH31/XEdkqNzAyjO1+Ga+OUMFt8n73iKaWP1hmkddl6wLaJTtwKziL4oD3XVxAyCAgm7Uq+YIqGGtdvzeLJSgQWRNdkEPOLLkBANmL5Lk0Vi9saSkP2Imi1kqjUyDKgp/xrgVt0Y2OwIpTaV1EeriG31NkSWxMrZDao9w05zVqv9b7wvtauEw5yUzeRFp4Q+7pkyMyq636rDIoRtyNtWD++22J4oIg+n3QGU0EtUWo5pqkWP6MRU2cNc2g811bbGEyFK+R1mfsTUvbT1zwRsK5bJ1HvHZWErcGCB/JdwOzFb8FWt/NCgnM+4691rlOb+nmhJj1awy3wfaHN4ixbOS6d0hXndMZ3N8T9jtgbWNvniURgmbgNlRSyYssc/p8hGz64UMtcpxs9TAVbtQKbbtNxPE7S0kc45+w+2UYF51+gE5jAhnDeeydWAGWXZf+RpN05AACUYfP6Ts4w+zSSJzbCmdOOlG7BlWfoYvZh8JBoILbo2ZmficSy9LJe43d3ln17XVXQIiZw4KVZOHXDamcEN1IqhNyKGsfU4qG29Q/IbvYZp/9hVR5sZZmnLJ0PNOcQMVPLRfo0K0hUm2mcPYCdnjRP4XjHWM+9ZcVPSTtEKSFmkhSnYk9IRIz3raSZT7fslerxxyWXE1KWvJyJKc4nVvNIiiXk3X2IkVRwEz4waRtjSktLbI=","layer_level":1},{"id":"3e42833f-debf-4ec1-97ae-33628d0eb521","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"组件调试技巧","description":"component-debugging","prompt":"深入讲解低代码平台中组件的调试方法。介绍如何利用LowCodeGlobalVariables进行全局状态跟踪与日志输出,定位组件渲染异常问题。剖析动态组件加载机制(LowCodeDynamicComponentBase)的实现原理,包括组件类型解析、实例化过程和生命周期管理。提供调试组件渲染流程的具体步骤:设置断点、查看元数据绑定、检查属性赋值顺序。列举典型问题如组件不显示、属性未生效、事件绑定失败的排查路径与解决方案。","parent_id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","order":2,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs,src/Common/H.LowCode.ComponentBase/LowCodeDynamicComponentBase.cs,src/DesignEngine/H.LowCode.DesignEngineBase/DesignEngineLowCodeComponentBase.cs","gmt_create":"2025-08-22T22:22:00.1321803+08:00","gmt_modified":"2025-08-24T21:46:49.6278926+08:00","raw_data":"WikiEncrypted:4Zqjl5aZEo1Vv5NKBpebTvX8iiDGAd1aTw+lvSJ8/hvFKEMkH5WVr8eBq6pHepY3w504mqXPM+uuv6higvhBv7Zx2Suu8h6fnxBnwOh+El7yAq0FxtOe1JrIgBc8b0PTLlYL/nRbADJjLFHBTkx2YcYctKxH2a7QGzzVYrNNJxzdhGvIv21UMkXg0UFV9nqmZBBIAdYVR23fAFpgxLZfbLyw+nRMi4sAWldPWsM74Is8++oPLCagmxv9cPP3l5QYc5m3nBTyDtS1mSHJEnL3n520MiPYsjlXJwuFnE3u6mOU802nSvXbySIkPolIlwUDddeJvC+LdJntMs2DJKzSI9cNZIqDd/n7aspFq0AUzajCMjBM1gGSaxxL8yeHuRXYEyu6LNz6pKBBVGzIKsh7d2bwOuA665/HNWOdP6Q+jYAytSLokJATNZ4MEzd1WiqvWHOhJR6mhU5u9r3hBdOU+ahYtNJgr1ipCpxKOBxu3nEQzJzMMRrFzVhtq/t47oXOZ76DezLTV/K8eFsYtQbjbGYM299lEzZkBdAOsJFp+l5XOwXjyNWL0iBs5uPz0eOiSt+h1xydnTRAn8bGYrUgeNjRklZd0Fp+DJw08b8zbKlwTy3ML3yyHyBFeJ5BCFoKphDajC4kbiwG1fbs1iwVGeNYQe+mlW7xWBBEkKPFEDJ7QO23+bw1KV93UytecNTgkl5d9Tur57HcJKgIRo662MOqrQ2RivwxK6aofs2/cGUX3lAVyz4S+Y8ECf9khqfvqf3t3+4HwhZewSf2t+JKjl1sFGeBHCvd8Pig9YuOXiECnl9fuL3nkEYwLX/EedxZiq2ZSE5HX21eziavctIb91TSuKrjPKBlUMjIJD1aSPgmF1wjAWCPdtGjL7yx2Clg5iX0Iymltq0UAnICkNr9g6tBhwoQWU2wGNQGAfJKkMYIlFZOFgWk3gBInXUsTCoDYsRUCzf3cUFjeX2fhnrFxYG5my2W/He9nO6d+TOT1Rawm6eIYd8mXLLqY42OYXp4nj7Ognr3MQmBLr/OTjqQEyTD0WDZ9O0fsgA8JjMpmvn2TYgiER8EIaUm4YWygnNNphfF61O5aN040EzZP/qtXOuOAKqlRoqlpW2L/4TefMcyZoxdPuygxJ3VrWdzEyRYGSqyB2fDrxrtKWF4xO7PTQ0jmXDpNSDhO1LYen1i3Hzw28awi55MHsFGg/WjLpYlhfZ7XSDG8OqFR0+PgtDFUg==","layer_level":1},{"id":"8ce24715-ed98-4599-8450-cd4e92acf954","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"元数据同步机制","description":"metadata-synchronization","prompt":"全面解析设计引擎与渲染引擎之间的元数据同步方案。说明当用户在设计引擎中完成应用设计后,元数据(应用、页面、组件、数据源等JSON文件)如何从设计态持久化存储(数据库或文件系统)导出并安全传输至渲染引擎的meta目录。描述AppFileRepository等文件存储实现如何支持元数据的读写操作。阐述发布流程中的版本控制、完整性校验(如哈希校验)、原子更新等关键机制。讨论不同部署模式下的同步策略:单机部署可直接文件复制,分布式部署需结合消息队列或对象存储。提供元数据加载性能优化建议,如增量更新、缓存预热。","parent_id":"87d35f84-473c-49f7-8192-185a0a489619","order":2,"progress_status":"completed","dependent_files":"meta/apps/caseapp/caseapp.json,meta/apps/testapp/testapp.json,src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs,src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs,src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs","gmt_create":"2025-08-22T22:22:31.049137+08:00","gmt_modified":"2025-08-24T21:48:57.3981207+08:00","raw_data":"WikiEncrypted:pjGuIDHO+JzqEKf2Vs2HOvD24sDStMG/clYWHOI3lDCL+rpMWiFKtZpvX3gdxC/rZYVBvX6EB342XG5adda9wo7+8UWP3FFNQFafvI3zTGej9mfQdFL+RUqwxh1oOMNh47/7CXE3j3tkpZnMC1hsjZUGwqgfbCQwjvRh8ME+IVjWP69xj6MZfXgY2QfEeYIoaJQF/vlof7z0aS791S79xjqMQikWEM0oCU9SFupW3Vlx0w4LeHcz4KCFRjzDFMd7ir/V2lpe4YaRME1xXqkxxfJuXNkxYJtrZ/jpF1fSuETOVKTouN8exI4w6CPz2iqBzzotmYKbNarsWIM8ByaRKyM4fOs/+tVGzl9dAw6x9TNIBOBSUQosV0EOATuf6PbDYcCZBvam0Rsz+YDMJjL0kJkqZvbQ9j7UrScUA6KCjNH9D+WRYJIJpJdYd2Aw5uMcM/MeqDxoSfBGtpt/RpHzFb0M1PmAxtvJOTUxGzIFsoVg9HnwOVxZ1fUESqdAObWNkjuKFHIljFsJRU4yWZqFyMVUaizJ3LPhlgMuPa+6wUCS/R04KMrrelpydhTw8OOeJYF6pB2GzfcAgy+6kfGpKRDgyOeWFWA3bTl3ySSloB2+fxhjUm/56T9hQu++XDCwsgkZf07kzae12H/H9r+ITIDwhyj0hxsK2EMJUfY+cB6ljw+gItJSw3aGjnOZ47hpZuiNPriYpO6luOJ5TOpCMllD7ff+BSrC8++dLO5AkCailYgxZY/0XZmmTi51r49xO3eIesrh5uo52B/3j5TgE78F01fTkXnhhSyiADd1VtinN4jDYP3dn8LsTSEtSTaTV3SKngewcV23TegE0DdDGHjD2TLBMd/pJSDBEXqhp3MKb75tzMMMJfOsWr2wqwzpyxOdtJWm8NcpK+f0hAJZfpqDWjW/APwCPJu4t5qJXwgk1dvH7MC5vEdBgiG5U2HEEzX+aUf2+QyD06aR/EB462L70s9hgqi6xWC0Q11X2W4TdbAlxvE3JgyBFDqbTI6v5HbYngwJYS6gkGAyim6gmnVcTgf4Y+s5ZvLoA277rKOT6Xm65LXVP8e+4s4a3kN1xdugecHALbvE8GvAwBvCfWX48/5afnlQ2wPnTUvOxBohgFsVEfvhwZp3KgJnm9IGbzcZZ9cI97p/mHjkeVCQl/l42mE/SKSgQ7fS4lhVo+FVZQOrTLiOUOToYS1H2Cnl942fpwRpvjOIxXiAKfboy+wyFl4fQR2qeSTq6Ri2075TomqnvOO/Fxj0YHSvVSTt/EtxWeaKkZT14kN66A7et/Ibrr3WyEzTXdQqLWO2JWR/5Mg86n/6/u2fveGXLhmWMgD865GgzsGdv3m+bKQd2SQIrw48QHWI6MsRzNrfvK/CVS5/2Ii/8NrwRwcOT6A2O+iAZTBusewG/y6v1d9XlNJYE0q08F7TprnyFqroMWneoBPrVPewvCW8YiZ82us/cUmMER/4SdnV2mim0ZscFiGJU1AMbVKVmpdf1UNdX7qC1ShultgamOtTBpggXD4tJJwxzKRhD23jHN5TkuHaZMhQuD91CXS42dT6Z8vgUB78kHozwxcDCMlEIiWEs6YUeLSGMtULIWSIDP4n2O5gIgOIvUQtSqP7OWlL53W9wEKzbUKehHdiIQBIetfQVRR04eQXwg4kOYWtgFU5HmlVZ31u47rrL5V08gw3FyJFNrE8AzZWi7rvhKCxkNUMnXVbnr2hlVqjVGCDt/0cZlXFLNu8pZZoMTfEdFDx9eI9bes=","layer_level":1},{"id":"e1c12883-dce7-4ff3-a390-f443525a38d0","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"菜单管理服务","description":"menu-application-service","prompt":"全面解析MenuAppService的服务逻辑,重点描述菜单项的层级结构管理、导航树构建和权限关联功能。说明服务如何处理菜单的增删改查操作,维护父子节点关系,确保菜单路径的唯一性和有效性。详细解释菜单与应用、页面之间的关联机制,以及菜单项排序、图标配置和访问权限绑定的实现方式。结合代码示例展示菜单树形结构的递归构建过程和扁平化数据到树形结构的转换逻辑。文档需涵盖菜单状态管理(启用/禁用)、多语言支持策略、缓存机制,并提供获取应用菜单树API的请求响应示例。","parent_id":"be52f1c4-850c-4443-ba95-8808d1e5b997","order":2,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/MenuAppService.cs","gmt_create":"2025-08-22T22:22:55.1545958+08:00","gmt_modified":"2025-08-26T23:45:37.6318341+08:00","raw_data":"WikiEncrypted:VlNwZ5SiObTSCaqQptW+HlFU24EP4EEoEliUwanbvh771zJPyZfdoaygO34EkVS/HYeoSh5ck24Yp0WuJcQ2GYtXWS1TXKGpsZGYG2jx1ozaeEstZOfVfslp1GBuefrdNNK+S/3jGNwIW+aGIIS6i26h72/vpesm+CegCo0UaTsUhKNSWcAnW/WvOa5LttT2rBgkwNd8pgWbaXY83GcpEYhqqllPVMiNRAl6bT3GwxaQyR4rpwxgWDjoneoYhnd6olqHzV87PxDAlrO9wM5XHpoJgXgCVxxrDtvK0UtMDdQsCL7KwvJhG6hLLsbpBriigJ1VzBekU4gXxNnkqi709t/endYR6ogi6krNN1ieFSxgnuc3AdZzO0C841IVf2y7PGyaVOGHl043is5K/giCGjEhX0zmiJFqHtZsi9U/HO9sdgzFgmZa2pf1KKU1hk1hHq9kHvICzDNMRyXE3YQXKpmeHevp17VggahJ4WRprIXvhPj/JZRHvJAzgTcooa3VC4drNRpMlWJuGKaJr1goohBRkz3Ck4mFa7eDBTcd4rIi7cAkZWJ+q7+630g8hgpAokINaUWdqPulnMHjnc8XcLyu1Rz8auZy2VQ0fRpvN/oH3OwaC3OdtorHf667iB7jFp/pNVKxxGbSX70WD42ZbL64GAz/hDycU8Lbo5CpDXZys24HWTz18r3Y/BuR94Sa58jkripQsAmrLlQfj/aXLWDe9uC9ebLbOeZz/dh8f/vclWzX/jBTEkSttyfMDGwkE6dUNcLo73Y7l4jN19UfzSp925K+LZCk2foGj/TuQyMFAHss3NPqm4smx1YSmnhFqudK6EpEm4jKsSOylUTWXm1KtwuMZftwU4GRbHWG3lzrMVcWxcMRwdb3qoKfMTJDxA/TvwidXRNLSAWrTqR/B+vhXVGW7aOrrqs+J5Hq7pSNCtlic8VL0qAM4/GuhIGkj8N2fRhwsiOQhjkfZpBJ4ch7eo60ufrq+mrT6Pa9lpd/VDXwzprzscpkBFP9R7R9ErG7jltZARHYIbdOlVI0vzp4Z1VD4FRqkzf6NnwS54xzy9zkshVKm2TKRa2eSWH0wc2xjgGNlDNcchxDhPgULg4Mne7twcWWThtvMn74MYEIpYbAJ4ZxERqbbmecr6oJ1o519cO/AmrCZiZwouIhead6x+864vkYZ+97gDzN1TJdrFrIVVgdInulK2w0PVRn","layer_level":2},{"id":"74e284b2-0e9a-4572-ac84-c08bff07e383","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"菜单领域服务","description":"menu-domain-service","prompt":"系统性阐述MenuDomainService在菜单层级结构管理中的实现机制。重点解析菜单项的树形结构维护、父子节点关系约束、排序规则和路径生成算法。详细说明菜单创建、移动、删除操作中的业务校验逻辑,包括循环引用检测、层级深度限制和权限关联验证。描述菜单与应用、页面之间的绑定关系管理,以及如何确保导航结构的一致性与完整性。结合代码实例展示递归遍历、批量更新和缓存同步的实现策略。提供菜单数据加载性能优化建议和常见操作异常的处理方案,为上层服务调用提供可靠支撑。","parent_id":"e52a6571-a012-4e2a-b5d2-e5f94c01d367","order":2,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/MenuDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IMenuRepository.cs,src/Common/H.LowCode.MetaSchema/MenuSchema.cs","gmt_create":"2025-08-22T22:23:24.2906936+08:00","gmt_modified":"2025-08-26T23:47:53.4953635+08:00","raw_data":"WikiEncrypted:pCo7e1DZrIkbNVZ94UpHerPbsaJkK+jU3+SlXRpdMein7fi9pRKrfxAupndDqZ/OpqDfsFJE7jbdRZWp39l0zNtJDLF0RyiykyStb4zeplc1mn33TX4iNFAIi14jxgHyb47LcvWTHYAZbgIFRCdqRheAH2LGib56ouzg9cW77rPmgeJvt/sQlv+FgqDchygecmAVXCWXeCrDw4SHIGg8VhOiYctPl3vSjZx34Pfe8WZl+nx1mrH19cBzN+goHlWvIvrNtsCPSljhcV+juNzQNusaLb4J3jVoPIQ0FDvaKWaayIjYgOaXn9vy5HMNS+1reYjTLW56NoxcILRU86Et8Y6ypViGdLPsQX5dZt1UBipe5Ji7KSTYd3Reh+gGo5l5S86cTNTfCzxsb7NsRbRoiDpUxzupvtqrLqb4T6lcknXAh/HsRuu2KlOCkt16xGNybjELXTIHREjJcZc9j3BOqxVjeEHJI99AHH/bbLx7kqeAt1rkT+ffR4ZHtGulrvrWb7QmnfvbBdCTOb07HI+EvOrcfx6wS5nhjUxYBU0C9D5m+56jtPXeW8CuZi702c21SqbQpu5LJOJ1My/T1tm+GkKvV49e49YiUUd9utoKNrVGT6Ds1XdjHzf6l6sIMTNLb69WpUYTsM/950Bz9AVASKJaoYu9AzzCFEq4Rgg0p9emNTXsOdBEHXAsVYSCPu17oMPwhDkS2jAaEC6j8DelMIr9cz4ai7E8mPyuiUTKvO7LuIibvf9nnARI3Oo0Gde4l5Si+xZGhD/v6X7piYb5vQTvm1G5JNlINJcCbrFLaHz56Onh5Z48pLNPlnwbfTfLNvKRJ3P6JWsdlUnx7UPJDo5Km3YfJO6H9hUV4OoP77p0mZl2yEQ+cPgtTbceLvmUV0PDvFwhL0p4rvy3QCZbd2OfPYouTzNU4+S10Sdl/P8+FvxYaK0VA9iqqdhJ/CGk9yoC3YPCdpRPo3qP1ZsJ1s3I0s2zHPT86mxlNTQ5GcHwvngl6xUeJnyKSW0JzMGcmROjwY4zAab0ySyYLpOuIJjqaNZiLoRXbhZjSf3Uo736yQDJsMAogX/aI5kPW1BUtdC4lwcy8fI4fpDi4hLEZlB3CMiQA7NAIp+2FTnM8kzg+OzXoiEGqlEN7RhndzcB+p+tp5MolbQMXj3HDQfSVlTddfAJkEMiOpEDXQC/P2c1iu84vzGUfyUN202KszELdvaNt7c7IK0njPM8gHOlBhVFNJGn/pT+i2YwqOOuc/5yavBD+efnk0v7zq5Yhx8oFfcdp0Yk+6iSTAXyza2mGC74acx4oDOmTxjcrxl/yJ/PQgJ9RDCkOe6R27Uvghs+s1pEporfIiij9qXhow3s3CK4QI3qCSHPduFuXLXqjxo=","layer_level":2},{"id":"13b73928-f482-4f7f-99ab-1b3c3f8a8e75","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"远程服务仓储实现","description":"remote-service-repository","prompt":"全面解析远程服务仓储模式,重点描述RemoteServiceRepositoryBase如何封装HTTP客户端调用,处理认证、重试、超时等跨切面问题。详细说明AppRemoteServiceRepository等具体实现类如何通过RESTful API与远程元数据服务通信,完成应用、页面、菜单和数据源的远程读写操作。分析请求序列化、响应反序列化、错误码映射及缓存策略的实现细节。阐述该模式在微服务架构中的集成方式、网络延迟影响及容错机制,提供服务地址配置、API版本管理和安全认证的实践指南。","parent_id":"d3062028-65d4-43ea-a57e-3d6daeb99be8","order":2,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Base/RemoteServiceRepositoryBase.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/PageRemoteServiceRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/MenuRemoteServiceRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/DataSourceRemoteServiceRepository.cs","gmt_create":"2025-08-22T22:23:50.8373587+08:00","gmt_modified":"2025-08-26T23:49:38.7342368+08:00","raw_data":"WikiEncrypted:cwcK3lcBC27E8P8fDmfwlW4/7MZKY/Dn8CUg53Gae2kIUk77h1FovteJTdn9YSX5BtHLn7zbydIoy7JN/a9Psp0LkzyrHEb0YfaceQ+/Kl1ychQD70xomWHYDweC/XCGNCZx/JnIVEafL0hHlTocVcPtsMlOywcERl2uRYaIgE1ppRcWtNC+jvIr0b+hzt6GMi/Y1GJXKOUa6XkJpBd8Cqa9/4KWuPZwO6UM+Da/b6+7i51F1wUP0Y8EcZMDV/s7G5KRPmN/Yn1j/6oAzyoZ0GHh3daFScxJmgWNFmaV4z8j2eiTrufQqhpXnfyF9YWQqLAFxBSSFH5nqbtgaKbL3kwUZ3G4wfF3tkTiBc7FZG+H/37nbBF8OkR7lYQrgfaS8piJDPIdkbfmUbijOkiBF5wKzBfoo9sCqj+jXIVr1ztjpP1pYJqsaRVGcez9adWcpLMtBrcrO8IzzB0ouefSC6gk+9Y6vucNDsAMY1eyCoUsIXJY0uPBqHyRyayqP/gASNm7cLe47Us0/WtO4uxdiaL7dsy7leYHYEkw752Fg1PWN+Xknz6W7h3Yj3aQpck7ImQw3b8rcTNMLT2K2cjujc/YLldx1q+xhILt15fpeunIR1ZVheu+jer1fTzWzUHQmYuY2QZufhrptjAtEq6jAkNg+jGVVWbHS6O/DqXjA0i+Dr0cj3jNcjMJVRh0d9SP+2eKZB/nrFglbNCED5y+uMISCzE5IsBpHIGOqtyN0J6nesFUwII/u1JQ0AtDP9AKUWfU/WHh+fEyyTZToDQHDATgLz7YXiEkBYCdJczDxlglEQN+pZ7SkO9ZlDLTazi46of9Ig5d9d7Gszt/XPfYmTexPPQqyAFb7PzPWqp2pbxhOcom+vFABSCSXdJsLEe5Ein4cW+GNyFvBCznF/l+GRKpvqYxYhZoS5T2dnNykL7cpSo4CUtlS4oPqzPRqX1evi3LQt/BaCpd9tcRaTglqeMH0xdUuY/km/CQPzAxruYvXbHRuQ/ZVEJ2NfgCAumb1sPys7qYuZwOcAthppN+lJDhZpl6msl18l6C0UQHdyatOYeWeRwKkLuPZlpmAREKsSGEPDpVVyGsQMYbgM7yj3KS/r8bDYhr/xWdp/NNY0pccRcejW4V125x7JQMzo3kn8zDX9xMYjh+89sYmv/tDXc/4C+1NrRkzQDvdx109yWBRvJCrGv9DOQPdeNpIWoReHK28s+Dqp3LtMomuc/CmgmhUnwx5gzozu3VPKKP3zhy2hFwqfaqYWDqRvlzJNewvqHoglsf7WABTdNGzYzTESmLZsN1+M/5/ihBRN9C9rB/2DOIzNUD2MCem0jS1quEHvU9zBGktaOFA+FV4381K9lJi1LUqZ0WMPIovgSSjjNxdcz5wqhTJ0GKu2ff2oFtH/CC6IsqfCr3rQyCIU3WnbkFXQsx+baEFXJB+lmqjpuyM54LqYFkeOOjgmOUnKeifbaj8WbomuA16lDK/fvu2vTNW4KxEEN9vPPu3SYROSyneeK8fjZnu4i+uQQWe6TD+H9uLxauNr4kvAuvp3EWsBqok6OvvlTJIcodew+gUMo/KArlsbJ/kShF222kINdUQlJtMlN2oeIrYQrSxHu5pcCfSGWywCegH2Ng9L9Z1bidowISqUSrFOeaRBrfbCfCJ2uVYBDu2u5T/HfkE1gxL03lCfyhKInHMgSfqat/mIYjzW5KygPcKwBtpob+/8GOnAXW7v35079vq1Tw3FVF/XQPbfc1/7UvqrpaiqcXMl4=","layer_level":2},{"id":"e2934344-c534-4b98-910b-8dc2887cbcfd","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"拖拽状态管理服务","description":"drag-drop-state-management","prompt":"全面解析DragDropStateService服务的设计与实现,说明其作为全局状态容器如何在Blazor应用中跨组件共享拖拽状态。详细描述CurrentDragItem、TargetContainer、DropPosition等核心属性的用途与变更通知机制。分析该服务如何利用依赖注入在多个DraggableContainer和DraggableItem之间协调状态,并与OnDragStart、OnDragOver、OnDrop事件处理器集成。提供代码示例展示状态重置、异常恢复和并发操作处理的最佳实践。","parent_id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","order":2,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs","gmt_create":"2025-08-22T22:24:15.1282376+08:00","gmt_modified":"2025-08-26T23:52:12.7992361+08:00","raw_data":"WikiEncrypted:aroBzHAlplzPvyNcdMV5qoxtkU96BHf6tahuJqNP2NLMkJE0tKVguF12yAJgZqg5FC4sDhkZJyojxhhV0fXuxS8VQhY0pSktOcRnQP5G33q6+IrFScibSP3/cAeAQsr5rrwFORQERN3IkhRSL5LyTc3HuyMQONYQLsN9xArIP5RbLhqPy+e22qLtpOjVPTQUqu3RbPdVxPEyphrDE+b3l10uV/GLKBVDluNbiJEEd0ko3A3nmaWlJYwWcOH0cMALFm/DkX2sRzSAyfm/J1svFJY8YYPHoFwfkPIEsiZ+ao/NYe0Q0KCyOvzJgF4XP/HXcYwXQI7xn3WdwYSOa//bR0tBOLbggJvff45zM7sfUtTUzOgKaspJrC39GFsYqkDobE4JNUgncg/e3Sud3rvlKBxdpU0ZKM70ifLKLVQudgJuJILae2iza/ADNjg0lZm0vboanr60e4YifzT611/ofVpZDYI+YOI2vNapFJD/es+segVgZ6d3MbjyQRZRXNXR193jOnx9uRR18Zw8vUsISaSLR3V1vBV+3HsC5yyib8aMfQ2Lm3+Fa1wl3ZibgOlAhOM0nKOyXKCpKMMbEGqb+zHXbuCDXUcYJRwIssZJSMTCwRXeleDNhydaA/dRF8Cr7xeAKQmm3+X7UU6vfIJEQ1W66jNTGEgfahs3UIOzo1dTtVTP8ojXf5oRSKJN9lGBevCAY/HZFymgxf5F6d41mgqeOk7ZxImnCBl1LYbVTh1aIFOlhlyD0zkEFWva5NDg5CJkFvKTV0Ev3fEJxQQwvxLSsCuJ35/gnjg2NX2vYLHYQB7O8Ihyexolb1l2vF7qjkfbchd2rdKEXVpaP3FibWPNVQkX7B3fcCLX8ZP2Vst6W9+aOcOAplrVxHNijR4A75m0TpxbC0IoCZTBhJx0WZn3JM96/QdEvOdqzLBLxjQqfhjx+r+EApXKzFndz8SA0KOnOdl4fOYn6ns0sWh31I6xiYv7tBKbHD0JgOf0XV1znQVqDbZcGNe/yXPkBYlV","layer_level":2},{"id":"2574726c-e59a-4bac-8854-59598d892537","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"核心概念","description":"core-concepts","prompt":"系统性地介绍低代码平台的核心抽象概念。定义‘元数据(Meta)’作为系统驱动的核心,解释‘应用(App)’作为容器的结构与生命周期;‘页面(Page)’作为用户界面的基本单元,支持多种类型(表单、列表、报表);‘组件(Component)’作为可复用UI元素,其属性、样式、事件的配置方式;‘数据源(DataSource)’作为数据连接抽象,涵盖API、SQL、静态选项等类型;‘菜单(Menu)’作为导航结构的组织方式。结合MetaSchema中的基类(如AppSchemaBase、PageSchemaBase)说明这些概念在代码中的建模方式。提供元数据JSON示例(如caseapp.json)来展示概念到实例的映射。阐述这些概念如何协同工作以实现无代码配置化开发。","order":3,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs,src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs,src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs,src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/MenuSchema.cs","gmt_create":"2025-08-22T22:18:36.9595042+08:00","gmt_modified":"2025-08-22T22:33:31.7716905+08:00","raw_data":"WikiEncrypted:GJKeAISOpe9fzBR3si6wxLaiETzLOChaSr38e02u1874G8hGeDFqyYd6gnecp8a72d7ZVymfuvXDCDSpxTpKPEmFNxEijXpppuPSKKAjoMcdaEAieX4sCuEMaLsVr5bYHOFGFxyEzyz+KBEdAbKBfvmOrMR7dQ6yNxfYYQmwckGwOl6JNst+70gJPt/LQc08OUOUBIgIC1bpv+jRN4rLFJ+qoS7RZhsRya9t9cCCIvowy+JNq4U06TCBeuJ8JQ5cjUQ7Ry54LOrXDU+96SvhOjuxq5RDXDeNuLhLcFfODVwfu4ZX9PXE3JhcSU/K1vAcaz/ltmIPLqNx/ATO5/5dfy6o55imlBd2YcH7gjIUG9h/7/eh9sNkZ0MCNoCS5z4V4p7WFLQWM0rxqtUKV1ObOZ3ZWponOIIWz0y7Eael0E2+X4AKgNdvA3vMPZL8p+ZX3+g64+TADVwmBOhqCH/Kiq/LDv2aVZ8H6rzHh0sbAGf41ErRiw6BSjzEbV0hrZoMkqf4bzRz1nTXPTLDOKArlz0cF1DPYtPh4UcsWZohVwjh9csE5Dd/3+K2W16rCPpSNH+MKDapbVLMqzgHr+PpZi92vfdZF32Q5BTsT/uJyt5sJo1DITLhExLo3QyZ4PeFPY/EvE6117A7ACC2EYg0r8VysyuA04Q+J9yJt5bDlj39W2Roack9dxlkyQ6eWSnPeUsYaNrlf7O7iCYeUQGcrS0f5Gb+HO9aJVB79Nr7Hl9BfbxnWCc5v5avT84cC1DtsVoPhvfRueqdAa71MUWobID7rZwZW0h1QnQaK+LFDX9+ulaRdXOjoecGvdrJDdbU7ZNN7I7akqeJzmn40BoARtcQeSveu8VHN0rLqTANWaKPqtERhqjqbzCqUTawqm5JYIMWNBzArBEgeqY5Lhgk4gskTud0BB1O/4vTZB9IEAV3/WgvimzrSnmiF3KG3GOYkMB8baeUz8/mfhR52DXqItReavwJmtXbfwHEevFlEE6fGQ5UiVGvPFg0xDWDXPTu5VkHx/wM3dX1PKCI1mNw9u+hGeyZGm5FjO72Pn+x5gPQCfsPVKO5QDP/LW4lBDeiRcMdbU8dz7phpCZP3G0t7zzl1ZLdFsJqQvTOeEaUBPUcxPZA3oUyBHXUCYaJhh3zEnZniYGpGTmmkfEDhMOaCp7lqX2H4Wa4BEQ8lGSlbpT/DHi1GcG54nzW595TCzORLZFGPZ4qBYetM8rZMvmy9AlxsVCgmkKR8e4Mwsx0e2EvB8dX4khn8/e5+pdsiZBzo37d4QuqgR1VbfTFNMMVuyYbDrIsnvJIdeFrZb1wY7R9qwjA19WSEUiAlEphRKLICXFp4AqyTJfUO7i3tuggCiJ8Ar6Q5vOH0/ihWV+zgZ4v9+40eUjVoNsf6PWue4TqUk4C1T34lV6UdDyJdMoTcJYOx0EPXaJ0OmsHCAOQGNiEtTMhhHx0qiGYs8WpNFQyoGXrOMD7x9V46QZLWIr8ldgQ/eNPJdtyrjDa5J/UndxdaHvTGp+Ny5t0qS98x5Yt5+gJl8/BO0zG5PRx1qEKffcdZVQledAkXiwnFW23HoJf/mo+zlkE1SDnVeSt917iNKMaDPbGDU9U+WI0eN3AatMaeI8TdG6jiZA5E5l3c1cqo2vvJvKGtDI9WBSf8jGieoi/TdjuUy4X6cXXqu70vYS8ihap9oZUFJC/8QX81VjLhIWjiDNMDiLm9Bdp1Dr+XCZImhu5/aurhyMlbipfXLXsWD764bH/1ipFfRurUILLCytOIXmK4T6GlxlHMc7xqDbQ8LoPf/MYf8qbhWVDetVd0XlBD7hcE9WaJE22QWVOKSDwt+lmY1ZmHCrgmH+05nKOe4DEiHQCVGmMqWd/glBp4BceWU9NuGiPmyEmV8/G+vMMJFOZy/Hjm7vUXpCl"},{"id":"dc56074f-64cf-4511-a7aa-c69d30f2b042","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"组件(Component)","description":"component","prompt":"系统性地解析‘组件’作为可复用UI元素的实现机制。基于ComponentSchemaBase类说明其通用结构,包括ID、类型、属性、样式和事件。深入ComponentAttributeDefineSchemaBase和ComponentStyleSchema,解释属性与样式的动态配置模型。通过EventSchema说明事件绑定与触发机制,包括目标类型(EventTargetTypeEnum)和执行逻辑。结合antdesign组件元数据(如52391a70.json)展示实际配置示例。阐述组件在设计时的拖拽行为(DragDropStateService)与运行时的渲染流程。","parent_id":"2574726c-e59a-4bac-8854-59598d892537","order":3,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentAttributeDefineSchemaBase.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentStyleSchema.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs,meta/parts/componentParts/antdesign/52391a70.json","gmt_create":"2025-08-22T22:19:14.1015751+08:00","gmt_modified":"2025-08-24T21:51:23.474848+08:00","raw_data":"WikiEncrypted:4Zqjl5aZEo1Vv5NKBpebTubKGIE5LW/Q3rizVf63zAgmINRtc21TURvBcyO82j2UR79lEDc5hqpiiNapo6ytwCciEzKI10gRfvm+aoAF9WRZrllsgVRuUPlHJ6uLR+SIT+OFEjv+pqli9Z8HWVPi5XlAuK7fb+7mzwoCPORk4ymKxsNhLjVGVBonB/H+7m45+9EyNTqedp/HWJwYPnZkk5IAgaTycrJkkEo/UamhOfSebYJ6phoetN8OCf6O/anv++ZsZBWxK2OqrPnWbJERRF6MNROcBGR0m6BL1ahqnNtdnAWZ/6nNtnve+ndvppmOE2ZR1oxxMTpaaQtnuw45UQ++08tkDKpTrB/uyV4fKpF5tT7ytzZeCISc127u1zKDhWvshZXxll1c/yRhaEqQya0QyGZ80k7esdXG2BNls6Na+TeKBvVF0kqtZoz8MeoCS5yLfxHKTDMDBY00G/7TmgIi8gQGCmkekN8cEemguOhrs8gAZdJvsIEyH7fiQZ8WQHPsO3HbQ4J7GibOO1lJWxhhpbbZKqzQFjRdCfXWjpYDTM670uV0t1vO5X1Gfn5g3XWRVJ/JXpde97SpyFkHDZ7GF1a1iQDihyJojhRI8y3gC+1o0OU6hBogNDQr7mHAYpUGa9nOvaIPnY1/Z9/aZejzXjQoz2I+A4zNtlXCK0ggg2QMCBEjQx+hRqa6K8HMxyP0n3dtxknJbeJer8KV7lJhOMnznzt+GzO/BAPORulsYLCfVSfecY2A/vu1t1CH/RJbqEsCmjsXZsNoD3g4EiEtwWeozgkqGB20qofEMmySEhMK/sZi6cALXmzS/7LKx9sworPmFoYeTtW66w4CZgL+IfvsA9Oll1l1xXExIP7T7VbjLzHgEoXJqRmH/UT6MSH6wJ/h8efJM0Ad2RlObj5N7eDWaETFFkt9hPr6ZzzSBowwYEVx5LdFFdV+oJQ0dV+ELggQy8laR9LAfASr33G0y8tr/byKmHStw4YyDeXYeuHPym/U3lH4F/9fqu/y5YWSdJHJIaDEvdhJUjGfujO26x/a4IEvW8gjfXLyFCF8zuabyrixLo5l0O5qny0k5ZCBcbfptiNA91DXcDkvoGryj+dh8M3PiCeukPFmoIivDwO/dvOZv9iXJxq75tU1vpJjFGNJbaHS7XLRPkc1ASgXtIf5o65CRHKfvuFzzaaOAC5zf7IbxKXMEBrmVLY7vVC1fYA0bMEmrxssCDxKBof62DCgZehUivQM9osCkh10mcqiFzPoZQdG8liAsxj1mY0eLYbVwYAofnWUb5ngw7nDgI5MNzFkgt9CVtcCFcoVhOjdzgo2j8B1Of2r4xY1WR8k5hlQiyvxiZiHip4eggPaQEejY7bLjiCm6DdT8f79mde8W7fjOqZDdL9H02oCWjW8EI1ANSFMrEVtJUpGjQ==","layer_level":1},{"id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"UI组件与交互","description":"design-engine-ui-components","prompt":"深入解析设计引擎的前端UI组件与用户交互机制。说明组件面板(ComponentPanel)中DragItem.razor.css如何定义可拖拽组件的视觉样式与布局,以及PageSetting.razor.css在属性设置面板中的作用。阐述DragDropStateService服务如何管理拖拽过程中的状态(如当前拖拽项、目标容器、放置位置),并与Blazor组件生命周期协同工作。分析elementUtils.js提供的DOM操作工具函数在精确计算拖拽坐标与元素尺寸中的应用。结合代码说明从组件拖拽开始到释放生成新页面元素的完整交互流程,包括事件绑定、状态更新与元数据同步。","parent_id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css,src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor.css,src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css,src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs,src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js","gmt_create":"2025-08-22T22:19:49.6198446+08:00","gmt_modified":"2025-08-24T21:53:26.9647616+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAb3OhSIpBrvDOaH/3vGL6j2AQoECPIEqHXJPNbXYMeJE2/kHsOns+FCL2Sx0h/bEMQeGDkfgYDfs00rVrs/gBmT2pI4f2F4dDu0X0w37PU7qBjsxZqoWvORWNgPvyzjgfczpHXmBRxpeZvRN6sdu5jjIrDGNhEUkuqKFNfIlzYo5f6nwfCBybAdyMtlfJiMQy1HfDdlgpZ6H2Q6UdRE9xcGZ5C1L928kOVxqlr/Z5+aZiP3EFu9OB9tu4ZicfsSoc0Gcf/I8DwDwb1pIPKlMyBJnS6vwA3mWWu+Mc86k+JqLc7r0YUP4SEwKbLMlgqOAQ7p65FBg7JK7KEgygx5Vb61dTOKTIO/3V5I2xBFwu2zUrI2r+igW/+DIcxq9JahN1C4AHKHXiskc8qTFvAiS4Tigo7BuWD9mNPfpO01EM8sL17SVSPsTwIBi7gjBJBG+A2AMqTSpGVoFweBQr9zISc4Y/L06Uat5+XqUFuGgC0Jtvw1QI99Ti9SeLb7gmpQNSgvI9C/VhqwUHnUX6dgUIKttvMMbAX/2JPkIzHUlZfs3ScbZ9l5k/leIkPjpmX7d9GiXYIoUYwyDg3vT2IYxVj4k2rR0tJMdwpQtbltqWQWstJxyr1B9Nnpa5APYy5mzWY1TvqxGd0d0f4UBUdlhGnTyKBR91vkt7x6HesyLhDe5A3SpWryIBtVF70VZK9ABGxiYV6GTJGibO8aFNwnnZc5eS1heOsG5ryCYVlAlDe2M9KPWjO38QETTgpc9sKB0DrVnvzPXrN2Eg41yYkskbqc9f7dBANIVjJamRH8oGzvG3VI5JBx1mAgX/sySAiVJx9ykmHPlq9C2ABp3AEfXWfhzNTWCR/981cSNA6CYF+UsH81HSS09/h16VIDfvEfDqzVsfypGCjut4nIQ5bUtzLIujBgfI3/80ZU/M2mrKtvTT8KdlUXsWjQRlRmmaZyhCQg2/YHsQ+e87jNCA8vPpRK8m1IGCSnGPz+BVVbi7RzCS+E17q/JtuApb6oGla41T7OFgFvRef++J4QqLk2G3Y878tvW3fo3JduTuNkXCIeHtov6Eh69UlUpaw/Epfo8MezR34KxJNUZDQYmWX6YBTSUY/JLaDU/FzSbZNXJSgFfI9vxslNPi79Ctk+YYCiHy+L672FLbEQvp46CjuZ9ADbK78478fmq2Ok06IqAO73VRlL/31fCo2q2EZA9eDaoLpZi+seDrM9sGrRDpk2BvgpgfeFaaeGKnH9oj9tgh6D6od4Pb1ozlTSRg+WPKLFsN4kbnrg87Dg31I8sj7xmbfuBfdYvodM4aUi2mMsA4Zo71JB61J2mnhU/rqWUQUkKdUm5Dhq4gmpKZz9H5bG+pDAZTE7Qfva/RIVzkAj2xWf8noJePLjHqGFs13g0NryT8yudRmmQ4qCDiGp4l0zhZeH4DzUKC/3aLX5QfZr3k4LpQVjPcsyQXQtjlx+cQ/edDu4HwjM0GLrpSK0dz0W3nyovpxCojZMg7Gq8ssFk5PBW222etsr6VrJq8kQobIYcAoQFcG91DagNY12wiVrFDq4azcO59dYl4lG6qkGI7ob+wBumlsbzfWaNIkJX4YbV/iP2RlzOv8Q0WxGJOKZbu0/CcnTXbjBf+ASx4Vc5K2ALCKHP1deIrx19IguJMfy+AhOR971uDv7cE7Q8hVhA8FD0v3ee/N0tNnKglgyF6/+WBESgZO0vp34DaLJJInoSEKhlf3+nkmXtBCktfUzaXDYR29847GstRbA28m7GQMAUzNy38dFC6xR9vBQp0F+x7o0RStLqQ6V2Nqn9ORu71faaqdOF3eNLMEz/XW1D368bA","layer_level":1},{"id":"3689e15b-292b-4e92-b40b-0c1a8446fd21","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"主题系统","description":"theme-system","prompt":"创建主题系统的文档,解释AntBlazorThemeModule如何集成Ant Design Blazor组件库并定制UI外观。说明ComponentRender组件如何根据元数据渲染不同类型的UI控件,并应用CSS样式。描述ThemePartLayoutBase基类的作用,以及主题如何覆盖默认渲染行为。包括自定义主题的开发步骤:创建新的ThemeModule、重写CSS文件、注册组件映射。提供样式覆盖、动态主题切换和响应式设计的最佳实践,以及常见样式冲突的解决方案。","parent_id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","order":3,"progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs,src/RenderEngine/H.LowCode.Themes.AntBlazor/ComponentRender/ComponentRender.razor.css,src/RenderEngine/H.LowCode.RenderEngine.Abstraction/ThemePartLayoutBase.cs","gmt_create":"2025-08-22T22:20:13.2955955+08:00","gmt_modified":"2025-08-24T21:55:27.7521348+08:00","raw_data":"WikiEncrypted:MxodVyPG/Qm3b50NiN9IZl+3vLCFTDymhQl/ng1sHNp14laXNNlmN/3+hKqeXM1rW7Zv42KhsyYiIS0Ou/cf3PSCgKI8czfFG0fXBwVRWPn3sFk0o9mqtdxJ07AtEBSfUu3MB9WqEaTiaqJiRJAI/dg9pKamqqOu+8pR/7FepuRvDVyGYSjd3hjRqaSzJxEjcMqJWDmGNOk7EC1+BRkLzBoAJwykBUTV74r/8vkgz0XraU2l2C35VR4YSWFKtcUVm3M1nhBkItnjepbN1Pevm7HIG7VmYJUrk1H3uTtrJ9G2JN31Ou98BJWtGlS3dAYTQ6e3AAeFZwoBvSau+uWFYVXDU8HvSib4RQBVpMm86ho5leBzORlmhP8dHAYHMgiHWwuyvE/eGNeuzsTJrdedjm+rwnCKEhxXvh32QiAD8OHWmAjUhK5RppAskilecGTkyqbUh454QRvc3Jcl0lzBlCl1n/obNvnuZrrRF0hCTQWXAxOwi+f2Ie3NQvVKSGPMfkyhZlaFdao3F1wYPojcWZM7OefNWnWdymmY/44p/PnXnicqx2Q4newPLh3kUg0+YzeC13ZLl/CS7cvtbjWq4aerKWqvaQTW2zzwEPPlLyMRKTC9FbvyFx05TBk1rjBrNdQ0sY5wVugi4TMvUl/0OMDOVI2eoKDCpRoRuYDkXFDJ4/sZN7QLF1f99GA3Sm0yDBuF6HWAl0MGhA11j8FVRM4te7vOS66P6xmh1vd13bl5D+EolBoJ6Zz6cBcI+mSxnLXJyokPjc7H77CU1uw1YYtQX8BdSh5uIIxsE+Epaz7gQdfdqM1Pfu1/m+ZG3xgPx+BZxjOkkKI7r+wo6wYjFvmoqb0V9zHtmnpzNfnaiskVjc06gySgkXgmE9bae7VCSYc3CmIT0luntPH/AgAIDyh0oEt/6C9ZX7Ox8yLyE/64qiTL/J/zYaBMR7io6Qfkbs1UQm8cVylaWxngksGRZTTC3/5358TlxcxE0rX1VerStVYKe2IKCrw7oyxUMnpkPQ/PCF367rnfIRyCj9zt0Qx2SBQLlAbWkr+E6phMrH+RPOwqG/Zj78wBZsAG0zH/rv6RQ8jVBRsa6W6UkzhT0e2mkMtB4PH3AtlOmakSRZE8D2qBrFWxZTJU3OinjElksVHf35LmF2207lN1Kubli+d0DrgcMi4MjASEez4SjeDpSSQQueFBbkXCH/+ABCqI","layer_level":1},{"id":"ddca48e2-b166-4269-a644-dc7bc00ad3e5","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据源元数据结构","description":"datasource-meta-schema","prompt":"系统性地描述各类数据源元数据的结构与使用场景。分别解析APIDataSourceSchema(API接口数据源)、SQLDataSourceSchema(数据库查询数据源)、OptionDataSourceSchema(静态选项数据源)和PageDataSourceSchema(页面间传参数据源)的字段定义与配置方式。说明DataSourceSchema基类提供的通用属性,如数据源ID、名称、类型枚举(ComponentDataSourceTypeEnum/PageDataSourceTypeEnum)等。结合meta中实际的数据源JSON文件,演示如何配置请求参数、响应映射、缓存策略等。阐述数据源在组件属性绑定中的作用机制及运行时解析流程。","parent_id":"8aaaca53-5075-4175-a837-be8548ca26c8","order":3,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/PageDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceTypeEnum.cs,src/Common/H.LowCode.MetaSchema/Enums/PageDataSourceTypeEnum.cs,meta/apps/caseapp/datasource/qgzhc7w3z.json","gmt_create":"2025-08-22T22:20:55.7910689+08:00","gmt_modified":"2025-08-24T21:57:33.2966962+08:00","raw_data":"WikiEncrypted:lKcMfSUZMkR3lRV3HfVi628i47MMaaK7Brz3djOsjCq4bOuRyQK7cguzYI/XXYs6Z/vBUmjwh9DWk32BDfRLVuKkP9K7uxtQn0usuvHfnCKtPZPm7RC9WiRSY1xBZ68VSF1DDJ280KA/dJFlQLAl0LIRpH3Jp7xoSyIS/xs1Y+wvYJFVUUSB2LJboyVR/a9D9iEwHdd7X5lUhaR1J/VG0NBioscTi37I4aI9OdSlJIAj5CuS6wRADT3KJeEsdmjWhtL4uYJDerhFfZdDRK6NKs3sDUzwKyc1aryn3WnVZPvczkwL+0vgYrQ1YW6Jm0dZF5u0xUxMLoEIyn3wtltb02qzBV2fUA5hdmfKRB4VWWFDZ+KWAspuDF4QSOXi7h0AQFw5xU9GTkDb99Wl/QXvxss1jy3haYQJFoYSH0xVH1PbnXPBaOmdXgvM+LKKSalxEoqdVaSwwefFZiTbRGXrXNkpFJ6WcAoSSKGu9IZuQgtPK2NRyGf+3Dkvj5W87bixE9cicHqo8KKFXxaPyM3V7TVFDtHUp6ZmyQV3Z9QpKLZPNnDwCk6ZoLBC0t6EiH7Q+jk/vkPBaVTJL1w2GLGwu795sdBiLRHb+YkM/1AwNpDXJOMZVKqnxpzvfZAOrxSFnm5R2HraAbIakinxqGvtsrsvo5X5ZlgPArHOjbQRxERa1ddXzS7upV/nUm0TvnZQ5zJ3FOWvt6OANjK+V+qmxIJiNwg4qO/+qf2zOS7K5ZNkGBNS7i4TwV+7RFzIliY3BU97LQNRAVsGipLVVehSBOQjra1wf3H3vO2RPuHjoST7ZxC0ARmJqPUN2EbY7ryG1rGjd7Qxq4NJJhtNNlINyAyxRUtoZ/QATM+/hPMaopfHtKfcvYyw9AUhYviXrS3WohNVcxA1gsPf5rP2s7IOPraiD98O69KydqUqJSqNDbWbfwXIHTrfRNyPmEXxCDR2Z/uCcI3/w/gIAuJ04UdHazl1ElOuRlFse/MlRcRPacuuZFFehMrOfhUnLDLcWntr5Hzy8HJJq8gytmR3s/awe9TzEsBRDgHvnbwWcoJ81PlvxXUb/Nd1sHbQpA1oWqqmZaEFvCSj3FMQ+4HCBP7fNA9w8pClQ6hKWDZXrC3UwWMl3J178NTYAMWfJD96eoZwbnVRB5eYEVZVSgCgDPgy9fEAntnqv3VZLzPEUwAXpCfJDQdZcTA5V5AX6VkoB8sQsAr+KIETZZoPU6UwILNq+8q/UWsByzq0QMVZLZAnAr7ZsHO7niLMHDiucX4WM3lvam6epRoDhiipy+9sORC+tYORRiIWbyDneMmSlLa5ngZgFPrKwht9qdfc5A0vNBDZPzHxdw83lP++WEEs366AfLYD+2Gs16EQcx4gd0fOGZ98wy8ukYfyekgZs+U7nGA9k2WBkoiiQLAQJWPabp/56ZAKVZgNqUNRMHWz64eedZQGTqqn4VzB4468o0WC1XIou4W9lHVdZ/VoFVqvXsoJp43TywLrQY0Mlaasr6mVfBHo3a0HLoiM49hUJUA0o27NKoqwB36fTtMH6g0wwCugQgvL1l1uZ0+fdxwIIwWypRy9c4eZEBF/5GbeOOncPUdakvqAIGBaNLqoOckimB3JJRdHJKJA4oCEGdfzQF7fVig7trc2sciyxF+eoO8vRYlj99z1xFPr++9mGygTac++p0GkOC0YrMqWNhu5NJAK6MiS/SQuISdOx6TkwBaJQ2Xvxg++hOaC8qEoxCPqlSGvioTy6aV1xB4KVpY+4GG26fAWHkw0FsWZAKXhg268b12Lrz3kkNpXnWVXhACNYBggwS+i5u0NRRxtgf+oMsAagOY=","layer_level":1},{"id":"93ebef01-275e-4466-bd46-741408c9e061","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"默认组件包管理","description":"default-component-management","prompt":"深入解析默认组件包的加载机制与覆盖策略。分析LowCodeDefaultComponentModule的注册流程,说明其如何通过依赖注入向系统注入基础组件(如按钮、输入框等)。解释组件模块的优先级排序机制和冲突解决规则。指导开发者如何安全地扩展或替换默认组件,同时保持向后兼容性。涵盖组件注册表(ComponentLibrarySchema)的初始化过程、动态加载机制以及热更新支持。提供最佳实践建议,包括命名空间管理、资源打包和按需加载优化。","parent_id":"1e1f9cb3-49a3-430a-b3cd-3b2dd4bb2603","order":3,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs,src/Common/H.LowCode.ComponentBase/LowCodeComponentBaseModule.cs,src/RenderEngine/H.LowCode.RenderEngine.Host.Client/Program.cs,src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs","gmt_create":"2025-08-22T22:21:28.1608835+08:00","gmt_modified":"2025-08-24T21:59:38.2942186+08:00","raw_data":"WikiEncrypted:iAyIG4qeSDZlA8uf8oTvalD+Mla1h48dazwhtFqWu5cYrMhYvNizCjuiHetLW1RID2X2mfXIEjZx6rlV2subvA7fxJiLRV9YTuhXD5+QQrBw+GJgXmgTRkCpw2VgfQiguuU1kHIlI9lLbpL73nzqe3a84R+3EeI1dlRrT4eU5lQY9HErY2NmlgSkTJG8UmQ7mTO1xV3/DN9xyOtn+gkaHxxQpwnbJb2Q2oL1FxXym7rOZJ+pSBmYCUMcvppTgt5GstGNcgT4yuSUoNG0bO6vL5arxECRluyme4xCzyb84Xo36cc2lzySfEqwLsEFnSmV6xHDxGIUTV2YBJjc1dK35IoJf5W0QSmFZtarJTsf5UHf2NncRHJc0dr5i+sUKP+CWRTn28JYMvgsKmQKhAwMCCp0AeZTUzTOxauHrVUOT39sMbdYSPKksKt+3j3nukfEOTqc7Xg7WFkw3H0Niz9TJK4kk6qIs0UejVA6vCCwymqxXEpnuF9GLR8n54lZYyxAdSSh6quTGzjEcNdF9dW6Ze+Dsy6eUs3Vb8kHEuEYBmT7QhKcS5SoPSgJH0BepnnpYxLnyLl/Z6yWyAKyGIjdmlTkliyTqmQKWuDSGDe4PDPP3St9tfZ61NmMnkCwE2ypbf0fDBkvZzQPZwai6/iMWgvRidvFKo06npyikjQ3tIdC8/BsAAVugev24zLlzYQojg7Gjpild8GDGikIVo5f+cTMOmP5Z66Ck7ZJQSxINUAQIR8Jfewafv49Rha4lzri8YOzbho/SZq80FCiFSysxLn09j/hqWq9hSBVRvZErCZbIZMAG7VF5YMooyCHuSszApQKYrOtFu/foT+w4mT+4DUJXYF/GJEZxnyDIYuW5D2HW3f4A6WC3hLlF8pB7ATCZCDctARQu/sIJzM0oDt1MT3e+tHsBDuKzHZSwR7s/8Yp5ln9P4KdnWPq/xWkP+JMS5lVzFB92pyUT+01hO0GBs22N8p5R9p2lzzRnkAQJPX5Gza+jrFh/yzRpukDw+lY3TrYg0I1RLXPMq/kx/QVj6IMk62nwchX9fUdapP3BD+NbRY98XeWJQ9J1ig7LAVRHJO61yi9gkKYrEiNiDXCDtlJUZrJfkJRcCICqFWmwfY+uLajDu+tElDxe39FZk36A2jvlVzLD0BMvRLehrxx3chCLA+Kajr3fJql8XCLaqhwjs+Gh1abKb1b3ap832n6SKQDXOmuZgOjbUlYA6RVuuQdJuKo0pA0lUmG58IiGpmVBGrMXVo8DsXAc8DesN/gioJ7LffQMSHe6Y+H2/lgRQdBwMvV9aAyolj4AvscC2ZLbo89PjkoOZ0ITc+0UshpcufbixVIBiWMFanC6mjj3w==","layer_level":1},{"id":"12a2718c-bc93-4d0b-99f8-53f8879be7c7","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"常见问题排查","description":"troubleshooting","prompt":"整理一份全面的常见问题排查清单。针对元数据加载失败(如JSON文件读取异常、路径错误)、页面或组件不显示(元数据结构错误、组件注册缺失)、事件绑定无效(事件定义不匹配、处理函数未注册)等高频问题,提供详细的诊断步骤和修复方案。说明如何检查meta目录下的元数据文件完整性,验证数据源配置正确性,以及使用浏览器开发者工具分析前端渲染错误。包含错误日志解读指南和快速恢复建议。","parent_id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs,src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/PageFileRepository.cs,meta/apps/caseapp/caseapp.json","gmt_create":"2025-08-22T22:22:00.1342488+08:00","gmt_modified":"2025-08-24T22:01:29.5236335+08:00","raw_data":"WikiEncrypted:CaKOW8OSSWs4aEYk06Hu0hGGy7zXJE5t3XZJK+9x87VfUjgnOpBUqUB9tJCet0sLIinaDLz0/K42XgnPYLcY1jtHmPVGxjtS/Dlx0RMjc53Uugi+LDb9zzLePOkj0F20AhfL58STXzTGbSd1tv4fAwgy0uLsWMXVvstfpJsQmp2fjFm//pFa5FYxvHCrqafrJ2uCBy9MRT7C2wSNZ2NI53HRrTTtHTldQ14lszC6e5sIUFEwlvBgHjcwabeC4A/NpEaWOQPgNtwDwKkXvNRCG5FgYu/WLq1UrrDwi1OuOs/NUTOq1kAL+qbH4oGQ0461F0KVdLbAobh9hM37OMwZY+Q6wSNYQ7N/wIohdb37RKG2BdZ0/+ih6GsFXbvs2zHjjLYqJtAAu1/wbSdnHzI6aDjcJDFBNlnYdnOmu0JbGt7nd6VAjVjOi4zRWoHFRC7bj/hX11iGBh1qZiqVrkKlc5ZnfU3mA45EPKsgTkQhjA43jtmvSwd1MqRBUgfP6FbxNWUrJhRS0WWESX5f3YNh2pGa/LBC1qJusescQR82tnY4+xvVgtWvdSCxBQhj/fnbVlThrSzQXHKmwen8uGbUzbf40AFrt9Xnr6ry5E0UGzyRaZmliaJwJ1t06H9WwoSZ1kqlxfyWYQ4D8TJPSFhE/GwZHa+v1UiK6uboZ7mz7SwFtlTspSvF3rIvbFCzJ7zA+qP+iVHALYrvtrucB/oq57E4PhxTecFe8ULpP8B6Bf6LU/bMM8ECfTl9uHZ6r8iS4qvz11jg4Ybarh/sJ7hQlSv85m1zhQE7VS+Km7hYPeKPGYI7twti1HXFx21AEOchTiWBpCEma6ib6Eoyh9At4lZeZ50Bl1I5Lj1wwLpFkgXNRkAhA1x90kbBIhM7bU0WB4Yz5aRrjGXLsxHraa2d8PrFOzuueDQ/lSo/1hglYZ7/ToiT7VQra4W1Zx/XGlKyILzCO791YuFpPBZ9i4DtF64a9LZHv7+WxABn4wsVTpylq+35/+mry3orqItqihme6qU0HU+0viS4ruQkHZ+7OibyHEwLO1B5apPqshINaY6fFq/IBmdlNUVh7znVgKrAl2kxAI9NI97QH7W5QaIeSoZC2q3VcRImlCkySqK8tR0MbCkbqnsM+ECUyYIEZgQ8vfD1uimTu6Ph5MD5kkywxTJRvivyHKW+0e1NpODu0Jf0jSmxNgiW+jBMbgwq00YIrP9rSA1L8TDj9GIfEIjIaQ==","layer_level":1},{"id":"3f7e22c2-c859-4f5a-b62b-4db9258f8e7a","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"容器化部署","description":"container-deployment","prompt":"提供基于Docker的容器化部署完整指南。编写多阶段Dockerfile示例,展示如何分别构建设计引擎和渲染引擎镜像,实现编译与运行环境分离,优化镜像体积。说明如何将appsettings.json等配置文件通过卷挂载或环境变量注入容器。设计docker-compose.yml文件以编排设计引擎、渲染引擎、数据库等服务,配置网络、依赖关系和端口映射。阐述容器健康检查配置、资源限制(CPU/内存)、日志驱动集成。讨论Kubernetes部署扩展方案,包括配置ConfigMap管理应用配置、Secret存储敏感信息、Ingress路由规则等。包含镜像安全扫描、漏洞修复等运维实践。","parent_id":"87d35f84-473c-49f7-8192-185a0a489619","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/Dockerfile,src/RenderEngine/H.LowCode.RenderEngine.Host/Dockerfile,docker-compose.yml,src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json,src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json","gmt_create":"2025-08-22T22:22:31.0512285+08:00","gmt_modified":"2025-08-26T23:09:08.7072694+08:00","raw_data":"WikiEncrypted:OYVOcFWO8QG2KTNzD99v47uguC331k46Jisr1yWpIuwUr9JRzitak1LaLEYP56JrPRmdzdzEHdoG2wPPrP6tkCx4rrrfDKw508lcBDVs8lvys6KlwrnpuovmBhthME0WtHVYt86rxd90jkuR1y3uODKor/h/bOz+2gTZyWCOLbdJ0R8l//TpOkJBW3VLmAwM5h+f5LvOAFkpELKvgmz3PVGWuJSVQbnupJwrsw+7FhNZW5gRT0GWarUQK73L0mtN6aOydlXc9UcknV5k7rhEhotY1fq/6Jf4b827t88m5vsp3K5lnfrVlNDhlyPUWMQw58WbamQGda0IxWcFVqZz+c/iqxcDB3VG7jpqA3WYK0vY5cfGZo8TjUR4FQKcQKKJJhHMZEtEIhNrD1drCjBejAxMbcCrJOTe22eGoqqO2kSjxMKIC/CSTsv3T/3nxzmzxDhiZvl/Jhj3bzAgQGU9IvgXD6Z75JCAjJNHo69CmdUdn/oa2/EyRQBdXXPvGPgxXq8sSkb/aupWMxU55ies5TVWK1nr51+he+ptKjhcmMlB4F3DThU9hQE+xRJGfUr3BT+4mnzBkrfGk2456BPMusK5YVKIZM+dMAFSV0hrbe5dVNDKoKBieMV3Y2TXjT1AtaQUDX1Qf+fvJ09jtcIPU/PBicdUIGNKCnuTfwapeTiT+JIKKyywcRJmXZYG50QqSbOzhfB1mqZcSmBJFvtPnAS5C5f8LVal/oS6otcClhO0VqcxnGwNeQVdFjQC55WewvNRrWB4gK06VPgnDBYPloLgHU9sC2d4cF+iCXh8upIVmLLYkerrKg6vUIUDk482o5hEbl+0MNf+LGpqqwgEubReuPK4lRj3Kf5WGVFvGyOqeamLjLCn0SELOShsgWD2Z24yh7uqRfErG9M/+x5dyrkD3YrTwiACYp9qpcWwGqf9bH+JG2eZtV7STE3Ztl4i6r8gmIln2/TKbM7c3O9WWF/160uIqv6ml7t0DQ0c0IEuGhVP7K+tIj9AEpx85geQpYO06HiGHcDToGpKSYmiM6OrqGT0/fDKWf8iuBLH+VpgCq25E16bIsoml9csDNDhP/V3SZAgb9YunNESYu85rMnQEQ6t+2TJbAEpfItbtnilxBUOtG7AdTxIzfadTcnr0z1z1p96/SF2ZJpsOC0tuZ0BB7aRNRtgQyy34GfFbNwrpplg1fQb+XCC4bNQTGvxqQngx842fAbIR2uA8+fXUIHAIKI7djyNXigqoucIUDG9DDc/I5vG9y1/lXcAjekXtdvHKVfZOJk/3Y4UZnFkyAd93tyzCp8xMTuN5Ttz0cn9nmYmth+rV/sHAAeL6hufa+jx+dlW8ZDx9zCWgFIRq7XKYsilF7pMssdE5GT2Zbe38yxtKCfYQLqp8XlH38KYZVpNF7YwYNEiPNKJ5IAuEbGzDXFRd7jx9LJOWzSMqdcr9OlefrAsKXGQp5JK71nw6hu6g1jpkI9RTS5trFSEkZu6LXMdocFloEtFe29+cys=","layer_level":1},{"id":"dc19c7a9-c262-4a86-a667-cf2206cde892","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据源管理服务","description":"datasource-application-service","prompt":"深入剖析DataSourceAppService的核心功能,涵盖API、SQL、静态选项等各类数据源的统一管理机制。详细说明数据源的创建、测试连接、字段探测和元数据提取流程,以及如何通过IDataSourceDomainService进行领域逻辑处理。解释不同类型数据源(DataSourceTypeEnum)的差异化配置策略和验证规则,如SQL语句语法检查、API接口参数校验等。结合代码示例展示数据源配置保存、连接测试执行和字段列表获取的具体实现。文档需包含敏感信息加密存储、数据源作用域(应用级/全局)管理、缓存策略,并提供测试数据源连接API的完整请求/响应示例及错误码说明。","parent_id":"be52f1c4-850c-4443-ba95-8808d1e5b997","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/DataSourceAppService.cs","gmt_create":"2025-08-22T22:22:55.1567024+08:00","gmt_modified":"2025-08-26T23:54:07.500593+08:00","raw_data":"WikiEncrypted:lKcMfSUZMkR3lRV3HfVi69K9dSB0J4MiwcjMl/7+P/V4CyGTJkAVNEHgfedc1scp3VpJXnKwbv/ydlF0CHzQyMwLOwDjXkYbYor8WBD0pT8/h+yEHvxmj9vkVA9xy9mZLQMWmlcPlvFqx/eT762U3YLVqxBvonDPVeDLW/AuqAip5vH7/GSkAoT0fvSC1rLxAXzuBUBlp2CLRTRJze6i7R2UsUwwYI3x3QM9Eh+j5MO5pm8n4C41hQ4VCB3xFbZS97aS+opydcJWfUmgANKWX9bDiizNpyQY4cRc/vkjXkrQqiwiQ+VZTjPH0kKlt5kxVdVGn5vtUyVQ+oajoE2WuEBkseo4VYpU+wK5jL7hv17Jer+fqSNd4NyFwHfl+wRPKF+XbDHToQDmZRYVUrEbzrJG39bZ5uTrJCdfAKT3ECSyks7SMucQWCx74K1SsDOyomp0rSvzfTJm28M/dTQWjaegS3pWCanGwRAvGHlSCoPIZb+kftvPf37A7Y1rK7RXNv37KaIqdneH0WgRZ7oh80fWFqmveDo/KSd5kuuEYL0+anpByPTsEdaHslZnASGiUGSLnP9eQdsaHYOHbbDC0QfFJXeG9xhUUL5jxGQvJmtYGLo6zZJ6YLBELtPLKzblJ5NONjvmEV86pb9KQ3wtiR3krx6m8DNkNpQcFsAdIaoKOSIOliSClGaS6ZjuzVdAPzbRx3tR96fv7YHdJQt37xGx5uaccQD1307WsdD2Bz0eiZD8BUyyFO7sDecCIwcwBEXLuhKtzUDpMzNQgXTNe4QG3SpumiXm0u7rnsR+L6EaciJOO67kuIxzGijQZLafETZAdl6wJ/Wb0ojhIeCKR1L1g8s8Itq42mmnB4On+meHyhXDKlcLauD3/iczreYH1/3MNhBQEmnEBoN+f4NJG72NcqrinqvKR0rTvNuvwNizEHfCIqWQMGvS3Gg8owPE87INHi6/feyRBtrq9VL71ZyuXB7ywD/SmzuHlm+IVir33/dawkIb6umVtC2fsSkojFDHabTQHbLkEEjJtlijNzp/6ZLr6UVUMD41cqhIcG2dx/xGSw2Bo6e0bw2hnqKaoxGY4F5VctCP56YIz11eXgA/DcYJsL6b/jZ8tf0k/3eV8vIyv4EgZjvTGrfd+/lVKHwFBAOnVwKGfJpjxPhtr69oiG/J7YfBzFON05zun60RtzfguM6XArbAxYid+d1+EFGSI5oIaCutt5nVFAL2qOlWXPkd/qwURWLWnlDD5U6mMARusF8jGZdI/787C390lI927wFyMo7b9C+aE4NK3WDYiotU0ZJFiarN30EXnfY=","layer_level":2},{"id":"850cfe76-4777-4295-b053-5312874b8446","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据源领域服务","description":"datasource-domain-service","prompt":"深入剖析DataSourceDomainService对各类数据源(API、SQL、静态选项等)的统一管理机制。详细说明数据源创建时的连接验证、参数校验和安全性检查流程,包括SQL注入防护、API超时设置和认证信息加密存储策略。阐述不同类型数据源的抽象建模方式及其在领域层的共性与差异处理逻辑。描述数据源测试连接功能的实现原理,以及如何通过领域服务协调元数据更新与缓存失效机制。结合具体实现代码,解释数据源依赖分析、引用计数管理和级联删除规则,确保系统稳定性与数据一致性。","parent_id":"e52a6571-a012-4e2a-b5d2-e5f94c01d367","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/DataSourceDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs","gmt_create":"2025-08-22T22:23:24.2927846+08:00","gmt_modified":"2025-08-26T23:58:17.2130682+08:00","raw_data":"WikiEncrypted:lKcMfSUZMkR3lRV3HfVi61PMShMCAdiX6pa2rwkb8R4/Fs+oNbaoNZrk6TZHl+U019e72kZNkU3uj1pQEpVf3xn3NRxEU91B2/eAc4C99Hd9Mbcb3X0X1IRgoFe7AgURNlNlddQPamWLUwB6N0V7rRWBJKc5swogF6T7fx6wDtNJOTK2nv4INijgHuzIY5Y3k8CpquV2dIY3fe1OqpexAI3hX+7xaCmeYZaie5FcoGDRurwSkMSxl9bXFFB2bp+QmMl5YsMefwKtSFcVuryOgr7iwH5wzu9A8ETJ7Wk5Gpw+3xSvaMnzwxKkM44ONDO82eMKbflSNtu8xckbF1GUgsF3RBeajiG4p91NISu9zd6lLO0CW2AT+iWcS3r6QUiqWrUu1xQOA5lFIdIyZlngBrNdIj2+78eY/A0HmFa8ojfdOMJvOHH/bls6X/rJuvSqIMIedP/OYi7LKwJ/U7UBYYtvwoqCN02mFoe9MGa4mf6N2T3AJHWY/oGKUeK9Lx4z1k4uOHN3x19DiuLtVC1a/fVhazGrVcC44xOoWcG90qdQH5pjJgOrvrz/mdns6fen30m2TOcikQ7IUqVwBZ1WbWTKHzVCEembOJS4gT9evcjMO+ZLeEakmYUU6OFe38Qtwf1uBuqMxErxDWHXuN9UGeN4om4oW8OGmRFqi8FltkuSktDp6IZTTeYCKAEJHl+jgUsZr1Wt8A6dkOIxeIG2mmcasapibC9h0p/PtgeUZVcQffAcXP5drOvmF/Cy0nE34kWDd0N+HqY1uUyDCpJoLGOMQ9na+elcwda372Czy9ez2qUv847gN3au8Y/dg5OnnDDNGtJsQi39DooRts6417QibvTS6e7bJ0aw1MdNXgFtxYVkHw0SOuu93bpRPgf7i+KgveH4/2+1mWIDCtcqwS4EtMqb8u7ms6/pIUlIMpEOiOs1YjyUGTKOXvG5Ez1hBjvljTZL5RWiZN0JzpNwv9+z6xyFS/HWCFZufkoSo8eH9EVL4AssafY/mshT+W97H3OmKGcw648Tqg/jM0BMrF2p2wtrHhtz8K63vHy3bLhzM8cLxS4OaDhmpSNlpTkdQ42H7JT4CI4RPqTwnb1/zvWFS7iZXaBJYM6RSC9gsdS0tl743KkV7q4sk3zair2B7c4kjjezgdJ8q1z9QRg/0DBWv1UNYWgV2ijsq3Tf6xjri28OA7QOQ5io9SSApprKdMwi0SbE+UwG9JmmQMvWFWnF6hkqp/sUmSmoaca2BUpL0IXu9a044W0T8ct+QdusaSI9QIapuTtvDrmA/GtuPR/niU/iVx5NitbPoMucQdfhxbQOpPofGdzJgCNzajPB/hfX9hvKOqNWF57Cz1inYAZ+QPRKrsiYlnog/RogxBrC3lgG7jkDtTn5vk/7uI9iMsEVQJiZvcKw5HjdMJHMn82sHogE0XBbAqhkSmyDKyTmz7BwmpqvNawAvD6tHbZjHQb9bMWpkViC/4WFfuehlziWS5s1an8+8BZmHi5VTATwkubRdZcuwCmNEWzLLV4C","layer_level":2},{"id":"9cc44fb0-22ae-4347-9095-e3dddff81e99","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"仓储接口与依赖注入","description":"repository-interface-abstraction","prompt":"系统阐述仓储模式的接口抽象设计,分析IAppRepository等接口如何定义统一的数据访问契约,实现领域层与基础设施层的解耦。详细说明DesignEngineJsonFileRepositoryModule、DesignEngineRemoteServiceRepositoryModule和DesignEngineEntityFrameworkCoreModule三个模块如何通过依赖注入容器注册不同的仓储实现。解释在运行时如何根据配置动态切换JSON文件、数据库或远程服务等存储策略。提供多仓储实现共存时的优先级配置、条件注册及运行时切换的最佳实践,确保系统的灵活性与可扩展性。","parent_id":"d3062028-65d4-43ea-a57e-3d6daeb99be8","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IAppRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IPageRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IMenuRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaRepositories/IDataSourceRepository.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/DesignEngineJsonFileRepositoryModule.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/DesignEngineRemoteServiceRepositoryModule.cs,src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/DesignEngineEntityFrameworkCoreModule.cs","gmt_create":"2025-08-22T22:23:50.8394435+08:00","gmt_modified":"2025-08-27T00:00:15.4467751+08:00","raw_data":"WikiEncrypted:iK+EVtJORL4i9RpuJMg4EEw/5hQiUUmxrmrWPhPzVGAiJpwT6QRRD/RLUg1+DLwHlKYgiEkRo3j2B/hTsWS5ZSCVF1OCYeomGfninKEQmJawWS4kwyUiE3yMCqQX/FxaG92Rbavb1eiBU4SmhSNr165PRSewdcO5IZbQO8zZfEpcFmSBFYvZefPTcfBJe5DD2MxTRYe4IeqQrDEE6diZFamVUdCRzcraXyH+XFX0roZZvt+CodGB1+ZBcPDZLpDb8bNeyXYfG8euKJSwB7j8ZcylDBc7tP8gH3h4vkXij7fwZFFNn9eBko/c09ByIpm2O08PmXaAEx/pKwhHmYifpU9k9HabvHjf0oNCP7r0ZmHnnNuJXhVu0HwpIO3U2rkvSCk1TI1UnKnr357FzKMDHTd6KmEbYH+GcygU2HjiDr87cooyk/ipINX2gPRql7EONd9qBewHotcEkeifVMAFxXn14MUfu35P3y0WxRcmwmEpOY72OzTcY18i3lQDP3p+RTjLcQ9v3GcAX8sxh59ALffn/lvIMgjdEeL0t9dSITzRfLkOjvlhvvHe1arcyxyZaa+3EuxfeKozGcV3myMG4Zavf3fOp/GJZ0s04dDGRVZyvLX8mj3JAmQEGYp+15t3uraUMLptjs250cvcSCqr37fum1X0QX6ClAvcj9tEKaYIUqz+gZO+QVwKTNgNfVT8IJ/rlRMUQvVmhkzDFycVUhoTTTMCZVukjBEDLJ3wRc91VM9sqH2Jy64leoOzfrui/XQF+4UU/gDg3UHW1jDLfd600xEe/0HkK76h9UzNsvJjXfg2QrTgNX3HrSLVVqvcXrRjbi4V8UffRAXhip7qVYUeveYwaqEbJOjUc4FFC20FwT0c620Ys8lq9z85RIV1iH2kxVsDRFe8A50nWxPPoY1XL3hvYcNia5iocjyNrL5l9Br32Ld/jBAtVE7leJNeHa1vkYJH9MRsg7qu9upHmZy/vKtIdGIP1SphrodpyW8KjlQS3RP/pK8JbjjfrcKGQL6PnZYLTBpS75fj+xEzDdq+Q3c3E7L01sgvw44g/tp73jHzeCvqej3P5qOG9nBX5M7qGf8ESz+Jop0ET+3ZRdCinHz68jmO3eBTCv+pUa9Sh8jntdEpuF8CwnFqKjYnuiAYyNoTy6MrpDNm1HSzJTom2wZwZ80yVeH6AHqVb5cT/jqKFZfy9JLQEQK0lAobHJKttZvfaux6DECrMNo65E0JPlDpy75lFqtjJy6t2dSDbhjco9n49QgVxsJMhBn/oxRH+N0OqJf6gSgUMjMokArnfB5TrRJ3u7CWB4h7qr18hefiEKBja20PFY+EtSyLWzymc+swI577JuK0uXSYiT5uL43OB7oXdJYtVTtynrCa1UFRqGAtqA5UZygyeTAtOvZpDzmcb1WMpdcoC2fU/V9ECKz+tHdmtdm2NixpvIVaQVZGWfjuKbhEgp01UcljAfN0pAqb7AJsyElBZe7OITGZ6P79cD2UPMST8fre5yuiY+Q1DVbGOvsoh4muTHCjpUZ5pDgNWjp0uDJ7sx/mEMlBfqSH82XOYhiaRBMe0I634Oj08Q1VpKxHRDPnQtjhxqQYmkt8hf4p6FLS2bk2JnidsAKmBfsSNOI70QmPEqezlCgXoGueC7TfPpU6vjnd2nEhsQqbbg0GFMeqI7bUUy4+oWuhATlmp9JwBmeW3sOo0YfjlJUWWogsIlFWZo3+2w+mF2wmk/XdocRvslOXaAlws1rM3H3pxKJRqeCjWaH7l7yMUAT4utVcQ2NRbANiLLFgayCjFHghly+crv60HZcYzUqbxJDwauCS6RoknRYDV6thvP4cX7pTkgMiiO3xIQSQSjEwnpoqWE914ioj3t7XAi5sPQkb0lTMnvNvI+XfOEqxAv5eqYWuBL6Nx9OPzmxixgvwTf1CQW3rIfsYRg==","layer_level":2},{"id":"00d767d8-e3ec-4706-ba62-8f445790c500","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"DOM操作工具函数","description":"dom-utility-functions","prompt":"详细文档化elementUtils.js中提供的JavaScript工具函数,包括getElementRect、getRelativePosition、isPointInElement等方法的参数、返回值及使用场景。说明这些函数如何弥补Blazor在精确DOM测量方面的不足,特别是在计算拖拽元素相对于画布的绝对坐标时的关键作用。分析函数内部实现细节,如getBoundingClientRect的调用时机、滚动偏移处理、坐标系转换逻辑,并提供前端互操作(JS Interop)的调用示例。","parent_id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","order":3,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js","gmt_create":"2025-08-22T22:24:15.1303164+08:00","gmt_modified":"2025-08-27T00:02:30.4492197+08:00","raw_data":"WikiEncrypted:7wYQPXOu7MuYn1Rwx94PdidcLbxgsbfZ3LQW7C1xGY1yTTwsgDE8oMxW3URj+sNkd0YHdYbaXZKQFpFo4QqyBNDARk7S3kKijHwiT3vm0x/fsqJpYkLOAnGJYw+ydIpkfaWvj/WlP2gliwA9ciSgrZHyjxux2v3GhMJbEuDlmoxa1CRIcIGmkRNGRPNXsmYG8XfAtmH5+Z4Gm7s7CH8HXS49UXeMzKtDh08kPC1g3BltIKsocYZV3Olh87yMiIfX9UFvOU6buskZJsCgIvB4D+fIfD8fNK5gj3unak09fIg77fr/1GVMUOaqrBQ9yyRkLcedzRdkF2I/In/S0hsZrsxCkm2k/7YegykPbMJaJVt9RsfgNmkAw3BSdH62P8Ff/LzvLLuq4r80nlGaSfU8D19Hq+A6ZLz3G7xi6AhKHlwK0u7IPFMMY4aKAOHE7vnWJWTMscEKU9CNKGYnxmGF3hDtisSh/1O80OBwKlh14t9KgOdFvK8FemKhKWlrLrWCU/HiJhDgH0WIh5ctTWqq+3dI4GGGwvD17NHvqFiVUaf5yQzUtNII0cUtQfMBlShN0LsFkKdu4kNV3Z8tgQBW4DweMh7RhS4P2wP1j4F2E2Yql8LM6mZVjyo77jToFiPjKvQUC0qofoc97CoNrX3PHin/ql25smGVq6iY+Ii2lmoZizWR50u7LX3sDlToOgmnwDn3YHCEgs2e+x9kYXgrZU63FpbDyPvRHYtam94bTPNGZ1i0zsUpDCUhf0zuXrjXL8b3kiND5wmSMubHtpzzw29bEs8OH3Qgid+/JAzhMT9iAQ6Jk+Jso8WsdB+MOF4lTC0VGL4CJ4CF5qz5aJBsoiLnSddNa4GCCS/wrwDQ16eNDGESUdf8tS0yfVKJ/yGU9F/kK3Y4GvMHczWDdULqehpGKCVbtpBogAg5uXTmYJ3aW2YbGOAfeyau3NfyWVzjeTqor2jglm2OOwy1RJa1ZrPttNopzXpg9Fp26S30VJc=","layer_level":2},{"id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"设计引擎","description":"design-engine","prompt":"全面阐述设计引擎的功能与实现机制。说明其作为可视化开发环境的角色,支持用户通过拖拽方式构建应用界面。描述其模块组成:Application层提供应用、页面、菜单、数据源的CRUD服务;Domain层封装业务逻辑与领域规则;Repository层支持多种存储后端(JsonFile、RemoteService、EF Core)。重点分析AppApplicationService与AppDomainService之间的调用关系,以及FileRepositoryBase如何实现元数据的持久化。解释组件面板、属性设置面板的前端实现(如DragItem.razor.css),以及拖拽状态管理服务(DragDropStateService)的工作原理。说明设计引擎如何生成符合规范的元数据并写入meta目录。","order":4,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs,src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/AppApplicationService.cs,src/DesignEngine/H.LowCode.DesignEngine.Domain/MetaDomainServices/AppDomainService.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/Repositories/AppFileRepository.cs","gmt_create":"2025-08-22T22:18:36.9616311+08:00","gmt_modified":"2025-08-22T22:36:52.4513284+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAb4OjEaDucJTrFCHU8PI5zr1UtUoTLFie5ItMsYKvheojH0gCuT8ShCu1eWBwWBJkJ6FIonppUlirn62ud9cdrG1Qf1BCqGEwT+84Jh0dGHMYNyEETejCl/M30bQhfWwKjUP8cfMg6Ew2BJqJWcf2R4e1KLFedt5H4UYFjyyGCfELNs/Tbg4CGmbdJU3+PoIG1ZIuKjQs6WA0EDPP2pkmQT3o3mPWyY5ll30NqMJ1CcBL0gisuHAV4DQhJvWXwqxffaGTG1J/K7Sk+hQGIs+nGpuF5yMugl1g8OVc8e6Ct+toHgyGr1yNSnjeauHYBRDEjfhZTGWPaf+wQMP4fl2gO6K/z4zO1jJhOY2KuDO/ejWexuRxryQ4amzuvw3rDQZadHHpFxhNc/7IU9J8HgJPoQkTo6JZfcjdakH1eg3SXTIfQoejUh6sqoCS1bS2w18g7vwtkLvo6uwCiw61Ng+kX18PLxPLcU6KtTPKi16cIAuX3g60kPd3vNUrEc/awp7o/wrJ7nKSJRFjoaQfz8eDc9iYjjM0OBPTummWiBvtbZktNWxKpiu88cKd4usDLGjI3N+vi8NX4ePMV5d35UjdEpuOg2Elfojl5NF2VPnioFxTzATM13dBTjuWAkgvH6wlhKe1sFV2C1iTy0iDub8MlUAjvUayjV4pWUH2qGlhuClq5TF2mCwzlaNR8YQvM3PADh1vWCpMKH0uLiDm8MEPxKZQUgpbC7E0FsR7LwEtg+27XDYs8hpff5bLtj3t7Ky662M2wtMz8qvFtiOsV7gcb6ZumUEWPGPYMokaaocl7gsn/auXO98Hor6gxuB166CklYtdwHr1d96sPdAj4jBQ1BGFO+x1cgnYaOyfuKDl/JSdUCNOGwNzJWk9NF/X6Icwytf8BXV34Tdw/ZdaMZ4pYkY2uUM1qbI7/xX1tf/Js0gSFlVJcNZn8mnUcS0txVtmX4QDgaS/BwMVgQVowdmN5s2+obmSlvIeHlGT25Sti6+rER3SM0mg+3nZWKAMVqRGo83SCAx21Q5st6yEjEFeyK8sSB7V7Dzv1Lq+YJeaRSIioRO3iCVIOPwyzLI2/hLMuYAwC6Mk8vUp6mXq09eN3vPZ11G+zK5FzltOHExn0mq1SBfaKFZnt/RJhuHifGTL04dpvw3RMAkBLeNTVy98cRp9o7f14eE95PNpeFuM6JsAjITdfFAWmlmg3vUMnEMmonFvLaz5RfIdIrifznUIj2xpTcBGUw23TfQ8YTmlqBWpXMRe+iwWMD4TCxA6mtfKJFWBKF8te1f0umyCLeQe0AYBUxRggHjibmkKIHZlSwQnlorzyHjkx1p0Hl4ZAU8T8IbAeCwSkh+R/BRNBB9JWmNaQ5Zp31NXhAvx6lHvam8H70Zzjow5AX1BOc4kwrfKyE6VrLikKDCvk05AvqHYoxuWSSX+JUl+oX6nKwygUdq7/X8wryok3SHneQChqrX5emnXNUoZK6OMBWPVVhaGKbrg7AddgYUvRIreb4gpInkqnXv/ie9YFR+yEWbzgGVlKK571n+U0p9+7hxLFs9rChvHI+QAjFd+d67RdHFbEg7nKeqDrOBZC+XJHKHL0CWGsQODH+AcAWpjZbah85ILnPAtjmi2HMhWwNPklsF45GdkKMCtbHxFenIIydOiz88peGL8ifvA53UtBhDRoetqlJEmcirggDEOY2Q990+lXbzSVlW1CIWZbjAvZ4y+RVLsQ5CATHmNabaYTe1uxW+QRy9qrvenm8xVtYTgsAvF8OTC/+OxLWL3l75n+AGsSgpi2H7WHud3OBqgLUsHxFe2zGx87yvz+DwtM+oIj2CEupex"},{"id":"78195675-062c-446d-9283-15af2c6a2063","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"数据源(DataSource)","description":"datasource","prompt":"详尽说明‘数据源’作为数据连接抽象的核心设计。基于DataSourceSchema基类及其派生类(APIDataSourceSchema、SQLDataSourceSchema、OptionDataSourceSchema)解释不同类型数据源的配置参数与使用场景。通过qgzhc7w3z.json示例展示API数据源的URL、方法、参数映射等配置。阐述数据源在页面加载时的异步获取机制,以及在组件中的绑定与刷新策略。说明设计引擎中数据源的测试连接功能与错误处理,以及渲染引擎中的缓存与安全调用策略。","parent_id":"2574726c-e59a-4bac-8854-59598d892537","order":4,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/OptionDataSourceSchema.cs,meta/apps/caseapp/datasource/qgzhc7w3z.json","gmt_create":"2025-08-22T22:19:14.1201297+08:00","gmt_modified":"2025-08-26T23:11:27.4390948+08:00","raw_data":"WikiEncrypted:lKcMfSUZMkR3lRV3HfVi6/qXil+Pp1fKUtgSMMsq56w2pvn3RqTdEmjlxpevcxA5Bjjp816vsXAEoRSVv6Is8OzkgSLfT51YkCTfuPhDBTE10WdRBAoWfNzYXlC0UvdeCGuOsShO2EKXa6swpJ2PszBWLsfF5YrediVkgLdNb9ALQimp6co6XuUSs7V+MQ+1rlPiktzGBoiC73+AfEBSJWU8h/CTbrT5UPA6iGcTVXipBmLC1n8N9fvsnc4kX7PSOqtiUKArA0fnIAGf8N/BxPXNIKlFCAk5SyZQVH1IWRonebXqn/IUQfwseKIbpGwFIJOOKm69bIenJNegUX2nrGVv1ZmpIr7vCPe5yNitlNvytkqsIckDuPRqQrSIeodK6sbxKEHjE+X0aBoEaloR/2/SrDVVP6Yc9ihzAVnEHgN8Clvf1zWMmP/N9U3awpQVIpo9k3Foh1uqBe30l2UszOBRhXLv1pUSuNUsjFnUk4Nwzeo1JHxz7YsHWTYWuFEUWtzZFRc6VyB94ugJ64DRNb7xziFd8kSug32gX4TlDWqKg02bE7/v5ikuhcJ40C2RItqEhFYQsh4odn3Q43BIc+sO08NVmZfoZIOsEy0zoPnyi6UoZDY/GTpnB2nUgkuliIHpS+RV8dSsu1/EUXfaFR+1PTL+060mWdjMKU+3YXYOcLW7+eUezp7a74+GH5JU5zxblFCp6ID84FrfBgkGtaA0OYuCZ2ojtPj/en+hFNrU1FfpWTYX9PcXf3+YFlJ1A5ru71NLpQJtBpPhtBIwrr0TpoX9SqPivnEKbFOstPNmvae8xeGWr9qNZruULeaMbGx3CKXa6+oymmaIy5/+TiaSmBIxlXfTiAudsnFaHCSVj7MS2lF4yNrm5EfxEsNf0P8rE4u0/3B5zo8v3D2HlFRfaKsKNQOdvECb04f961PC2ybRvmNWhYN2HVnVhU46LgJ1Zgu8PL9yXLRCtUK+Bv15f1p4KneyD0RlNrTbHZyZh/xfUrAOJU/hNyhndQyIkahEZlfEFAdNHFA9JyMUbUpYgz+6mfUI981idqOXvmTQmcvq9HrORX8yo/VjKE0U8xWxsi0FAGd0htkzlocuWxw+8yK/n5/qZ2S/gyekTUyb2NsMmP0s5NGozrRW5grRA1fleELrFl6M/ZeMgDqCcLaklO/eUpluA5TG8i6+y7JKwn6oNT+O+p/A5YZUqd2fElPZ9SPavWBincF5/B/JgV8cFqSaLJjALWmPJlp4vYgPsPQpSb+gPHwuazWVkbaSdztODk1pXSy3JIX/Ldw7Gc6H2UeQx+OM5fZeDbR6f3c49XO56mCsnY/k94yY7guncoxATq3I7M87spTtNKjXOADVYYhVnE4DqKiWqUn+Q9DL44mQOpH1JRKHyKnCVQwN","layer_level":1},{"id":"4c5cd926-f453-4694-9ce5-eb3057100423","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"宿主配置与启动流程","description":"design-engine-host-configuration","prompt":"详细描述设计引擎的宿主应用(Host)配置与系统启动流程。分析Program.cs中如何通过模块化架构(AbpApplication)加载DesignEngineHostModule,并注册所有依赖服务(如应用服务、领域服务、仓储)。说明appsettings.json中的关键配置项(如数据库连接、存储模式、远程服务地址)及其对系统行为的影响。阐述DesignEngineHostModule如何协调各子模块(Application、Domain、Repository)的依赖注入。解释客户端Program.cs的Blazor WebAssembly启动逻辑,以及LowCodeGlobalVariables如何提供全局运行时变量(如当前应用ID、用户权限)。提供自定义启动行为的扩展方法。","parent_id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","order":4,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs,src/DesignEngine/H.LowCode.DesignEngine.Host/DesignEngineHostModule.cs,src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json,src/DesignEngine/H.LowCode.DesignEngine.Host.Client/Program.cs,src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs","gmt_create":"2025-08-22T22:19:49.6224575+08:00","gmt_modified":"2025-08-26T23:13:10.3933407+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAb/+cNOzV1jVh9ZpQlDq/JzUx8h+iLM8Rc8ZNUm7hjBRu3Ux0To4W2qsPPtLJ8hPcuTZDThPiPDPCb9MvV5PCqHhS2PCIIU5ZOry8vJxuIxMyfvppEadUr5KUzTtnfY6iLCImwCCvrir0nvGIzA5C9TzRsFzoOBkWoI6rgoGwukg2zgzoRC7d6skfCLIpLZFgkq+w/RBxhuEHAMSLssrAmuzlnDQPdt+5oE9eF5TpFHhe4yoduaY85v5F35lxb+uSDw9igjiVa4c3Hcwz8SWMgVYNyma+N9rFqfxtt/dtiV0eOOr4uBRB+Ee3UWTtye1Z2WDJbo2SKk410s8VrtLgDANjUtsWIGT04/Pk4i6gBASZTJ6zukuiONby1HSqQdS9fLccgNRW+C3E8/6dwP9oys32Ds0fAq0wOAEj0u8kH8dbAn59jtYflglz+dZlmEOAc7mjz8kCb8yo4tKDME47ofB07ciyohjq0YFUz6m9T1CLIg/AsOxZhdhKWdI80TiVTxNLHhoLBkl85AKQ5uRuZWqDpDkp6SPBNfyOno/hNavGmU7jVFEmUYQZ8/2yEMso/1WyljwqpAouSPMFtT9X9OPh3Bv+AW7S/dB44MNHa2gKB9X0RYzHe2/dqOW4t4vxa/EyZGBbIUe2OtgAtqsqB3MnU0GyOLO5twkxI2N7+EQscYuoNfdcr/89z0JrZVl1ctIEaEe8UmJlnraNNXG/QDeO95atnOmN4FOyn3lDih4CvqPjqiguG8iwBb1ac8gNp9jpFSotp/YORQ4h6op/O08ZnXMmCUxkWQeSqzMxRNzu3shasBuOhv23tji5TU5b6bZrwFEoklc7/s3eO9XZ6+Q9BIaVoqE1JrgH5NoWv106IoIdhG79LRvS74yHNWZipeYYhXRlIAtd4anB1A7dCADAt3Xxxa1/nNRqqw4qmSNe27bgCyNTyzAXWRFzcw9lmnonXlrT3pv0a5pIO++QG0bDMBGWDsFmhgpB+dooWEQknkLp7DgFnAhOhLhvbHQk5t+RndkAj7aGfxvdueIcMrBallSltJocvMOXUqlPcGGDQ+p4GvoRSQ5sZ8wjTgYwDmDxkpT5fdjEnNA9O3Qq+5lFY1134zkCA6NleDGbdjdTGs5cn0evZvjuFXoXt4r/5mUPQxzpOrTWypdMdzTmlgNimTyshiaYRFx87q8OAdUJ5JOL2IxWnRbEXZqZCjbU989blGHq1z2dxcXS+NvjB9ePYSoVE/U/aP/DF8BYZ9VvGuFxCpri8jPry/0r4PkjEeDEndTJuBnL9nVZHDwgmNvy9NFAErYZ4W+Kb5fSwzjM8FUywY/mdgHgK+dxEanlWfVCMwYEDmPPJorMNocA77dWw0DLuV09ByvXmoPM0znXdC1pbcMdt1TmAGyPCJ+pbu1qCRAgxxx/AtyzfzDpHD+aW1CHHezVuh9SoKb6f2Ox621Kngls8iW3fU7M+3bN6dwgm5wAfgW3wszD03hyYmNHwRLpAxRm6iPLvXYjUYcXBXOIet4Ay4qN/srmj0xxmcYXoSzcw4Fwj1DfG85dmu+u+eYZCdwPo5AY1ZxRRp23WLRcMItL3+KPlBBYnbFRdBOVWz/QIZnXWc7zSh0f/S/dsEdXrhUxgcOxp/HhrcnaeLo6XRGnNyDsE2vkuoHW63MGsBcK6iEa3uUdXFBVI8Rh3l7OEPgg6L9ezU4RH/Q08hG9lgL7B+3NfnoNMNpwgg==","layer_level":1},{"id":"bff9eb72-474a-4e2f-9217-1fa6747801dd","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"存储实现","description":"repository-implementations","prompt":"编写存储层实现的对比文档,介绍JsonFile、RemoteService和EntityFrameworkCore三种存储方式的应用场景与配置方法。说明AppFileRepository如何从meta目录读取JSON文件作为元数据源,AppRemoteServiceRepository如何调用远程API获取数据,以及EntityFrameworkCore如何通过DbContext访问数据库。比较各自的性能特征、适用环境和扩展性。提供配置示例(如appsettings.json中的RepositoryType设置),以及如何开发新的存储实现来支持其他数据源。","parent_id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","order":4,"progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.RenderEngine.Repository.JsonFile/Repositories/AppFileRepository.cs,src/RenderEngine/H.LowCode.RenderEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs,src/RenderEngine/H.LowCode.RenderEngine.EntityFrameworkCore/DataRepositories/FormDataRepository.cs","gmt_create":"2025-08-22T22:20:13.2977334+08:00","gmt_modified":"2025-08-26T23:15:00.9056764+08:00","raw_data":"WikiEncrypted:iK+EVtJORL4i9RpuJMg4EDYGvbsEDjPDS9q29hNH7cR9pU0QpohUf0P3thJ78FdlGTyRgwnq//LIvQaGQyX2XjrAflg7tB5mcPNfyi2Bp4kyQWS97tPEc5fbeNPVg0rhJtYvZsJcWUqUzuEtiiAbE9euIs0kiBUogDGa5czhAhj4gkqZ96rcINMeJxXwSBzklV1BW5NxK3oPsa1A7vQBQqrhHsveyW5O3AGgKd6/HHZ5yCfLUJ079OxMg0B6KdPuwgtNjYFAN4+1DbSDzG8ptIZRIZil1UbR8BcVe2aPuqlZS78sqmIVwJarVCBmgffIB01yfDtgXj7ECmi8EC++JO6Rx35KYt5deJRyQGdKMdJJFPwocsLcQ/P+x6dKBoQf02fmiKK9Kw4UMYkHcsRQfPPBehpoZAifqM0jW7b/4s85xdm2E7FBkyUlMtKp9G6Wh0UE+yAYOSEdkFFNjSuQ7XwEEmsTlQM70o009TzLnVBPnKAaTSKWERwWyKALngpIHhpQX2LQ/1X6XHTVZ9mugn85ldEkZi/mfhTI0sBwRfAwR+yEL9Odsg9rPyw9FgjamR++ZM34YCv8kpPAWSPSgXsvGMv0VrNbAO2KhLLa2YkMR2c56m9N4JBuv/IEtyiW183JPiAmZ9N9KEa9/iw5aynibTDTTGdiDuaFMPSpxcpflo1CvFxiJfT4DIpziei1oKxach8KC5vHDrkZ1MER5pLAcznsxiuO9kpjEf+8d5F8P1zVg0VyEY71ndphus4Rc2NgjdpQxALUef1C2lk2niEHbF3Nm0+s/Th+ycEEYI1RB+/F2zqMZZPehzLVt8G11b84SUAIspG15v6FeERVwz61ZmZwRbpDXxdgJm7VRClNu+qwsjMd65O+2GaugEo6SOdG2Huf0HQdJrEwae0gRKfVPlPYA0CY0QPpudX6ROEqfT25oZEb93G4XqV+eLjQNcnLFfiuYO9WhneVj9k8XobLwDoCyqIfjL5sJ+a5TxCu4pDxUoCKo4IvjzZcuTMNHmg3WXIL+PpJdEebXEYXnDQztThpDOeoc6NXouU3O8Yjhvpg9d18esdRmOvDwra7MWW83OUkoXGTxwLDRbp7TsbWrZZN9jNuF7+mXC+vxgR7n6n5mW/y6EIq2NAIoriM3mw6Q5kTRPUlPwUbq2JqAkoahpfQuzEfOXSyEGXV+0PvsLenbO9nHkaCyqFiakxAZwCqEqo/ZrRgtddQO4LVRYLK9omzzNs1N4IT3QkthwnzZTEvQY8hLlmJkHs6i6Q2EyvN+dGTMoXZxRdbNZqm89ITsj5m74sZu/pX6z1njMqdHbNs244hPGqqONTBpco/","layer_level":1},{"id":"b917a6b4-fda0-445e-98d2-46452bac7789","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"设计时与运行时元数据对比","description":"design-vs-runtime-meta","prompt":"深入对比分析设计时元数据(DesignEngine.MetaSchema)与运行时元数据(RenderEngine.MetaSchema)的差异与转换机制。重点说明ComponentPartsAttributeDefineSchema中包含的设计态专属字段(如拖拽标识、设计预览图、属性分组信息)如何在发布过程中被过滤或转换为ComponentAttributeDefineSchema中的运行时属性。解释ComponentDesignStateSchema在可视化编辑器中的作用,以及为何运行时组件不需要这些字段。结合antdesign组件的元数据定义,展示从设计态到运行态的元数据精简与优化过程,并讨论这种分离架构带来的性能与维护性优势。","parent_id":"8aaaca53-5075-4175-a837-be8548ca26c8","order":4,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs,src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentDesignStateSchema.cs,src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs,src/Common/H.LowCode.MetaSchema.RenderEngine/PropertySchemas/ComponentAttributeDefineSchema.cs,meta/parts/componentParts/antdesign/jlcybdkg.json","gmt_create":"2025-08-22T22:20:55.7931298+08:00","gmt_modified":"2025-08-26T23:17:04.2347293+08:00","raw_data":"WikiEncrypted:tQ/n3TmqqyhuGeI8lCgAbx030XnmFkzVXkli8jHqItkXYCHw4bdka3UFSvMAiTFOvxQ/oNTHlE40t9IHayA2EumnZU0fgJ6lE46nbFPo6anrbPRa3WvKsxgmzWmSZUjVc45zc60UQTIiXZnYTU9EDGq9hhjIXWoVwjl2nli/dVnmEqiLgkBngnk8DlcsZStum5U/ijQcqcRzvUL6h2qPhdrtFT/2YRgtPbNqFGRUOrY21Dr1aBwW18l7eTcN2P+j7aCY0E8hrNOsYwMBfMT+2YbIoGgI+2nD5iS7VoKkN9gxQq0iA2hPINKi50Uk31BIppVioypCDCxH+cmxPyN9q8CmBNsfLw/5NmZppmEn0Y9mgi8p/O2uuoQywvKzwalXU20XsJUWtKCHztjlrhxvjZMcpMH4KblXxJTmay14tEtVWFYCGx2AEFbAyACbhicV9+Y4chiGFUPvTu0bqTITC3Y1EdnCfV2HSclaY1n4wVkavsU6OjrWptWeY2oQcQKKPJSDLU+ebYaPoq0dKY9cJ99OB9UgwPfCR8+mxIIxRwnOojROsth/Deg8/b3KYlkEO7tqf71poZrqCNC19kiy8aQuRsI1rbVwFaBShJSa5fzV9wqN2Y9WciwTs4YRm1vXQcMSz7I1GS5RgaQB8KXlmB8JYC55NELtQl6zhJSDg1bYqWjNOnS2jde635paiCcxAaWYc1ojH3q6jbyM71Npj9I2JQqTyvJmBv9Dr3vAbH+b1Wl87Qfhn0ZsEo6fbRORb/iVmZtS/FTbI5x/PbJkhlj0mZ4jGhuhnZRcVzmVx4guEZLgEwk/PpU2FNQKzpncZZvoOomqYbp6Lp6qUf0PCrvckIMVkIdYPn82CPs53FOCOjmzocKTp51Z+A1FtgTqgQYebFJPqVifqnOEg1zLbsvt4Tc6EMip42anMsy8iX1NRoZIaCNTVeJd0xb0hV8Qsq+mY0giArdzPCi0IqGUXPoCdBxbL0oQ0RBk6wojquQtIJDQB0X/xjzYP+olTTd1/3mUZwgeNCyz9Yz2kHeYshExttoZBK0I2AjSTizuWiQ/xLadejoXj05lJbkon4sSghH5aE5S+RYilbXXAqEWda9jJqZU+dq93XnPy8WhEAQaCaq6FlWXpnUU5Q499x98JDYAKPZEMuGw2sOEYtNmqbtMs7Rj8U6Mmtc/R0Jh5iy6EVJC14Wle9TS8bSRlMsrj8Kt1eRjAENQxEzMxwdPKGx+/Mwv1g30A03tL8kBp0Akp1/1qYngT11zOMa+mTiZA6Twv81pnfnqe3DK6aT5oGgBrrJ3G8o3GP9n1Pgu7BXk3bOzeuNDkPLEf6Yco2zA09B41AGkwbdcLIMVj/KA/Yx0p/7IcVSYPe5NJ27LA4O3Y/oFOqQSoblk27Hpc55kWtnxH8TrPJH4HIh6bFXbxp4+SCr3UXhRtaOO/Nv1u1x6nWeiHs4Cn/qiS2huTLNj0o+Oi/1mfQslPk8j8X33uahZLJaaJXq5OLQ4Z6F2m0XpGukpTRNbX7zQJhUksj2dbFUnEbW2auy6REHw7MIurT94MpIjTBtwt6myTN3NDX0VN0NOPBImvY3javDLrxKbBmBa276+koBUqRpM+5M9XmruWwKCMUnfyZwM/h89cLEDpFh8bHr06RWN0RwxLarBbXLsvvehlRg1o68iCcsQ6g==","layer_level":1},{"id":"e2a3e381-beaf-41a1-ae35-53eac12640c1","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"编码规范与性能优化","description":"coding-best-practices","prompt":"制定平台二次开发的编码规范与性能优化建议。强调代码可读性、命名一致性、异常处理机制。针对元数据合并(ObjectMerger)、拖拽状态管理(DragDropStateService)等核心逻辑,说明避免内存泄漏、减少不必要的对象创建、优化频繁操作的性能技巧。建议合理使用缓存、异步处理和节流防抖机制。提供代码审查检查项,确保扩展功能的稳定性与可维护性。","parent_id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","order":4,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs,src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs","gmt_create":"2025-08-22T22:22:00.1363904+08:00","gmt_modified":"2025-08-26T23:18:49.1482405+08:00","raw_data":"WikiEncrypted:wVpQACS8UBPxJkyyBQNEMVVInyReLSqDFfVrTY5qbgvZ9VlTWrWzIqBLIEpLazu5T+TM5fWNy3F8dM43XZxZBO/pImW61t7qD+GGO4XMvjg5Up9gODwid5wyB7g+IE/AzPcWDkS2sMB9hTgshD+AqwgKNtZsJkH6iwwXaCtmm6zFYZq3yaz36IZz4lA2KKnlmwXGVYr9xN/0MNvFH5kTFeHyPA/oi+nNWd37SagwCEOZW/aDnZyhWL1JeDKctiqo8fC6ndeGuvrJYOC2SNjJcbz/bKX1e+PgPdVCUFQfcej5ygB69gyU+02RISn0DA42zxxRVrrs3ST7T5//mOE1yGEMStTygwMlGrBaEWSz1/N/DxEm0+wAbTw0iFIRr9TvF//f4rwkmsTY0HOVdqPvZxsrI+0wpDofwJtpw9ziNQ+qRr236Bwdzn9qL4Vax5m+q6FT2b2e5j17rUXIzluXEXsM9/qCEyxAh8VEWbCGP5Rw5u/qpGH1thbFxa8QJATG5R7P/nQRLIAuRhNXi/U2DnZEvhzU/iBM0dAbo4bCFZvo1nZ0mM3Sap9lk24z9y3+EvwtTR6lagpXi1AGNB8oSSBoIj1gTdi7lT6EunxS4Rvo/+pjJ+w1x+PBPnRKwx2iW4PO6+/fS9YkRwYUQOB0RxDuV16v0MA9a9QHKv6QywYuJuIgUbLOzfjT5UTSIfgUcyhXDSxn7pbQCbL1+mvl6G0mBdibx26qhca1TG1809zFQdjfrW8/1rAFtBbm3AUun3VxRTKn8SpWD6FheN2pQkK5yEbsBAlbdc2CSP8J8ZNYAGMA63EuTgtEyyklprRbI2YUrgxYgQIJ9vlzIc7WuGyxYzGqxr0/CYCZM7NFJKsMDJbdU0ZYsWun2O/4mplpAvvIL7Cd7s0aj1r10sKcfjuJW3XzYlTs+CREzuAbmFlMGgvc01/JlDsk7xZfmUjpUAKrj9XDThgXhzCFLTxm44PiwZCC3w8DNmKSXOTMlHG8BTXd5SIAPcTt3NU9LFFxFsmH3k1T8ehn2uNL3nOqUw==","layer_level":1},{"id":"be444621-aee8-48fe-80a8-70612fceeeca","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"监控与日志","description":"monitoring-logging","prompt":"制定系统的监控与日志管理方案。说明如何集成Serilog框架,通过appsettings.serilog.json配置结构化日志输出到文件、控制台、Elasticsearch等目标。描述日志级别划分(Debug、Info、Warning、Error)、日志格式(JSON)、上下文注入(如请求ID)的最佳实践。实现健康检查端点(如/health),集成到Program.cs中,支持外部监控系统轮询。建议使用Prometheus+Grafana进行指标收集与可视化,记录关键性能指标(响应时间、错误率、数据库连接数)。提供日志轮转、归档、清理策略,确保磁盘空间可控。包含异常日志捕获、敏感信息脱敏、日志审计等安全要求。","parent_id":"87d35f84-473c-49f7-8192-185a0a489619","order":4,"progress_status":"completed","dependent_files":"src/Tools/H.LowCode.DbMigrator/appsettings.serilog.json,src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json,src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json,src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs,src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs","gmt_create":"2025-08-22T22:22:31.0533143+08:00","gmt_modified":"2025-08-26T23:20:22.4703831+08:00","raw_data":"WikiEncrypted:HL3VqGjXq8A3aGeLxAjVPg+lnGgkT5PNghnzp51sgLDjuJwvzPZp6KDp64sXTqk/5Kv+l8CP0s93FbLMTArkbbAKg4+6Ep9HZrYz5rGc6WppMtfdCt15hO/bmISFc/4j/uQgBJnz0PBMepjgb8TlRj+aT/V57Mf9b1dI16B7MjyTOD6ceWoZyk7Reqv+HL1UUSKywQLOE6qoPcIpCnotrCzgoUdCzZenXlf8dHOb8CsSsjnVTIQtWJ0BV4MY2HlaAcep31pw/OBqRBlM+et6+5xwj4OA6XGpKxgIjcF0v5VjTLoZQKCl+5CCLnys72jU87Gj9q/kq73Jkp30qyhMVc57V5eV1C4AepzEXnAktZ0zkJK0YJ51X7gOcZ+AW3/dTv0McsDM37RLHD/Q3jxZxPpohLuaPdlMDcelt8+hC0tb5hvql1puGk+ZsDN+TeqBBtuaSxEEMiy6UMoHfQxzW4LS3B0jLQfuQJRS2kT0KQWIRSjgZtgqbTlMy4k8Li4N4jm3mNXvnXn0RoRZSkW8hzt+bQGoacoFRMRe/OQ6W6mVslugVJU7EpbsYL4k2GPoXGUGLj6hvDMXPWCmcHRgUuhFHvNVGb7R2Kapl5ERL/fBM+aGnFe6aQwg+QC0eXTWKtSCoj5QWt/0T4gaLJgPI0n5/Y24gFtkUoPskEL0iat0fylr3nv6S4FNC0zrU7NaszRLNyd2vKz+DyJHJYktMqzz+3ka95IJX9lpJW4jjmv/9tR7jBxS1u0AVHMi0YpVDyl8lwIaXvyQEBOSFFYGqKJggUNS9rmtWdjY5fZCj4AwrGfBTh33FGodAudT8072nRaJ+JPV6Dpwjh/AZ02FQsOFg6WP0EjsJ8IoKQXV7XeL4ZV51xmm6hy7ycclLiGj+Mwqloq00PRcTa9sbp5Ap4ILrA/LYwrTlUrLzmnuJbn1hEL2jBQWxDhJuypwkDVDmAvqeoBtGmGsqJ/jKqS+TPDjcYSMtHwxIgdj72pYzITO/gs7CAGmTJXyWNCCD88KP5SuZ0SAmjfbrvAJpQJ/16LbUVjxB3EhkDqbvN5az5DMNemZ2K7Uol14GyQECavVBbD6Zo0F9o5/aoMm3zRLS4U1lGa4zrSzBk0jSvJF+onEST0dNx49a52DloPKjkX19LAYDSV4YKMcvlLVkp7Azo5nzyDGXAgYDn/f2W2aDcabKQ8IQsy5qnf7T1H47Li3gZ3lQ/NuehyJNc4ZFnrtxe7oJhXElqf1n/qDySLEGenmKIrd9fpQ1kYSSaOeEtmfcpQGfJGtUPi04tT0UAGEmX/7QLQJxAc7mr+msXEUZvLDO8BtoPZlspXULKc5bnXuNldnLQhvP/EzN2nuOh5ioSzjV2JWJqVPB/KmpB1QNDnle7VqdsX5ivNu3OQmeTyAFOCH+wJth6EmNCc+ztGtCdOiyeW3uC7KSCaSuX8AHz/MmlOsCocv1pOWahI918jUUJVmaS9ggClhi+o/DHib/3K5pFKbJWNyGD2gFGelJgPUu8+fDsIkSW0tLmDpfROryvvE16IcutZdFMzgbatjXjoGM/Tbh7RkEPkNtmbDmvY=","layer_level":1},{"id":"edfa9ec9-83b3-47cf-a151-e4f404c340d0","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"拖拽交互完整流程","description":"drag-drop-interaction-flow","prompt":"整合分析从用户点击组件面板开始拖拽,到在画布上释放生成新元素的完整交互流程。按时间序列分解事件:OnPointerDown触发DragStart → DragDropStateService状态更新 → CSS类动态切换视觉反馈 → 持续调用elementUtils.js进行位置判断 → OnDrop时生成页面元数据并更新AppSchema。说明各组件与服务间的调用时序、数据流向及错误处理机制,提供流程图与关键代码片段,帮助开发者理解并扩展拖拽行为。","parent_id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","order":4,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css,src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs,src/DesignEngine/H.LowCode.DesignEngineBase/wwwroot/js/elementUtils.js","gmt_create":"2025-08-22T22:24:15.1329483+08:00","gmt_modified":"2025-08-27T21:42:52.9415143+08:00","raw_data":"WikiEncrypted:aroBzHAlplzPvyNcdMV5qn8s/c0u345vvAc8EJ4QAaXlf6amMkKZDz6AzEcYeiHvzz5JgdVysqf/9m4VOGgX7RdcCkToeVzCXcbcYV2kfJ4jNLGzru/8NoInJzs0jIQJgfDA16EhhITPjsyIKvae5IJ3XofpWFR+gYB52ABq3IXugJooTWm9+s7SPaw5IoYmWa+uEd6QJCY44c+yVYzCLalyvX84L+LVJ7kDe+YPs2gU/CbOjGpNLzvwPgPNGbbi5jqbevqxlbuo1pgcmblnHwVrlwsizenkTwJB2cSRmymhCCMLvNCpJXX0S9s/seI4wxRvCz7INkiJksT8RCj4fGTIpQLAafT/Dl47lI+JnY9l6WGomIJ2CrJcHGswmw9y9XlZeWWG640K09jKmKJJrHu+jo/I+ZjSKDVSXf8CuvOrRLTzaVefJsR+pr6sTEjg8GSzJBiAUGBXjyDiE41zRKZZ9jBXIUN3oJ/Y4TXaLfxTBVFOr33KEFg5UZbq6pH49nVcBlV/EopG2TLCBsV4otEv4qAJ/Hbl1oPH5jO4kjInqZ+yqYHYKNTL7e+NXkitSohdoPSFLv13G/XjMx5S8en4HQe5jrWSFTKO/t+TbB9JLyDAQ0Vt1pjuR+r/7FGiWDbudcycAW3QIiSwbd9jEvFmP4jm68NLAhWI8/TFaDmwmv72BthjUGeodOOo25bA2QFEi9oj81SuUlh82g/5hrwC8mqb9QqDMgy/q92kpvoALImxFuU02sdrSkh54gnqFv89OC/In9daBi+aulc5OJeCoM1Nh+aN7U/rmga9wXuyGq7sImayjj5ylhFcVrvQ4g6zVL/Rko0fgdyIDyMb3B0+JfivHqhZf76T9qJEs30TlryTZcTm3ePDDrKW9gx8+eWkhJ+HW0w6zGzj1WT+MdgiiInDdw0Fpu2frdvgTN1HRFjdajU5n++9sv41By9QewlpJa5kXNlBU0MAbyWolw84E7JIHlh4VTf8EkDP56f2OJU3QUfGgXEW/LRVNGDYtm1dMLtAyVNRhaorp1/ah6QnduWXfqG8bQ9AawAxqxdnOWXBtCP1L2X0WUIAx7k4B0sKhRT4Om12stn/+QdZvU/ElvTnAB9sdfs6sSr7VbIb7jjOTU81nygCQLVWJwgs25n8UPZiGzarH9rFJuEq/4suFCf+8X/bhcaQOTpH/oEngtUXKOsc90aIAXoU7MwlS7EzJN9aBw8Tv2IcFFKOLfyCrzEh1wozUmCON//gzgk=","layer_level":2},{"id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"渲染引擎","description":"render-engine","prompt":"深入讲解渲染引擎的运行时行为与架构设计。说明其职责是从元数据中读取配置并动态生成用户界面。描述其启动流程:从meta目录或远程服务加载AppSchema、PageSchema等元数据对象,通过MetaAppService提供元数据查询接口。分析页面渲染流程:如何根据PageSchema中的组件树结构实例化LowCodeComponentBase派生组件,处理数据绑定与事件注册。介绍主题系统(如AntBlazorThemeModule)如何实现UI外观定制。说明数据访问机制:TableDataAppService与FormDataAppService如何与后端API或数据库交互。强调渲染引擎的轻量性与高性能要求,以及对元数据结构的强依赖。","order":5,"progress_status":"completed","dependent_files":"src/RenderEngine/H.LowCode.RenderEngine.Host/RenderEngineHostModule.cs,src/RenderEngine/H.LowCode.RenderEngine.Application/RenderAppServices/MetaAppService.cs,src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MetaDomainService.cs,src/RenderEngine/H.LowCode.Themes.AntBlazor/AntBlazorThemeModule.cs","gmt_create":"2025-08-22T22:18:36.9637583+08:00","gmt_modified":"2025-08-24T20:58:09.8822693+08:00","raw_data":"WikiEncrypted:237Hp7b+m+6V491ZOMBhPOGepdjudKIOScbF6DP03ccYg9jP7fO/4w3gz1S0Ua9CeYm+X5uUyY8svixxuguhM2I5QqzdcoqQBgaTCPY923oXMS5dELhL/JmY1HIPIBi7Gb1SSGPEyVX0J320JZZHnpjj5Z5kmrydwESTpF4epNK8NgJgqEZtqtMDlA6pmBGegbas1YLYfFs6mcI46SN5IyvZOoQ/VNrwov73sfikf1x9f/H8Xpcs8XhoHGVfUy/vApbSvI/XUVTPHKvmWkdJqM9q0loafLZZXLoqaoFzu6t4oeE1QAPSLkB3f72QhrPVBo9q116btaRVGZc9jhGepE453BfBDdrm0Li6dj2zNBfMb9wYjR0bm2AzFrbHzQftBRztbcrABbB7YMwiIxpOCg2W8YD1j1sh1/CMVkh429HmY1ShA0Y9K/wNuVXRcjAtX1fRE2OzDWnJd0PSU9i62Pb5GA+CjT/YkSu+PTsp3KszmRVmSWg59P6vpS823anzqm8U6hnjrD8dhvzACSy33r9clVb7ToQrS2q8dqHY7bL/eFLerYgePVLHGSwH0hu9XOWcRLfH+LwQcZX79XHZ7mhQHnp8s2e4JRzzT2VwJdGh3odRN8R4KeI+olvSoqkRDDmQVc8ywQrZWBm1862k/M0CExpbCHR+/tgTpE4db4wroW6+hkckjZWqpUbzk2fzNfOn3hNeqp45MWhQljOWZWRswBmX79csU8ZJX/LH6dK1XrI/VT96ZkWEur8HfZPlrTxQworrG4WVjYgKVQElS55SVV1fDAgChY1FZacsfyDshTK5ouSTjpxJy6/hyV6bq5bmKgcAcWag0lzkOjnAGV2QSi4VnNzmU8XRPakAnYEP5KLKjxiE/iKHzfKmLNZsouhzYC6YdrI5EVkhEy1TaM15qwyfnuYFyeFjssdAMQvpcUMum8yBBtv1fKXnwXWY2E7dg2lp0xhE7+qdBEl1u9CvPJFdgaOhPs/qqh/J7/itOZrChhqV0xtYFPuDUAxu4A59DKzwfFeK2lDkPw+HvZ8IFo9PKP0HRs9ObGI9Wp+S5oIxOi2Ulrn3PL7c7CRz59j5vOGbDX7cIH1TKqbpyVbRUv6bfWqz+E/H8x/pY/dRhpgHa+n6cbCZi+WJMDWyX65o+IGHEy1gpG0Sv2lQ1duxTBsI51kyd/McG+JWeixI1fKKFGURV5jjrMbnGH9R/mycNvhLEWNYef8v1vx7InJYG9uvmpu7PoH5ZGSvNHUddKYdD+kclAGrzvPaZYp69x561ScKWzFn7hCAyKYNsAnoP1iubMWON9dC/I3hgXW0JdFXSSO8FZQjU9QHPK1FnDGuPmIjVghmAEBXa7/XMAuWGVnC2gN3YEQ9gaBNFujxMwaD+5PT1Y8Eq+pUxf2Pr/VynIb6mDE7EPf+zXEXb+6/h1SEHL+w249zgK795/cTnoM3oZNRz+ZdqicqLhZN2iR9y1METXjM8UqlKnTwcTQ2UR4dTs1y/97hheLRhwM/nqWfk2cUpvj+7tY+O7I4jWTn2zT0XLdSIi4rQafL1TzIJqDQ4oyk5Z5s7qgaT8asF8641q7SUdfUANZioQSmwfbEUeMdosjlBkj4AcgNBU7RC5pO964AbnszIql8Y1TrkhJ3fMkpEwi2OqoB14TL2tUzY0+hA+3N524XzYQ6tIlxcsr1ZjmbJKwECvk3cRPKSisEstHzMHw2G2eIG6FbasmGCIE8QUv4kciqXXMyh6xAJoXsTMJDr/6zAm3yetTqUBWDwat/dutWJ+UEJ5m2"},{"id":"21b4b5ed-9316-47fc-83d2-1017375d951f","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"菜单(Menu)","description":"menu","prompt":"完整描述‘菜单’作为应用导航结构的组织方式。基于MenuSchema类说明其层级结构、图标、路由链接、权限控制等属性。通过5omcgxevf.json示例展示菜单项的父子关系与排序逻辑。解释菜单在设计引擎中的可视化编辑流程(MenuAppService),包括增删改查与拖拽排序。说明菜单在渲染引擎中的动态生成与高亮匹配机制,以及多语言支持和权限过滤的实现方式。","parent_id":"2574726c-e59a-4bac-8854-59598d892537","order":5,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/MenuSchema.cs,meta/apps/caseapp/menu/5omcgxevf.json,src/DesignEngine/H.LowCode.DesignEngine.Application/MenuAppService.cs","gmt_create":"2025-08-22T22:19:14.1230071+08:00","gmt_modified":"2025-08-26T23:22:17.7573099+08:00","raw_data":"WikiEncrypted:Jy+7YtOoK4kGSfbkpAz9mJ1XRgsrFMjGXOBby54yN9lMh8iWCbh2ELdfy8LvNqMfXyGgJ05MJYXJqPpfA0dY3JhJ4UtDQ9RGrScX6DH4BT0WyTnUaeTe40NJSh4fbdXDvUhhXWI8RTcAYWRjkKHapKj0jGxmLFeGkAHINRxEI8s2EvauDKS5RUL0VeSUcsY9upDzhmYFY5oh0is7DMxJatO6zuEYs3fUSDTrbrwXF09oPuj9v8CYo0KPFABh2VxmH6sFfNqiqYGdL+0o5nEJlx/EDVs7A+F186njhYxwGifFrmIdEXazcJdqOWEHIsUGWTe3Wutm//kSbcwRJEaLUpf9MlAUyoj61G4E4eSY01m1GrwpE6ewAirmtij5Zz+3j0SnGvQNO5tp2X5OfRNaUMYlqZQeuJgM3bDMCzGxgvbJV5wi3YcP0D0DeQijsypEdV7tCnsdZuYYAg/+dYOFhhB/s8fe4/aOmO6lu/soW4NVB834vcFMssbwE6I5siyYhjCjq+b21jpvBeD61aqRp6p+ouRc9jVYtnOFHq1j7xZod+8r/7GaMiYghuU9yxSWDX2z84vECvsCxD41lJv8gYG3Dmq1gWD6/6FENDV1YL+nPxjHTaQtGqubcjQwbXJdomheGydYit7xarGqTKE2N6a0rw76ibEtfiB9e8VdA+s0V9AyxG0HPyi8lgz9lXPSD42hXZV+BlbG09efKy6wsESarjhQVuowlz7z3gZd1wfOKONyngrme6ZaRpDRL20GVqqDRLiZzedGzm7PajF/ZXLNvDdpZhoWXFHhDnllwkyMv8dk92FmibOsSbZYI9S4LFC/qUQJNPIbaJ3h5VPek82JaS/0jfOKwihMi0IDyiKiueELKlNtjpwvbSIn9yrsMLDuBmWPle2bnf4UgqpcRSebouaPCO/e3sze3dSeevV5rpFCmTL4HGSizJao9wAb8tgo0/XsBTb4GTo2YLpIRXOOiIN+ZwwPJZp2cxh5GQWCSXQioJpHg/DUM8ugAw56ze1SeX5f+OwQiVO59Qiu8Q==","layer_level":1},{"id":"5a33b175-289f-4afe-96bd-ac6db90178c0","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"性能调优","description":"performance-tuning","prompt":"提供系统级性能优化建议。针对元数据读取场景,设计高效的缓存策略(如MemoryCache或Redis),减少对文件系统或数据库的频繁访问,说明缓存失效机制。优化静态资源(CSS/JS/图片)的压缩与CDN分发,利用appsettings.json配置压缩中间件。调整数据库连接池大小、命令超时时间等参数以提升数据访问性能。分析ObjectMerger等核心工具类的性能瓶颈,提出优化方案。在渲染引擎中实现元数据预加载与懒加载平衡策略。建议启用HTTP/2、Gzip压缩、浏览器缓存等Web优化技术。提供性能测试方法与基准指标,指导容量规划。","parent_id":"87d35f84-473c-49f7-8192-185a0a489619","order":5,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json,src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json,src/Common/H.LowCode.MetaSchema/Utils/ObjectMerger.cs,src/RenderEngine/H.LowCode.RenderEngine.Domain/MetaDomainServices/MetaDomainService.cs","gmt_create":"2025-08-22T22:22:31.0559236+08:00","gmt_modified":"2025-08-26T23:24:20.7982242+08:00","raw_data":"WikiEncrypted:9uOBpMbLX4DyZqW4us3Wm3jRF/hxodOy4E5yC98jNVvCQzAkylIowh1uCBS406xhqiZOXOorWk7+jRdBo8IX7IliSYH+TffbrfsnjwYV0tPkQEwPndlzluGP7NpL3MRL64Qz4LpkIYHDsUeXqDFq6EtpPUy3NQF6PbmbYTWZkTb/yl5ReK0PfOijBgCILaXdZx98pwtcGeBN8g7BPXfOdJO1LNkZOZ5UknDOGCymBWQj9/U/HLQ28b1RMfbk5klT3OpYlhl5oN1fS6GR800mIK/bB1GYOXj/IcyWWSSekUTifHSyWAnYap4B+1Qc+qLiqDgJh5BmhUpbZYi/2NLLhFLUWBrdhy/ln5Yu1adoCuZCzZtVe5biIK3blpCClltN8qcDxKmm3pRw2ZOJmGNXTOLbv3JQSjJdycpRzG+ejIw3beapTM6ADeR10KsgRYz9+FTcfBS1I7/hWM4CcAKX08cbKyGccjKcLbFIP8qJRm5SyFJuH4g8wKE0oeMSFBHXRQLxgV970eoaGC8Q1gPGSTuOPK3L2CvTT8INTQk9busfipqaus/DFUOS6ZeA9PeQ1CjprE1O/02ccl+HLWwpbRVtWGRcDTaJxNheLU+yvcOcZDoy/a8flmzEwAfYkGg9lvY/4nOq7H6vd/xEE0fEZDhE3tFXurKLiXigHTz9JfloGNX5oFiclK+E0h9YDcspI4DR6RYWahWk1I3Tf5wz4UQm9m/lcYxhbj+ig4NskhscaUYu2ZlYfjm/p0GXiYvvPqeh2pRM2nNQSDYaSTAnzPy+htGIs5niQhS3he0RCxh7fnJA5QyGnR0igvMnw6ZSeUak8RxZuL7gu7hR4XPve16PxIFMPd9w1a1BX0vXRKONh3+uQ+jgPE16yXoK4udOKk3yHzvhf4nJJqSV3+6UhI3ZxmyneoD1Sjp/uIGkRGvYTSf38LFOkcbgIIT1o0cHVyPwWidPwDig9/D/gqu0UD6ojUk3TNLFgsNVHtJmWdSKa6h5Zi0mpUGK/GjU7CbOIJyfZHGE/5fn8+6OIyDaSEbdp3RQbr6XNjn+GvsxU0AYx3YmcnPt82BxKVEgUdLuin46ojdof38fgYWxmLCkhZjyFCxTn5v7YHIhoRS1QbLMZFLhRWEqk4tlLLAMTtOERlSqqF6gN96Qpr3HbeSZlRBzbfrk75ycVmbRnjs03VZCnvC6LgUNqtYipWiZK0RBnEswd+cCw+LuOYNaDT2ohtVrXfgrZlf4WgxDTJq+WQ2Fl90dBo0mT3YjKYUDAcL+db8SjrOaqCTLdrYdBIwvvCiVvImuS25mi6lFn/3w0ZPbNkYRh03JPzbwyQHKvJKDrYekvhWloRS/qUgYYV1C/GcPiX3k/CcMtK0wGK2Ct/yS7wbTuio++aBmgKM3LbV7Pz1vuUlwBWdjUYZB+/C2vhAhYwM0U2J3R4DbZHjpUCWss3LZVlfIgxk1mST30rCE","layer_level":1},{"id":"8aaaca53-5075-4175-a837-be8548ca26c8","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"元数据架构","description":"metadata-architecture","prompt":"构建完整的元数据架构文档,涵盖所有元数据模型的定义与关系。详细描述应用元数据(AppSchema)的结构,包括基本信息、发布状态、支持平台等字段。解析页面元数据(PageSchema)如何定义布局、组件列表、数据源引用和事件处理逻辑。深入组件元数据(ComponentSchema)的组成:属性定义(AttributeDefine)、样式配置(Style)、事件绑定(EventSchema)和验证规则(ValidationRuleSchema)。对比设计时元数据(MetaSchema.DesignEngine)与运行时元数据(MetaSchema.RenderEngine)的差异,例如设计态的拖拽标识与运行态的性能优化字段。使用UML类图展示核心元模型的继承与聚合关系,并提供JSON实例说明序列化格式。","order":6,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs,src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs,src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentPartsAttributeDefineSchema.cs,src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs","gmt_create":"2025-08-22T22:18:36.9659115+08:00","gmt_modified":"2025-08-24T21:00:06.0278278+08:00","raw_data":"WikiEncrypted:pjGuIDHO+JzqEKf2Vs2HOu87MvYymhtNQ/UUw/3NB5b2Xvwu15GxsyjvH1q25zHstqPaMj+Gp/Jbk+sRegj5uV8mp+Us+7vz3j6Iu3hWyZHCz+5ytGlyDvffzPevYMCisFhtgE5K8wkAyoVoWtqWKvgz1NV33WRlHMErqtP6CyRCx94kcH9LBWth+2N3LBHtM/b2fVGL5TqKdZMx0SNhWBbd/h/dD9LNfvqDnRvnPOkWJUNExkea8tx6dqw8To2Zl5f1GWfC1CturoEKxSsgdZ6H5GRYbxAwXTQcYpOx0jSb5zKOh2fljCwR0hN1JZ00d8HgkcFNtfMUf+bhi6rWvUJmrhisBoMSYoWwSdxiIZd3JHK9rDv7oCuyB/42h5MsQeSEu4eMv/ZLkKGm4EKmYLmOe5BErh3bCY5dPUfXckaZe5o5YjF6VfO/qorOVzBZPZfKb99rbtroMpVQjZwHMggqQxRR+D0ZLnDQo79BQqv+hO7kcitKuqIY1wkFT0ZmqbOD5nJQviRcJoUXj7SgoWdrjxB9VezGQiAJiEMsPmwQL2hnnUGRXtVIgzF5KVgAuJq9MgLNZVuhRAKBPIKYf8wEYeyBB3Xb8ezKtBHCMGtkCvLcpJGz7Ad+QQ7zbpM3nNF3s81r2pjTl+y7ciu0Vk+Zq7sdomRY6883CBoAoukq+ceUgOtUFGlKYo/G2s+L88LsLVjG6UThSCRH8mhvdClLFzOl75hf8BzcS6tLcWtP9ERI7h729cT4K/UptVfJvUfAPCq4HCCu4zpnHnASUMIjXCqbH+YIJY5k7AmECFzQ1C0JH0LI9vOmDVUi6BXtr1jF21xmNa8atmRZM9B5ad9z8dJHi584SiPzzkzNMOKE7hrv2cgVOceTBagROIkoOh7XnAZ2MJosQbeSDXFjGJfpTsvI6CfC2v4o+QJ/BMKXwmwiO2ItpZJuHVTR62GUbYKp7paYxnjpK7ZiHscT9Iv3DAel/qTXeRM07vCDZN5vmKvnufq9nCtMy1hXTJKsiIbpuqeUD71hBuA1JQ/KbzTk3X5Nrxt6s3AErtZzv7yvRxAY0a42Tb1etZMrlPleoGhO4lR2gt8tE3A+i62UhLxpCsqlQ1qarVC1C5sXUo6mXrCymEgVUSnG/RLrGBd0M6BI0AIaqmGgNoY9qIxvXn1hc5znl9c9Yh0U18BdMmOeZWp3T+E6bRBFP+STqX0DJx2plohSgoAAFd7P+0D49S5hkN/hfNnTV7k4KlnnSDE7wHmR3WOzMMYNeoJhO5X580XMFQZSkRWE8IKwOr3tJehRUTNqKvN3RItC4bZI9lTHBmehvijlacVYQdBgcSn6Nk53V4lqqEP8W+pfVPfKVf6GB9pIy0LPDBVoPLUhGcKfj/c4WaSmEBkiXSC7tJZQ3/zhX52dDBht8gJYDJSsbXQcOmxnqXhVlWORVh2lOuXhgf8RsuXyAOxYfA/dtWBolXIg8kxQPcn6UjGH8/bPj82FfXgWTvy8zYU0PxHToXCBBocsj9u6+Ml2vnokPTA22uCcP0nJngH1yDPCx33VTD07KIr6F9xJJNUfgZ3gygJ+FDLnYpyLC8/6P57BHcx9sswC/Um7wgu6dm7HluXE00ich0OdNDljYCFcx4kXO1dCFE+di7HFmUrTN1LvV9dVCG1KtawJvOIVd4qRwUEEgIb4sYcx7cVHMg+/efYECQ0V1X1xAKB/i0qZNP5C8Rhx7gg8AeVCL51TtyabJbTluMlI/wO3e7MG6EqQ1Kdax9DqavCnoB44J2t4c83T4nGFtkIbI6/09KGbQupP4AHO6lrvsgdYrz+TYAm8d2kQJx2gUqb/OEaBRfF75Y8DNlF+AAzNbbWFrJWVhxFB/ugfhlXmAuau5/BmYDBkW9jVECadKaKVsiD1NQGik/UWSJ7TUk60LUizkNAckpU39AxiHlZuRlCW2RT5lzGCDGEvdjek3qcLDzTpYNTtS3CJKBe8"},{"id":"1e1f9cb3-49a3-430a-b3cd-3b2dd4bb2603","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"扩展与集成","description":"extension-integration","prompt":"提供关于如何扩展和集成本低代码平台的权威指南。说明自定义组件开发流程:如何定义新的ComponentPartsSchema,实现对应的ComponentLibraryAppService,并在前端注册渲染逻辑。描述数据存储扩展机制:通过实现IAppRepository等接口,可将元数据存储从JSON文件迁移到数据库或远程服务,重点分析RemoteServiceRepositoryBase的抽象设计。介绍主题定制方法:如何创建新的主题模块(类似AntBlazorThemeModule)来替换UI组件库。阐述默认组件包(LowCodeDefaultComponentModule)的加载机制与覆盖策略。提供插件化开发的最佳实践,包括版本兼容性、依赖管理与热加载支持。","order":7,"progress_status":"completed","dependent_files":"src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs,src/DesignEngine/H.LowCode.DesignEngine.Repository.RemoteService/Repositories/AppRemoteServiceRepository.cs,src/RenderEngine/H.LowCode.Themes.AntBlazor,src/Common/H.LowCode.Components.Defaults/LowCodeDefaultComponentModule.cs","gmt_create":"2025-08-22T22:18:36.9686391+08:00","gmt_modified":"2025-08-24T21:01:53.9429418+08:00","raw_data":"WikiEncrypted:9tFZPEMPWdLFkkE2XbXYMsgAB893R1hoQbifkGrkdO+O1/siIORqbf4UuxfslSvzF1h3dDPfGlid7D+PAg6Z8KlmQ8jDXuMfR61mCFN0YdjBCbPf2qkLA9bSyw+FTMZwfEk6AM4CZgCJROj+gQtIhNNSBYQhrv36zfN2iTSiWwrFja1ejE204HNkj12e1ZpzYbLogIamT2xN22Q/vuRh/QHf+7V5iHABtctTNLENm5L4/4kRL1XsDvRSDg4vxx4q/XIjavM2WWX2Cr39gYerhK8Ndtg/gXXp+0q/Vnh/TBKAuQdNO46YZrnoIqy3cRL/3w6byo4ID/keD+HsR2UyBD7zEUMBQ/lvSZaxwyHlz8aPDgrmkcmccT8yxzw4lNbgEkzi7aervldPtaxbWU9LYXG6a3x/As3J6oV1VzcZAzoTk98M/p/rIlS0cp7UjGL1ua/Y6qd5DeuNBfYXIcyX3vr7e4amlGdosxfM3Fj20iaOjVqwSO+fXYRt8ar3aTPfK6Y7jN6cuc617wXo6R75PZJERHOQwl3w0SKNfvWwWzzJAvDPy4Ut5uT1sEuj+urhXdz/VZOLi6+ruxghQdH2cpoFe4CQVRMT7udPhkoARiiEjnrESV5Kzxj6B8EO6mNecVyKWcpm9oXi++Wx6HqzYtTH87JTkWspSB6sLpahDVHpqhvKfTD4aOfeHVVEmZxt1+GS077jyr4CN97n0Lfy42osjHHp934RZZe4Bt+uvf1w5qk00STiNN2Vc+cv5tQgE66i+qEBX7JTJ9GZsHwi1GQSkYpe8+WmEqIHlrfDAtLWY1dSDggV4btjFbjVWuUmyaKHmZvZDgcH/usXShNptsXinnjyhx0o0bCY7mgR0qo8wCJqwthiqoET0JYCnQ9W/TCNhl8ROxxzMmDYsn97iz3qqUaRX0PL8lDWBlX5z4StInMMZ4pqOUDw3MCS5LmyyeGTG7hY7PW27Q25ade3VKdbQhlNIYDunEqFuVZCzk8h4HFlzcKqq2NMnMYqO7zkB25rg58E/srWHG70M4yB3wDbljztoXBUE1DOJNzLVDgFQk4HI9Fn8TZ8S2uUu2kHXTnJpiDZLv1GSKLdMNzXEIW941DOsrd35aRTG3zUVJKV3finNG6VOaAtMTn0rU6mjnHYVRMXo7NQZLkvkIeke3m5mVDv+ijmjUF1QpBXrNZduUf3FMgudFOS1FmFLZu1q5OME/7wwWsYsXIOgh+Onr5q42dM0NApJ5/k7MGVi0+8f+w57r7rG0FK+S3s9WUlCkxEborvXmEV43TBSbAPFDNRfMq1tp+bRIwnn8xOcm22hgf0n/2H0qDuQAYKceAR8DCKivxIzfklrr2v9l7nXpNJ0OJjALQdK6hqWpQ704gN/e/NUvIFSDtTbwHouz2IvqKO8SU7lDS5uLU36Mhg8T7XI9oKcHUEzcbEF+PEMs3ncnDMAcczXOC5HTa0sfSAVOak91NM+o1MDSOSUp75rEtebup/MD5n/hJlgFhlioG1v1lQbnYasmwsxXCop4H3ctgEtNvA5gdOeUML9kRheg7kkFzoPCTBd03Er1q5DXzSHqaG3UnlytVCCpuk8Cg72TXSXJVolmeSMiO51NmN3+rMVAENV7K38G/ENWA/i2LQHx4vfTJV8LT1YyZm8zvXoZVJQSYeKm6m8gaN52XmdyeFWn/lEmj83lw0aUD2i7uAg9IIlCvwXSmHGC8rXr/Q+N0MmLUgD9fmmYg2dAbqe+RqPkZ9x+jXCkDglob5KO58qGQuS/RQWgN7NlKDh8RG"},{"id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"开发者指南","description":"developer-guide","prompt":"编写面向开发者的实践性指南,帮助其快速上手并进行二次开发。提供详细的环境搭建步骤:安装.NET 8.0 SDK、配置IDE(Visual Studio或VS Code)、还原NuGet包、运行DesignEngine和RenderEngine。说明模块开发规范:如何创建新的ABP模块,注册服务,处理依赖注入。通过具体示例演示如何调试组件渲染流程,利用LowCodeGlobalVariables进行全局状态跟踪。介绍动态组件加载机制(LowCodeDynamicComponentBase)的实现原理与调试技巧。包含常见问题排查清单,如元数据加载失败、组件不显示、事件绑定无效等场景的解决方案。强调编码规范与性能优化建议。","order":8,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs,src/DesignEngine/H.LowCode.DesignEngine.Host.Client/LowCodeGlobalVariables.cs,src/RenderEngine/H.LowCode.RenderEngine.Host/Program.cs,src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs","gmt_create":"2025-08-22T22:18:36.9712923+08:00","gmt_modified":"2025-08-24T21:03:33.5261364+08:00","raw_data":"WikiEncrypted:F3QgleoEfoy16cQggYe9C5IaSqlGa9MAZLOFAWytoRMydW9CaKFacxmHFMFvq4MO4qJbomNzYz9hncXLdeBzq//XdmQOZ3tqTmBCYycMyw8yv9qjk5ejQUgQBLyC2HfhjhB41N91T/d+il82/C2Nj+gJbN96kqzlE4D4mp5BjUQ1w7P2N1SwxsTBo+YVuwAWfZakMzbJggWX+nWZen2s1pPuljXIiv+cdMH3PvgyrAh50+WGD6bIkEBX014VBL/w0QBBc2FIEmJNWcnfJ6LOOF0h567XnDk/tEIxnBmSC18hlQB2o7GpM9+lR/l1+BOrgygg9LG+34+jd4q3UufwA2eCNs/7hNey3jv58+XvnRL2z7HY3ectNoplsX+v4JEthnL3nBsffmaIC/x1WcvRsjDAP4cG/PbF+aptuP8fyYZDJHxwZfqaQ3SrvnEhydyI2bDNH/TKkUZb2KsPGrBSUy6IgdyvKbSkcoqLRVw/GvuU7wQAZlW5dzzwVSfb+y89eDLd/D/YfEKt4K7DA2ULwqlcvbqtPfYNkVzVJ94WL2iR0QCMVImCfjLjq84xgA49pxANnMdnfd0uVvoY/CXfM8oycBZt0hIoFCk1XY3I4uuww1F4lQMMtZfoD1nRmVh9iXBJ26rBft45HeGb+ueY6rQCSigpvXDRMeCfEi3Sa6Emkna2bkoi2c+nSBdFBH4dxNbDKZ+l7V0r+BjFBv+EW1oz9u+n127Vq6FHSED3kZPDZU6bNK2AmcC9KajReAuKvd9mtb0rRA9JT0Yv8iGXxDltu3nNqOw0ZomPsQsXlrWztVEDNkGms8rTeqeHuIbVxu4NmA6+pWLwcGD9VilVcixno5neJ3IBpuIS73Om+ssefHOeHjMxcEXp34okbNfjuKW99WlfT2B/UCaK3wZ9F3TQkqyj/+AY9l5udEIK0GUWg1f2ZORWofvxYIte1KksqcHBfqEEtmGBFyg4o0sgMmHc2oATKUcDt72MiLTWD1VFbiEEXsEzaT15ITwV3Dd71BJgv6ZjQdIwyLasw1xcVma6zVEwsUVT5VWyn8YHnZpbZhyWUvY9LvZrcnZ/rl9P1fC/CH37iNmSLxsr2ea3J6WZi9bMKpPtrLqo/wcYzQDfA1/DnXX6JML/2EjQVI6paAQHpb4rKpCtu/4vXFSfXujoFatvOQfVVX9mKsoKkxSuU59ME0WQDTKHOxTPXuKGV7LUA1vCYY+bC8ud8U1L5TSPJIe3x/UISNz1dAeDSk22zfHK1FZyICUGRRmzhS18HsXUYFiQBXT3ojjlNAyrBKlv2LngSXgxS/YQRe4pvqRW1fW+5NrPsQHGtHcna81UNwbHZ4eM0yO1FgIMqYwXDHIv5cD9JnYnIF05qwQUmkZYC2A0Mi/6Vg5tCf+nu2/uNvN+ZXUC5krKYzA+AtpYt/dSuP7JJAOJ9iXjKmVKgJ3URHnXARThvAU0Yz1NVb7dB2bcX0tb5Je9hIWPt6nqlTauvGvvLaZzoZQWAqgm2DJYRwhtwUpa7lE4P996ny+PofuWU5o5rTEsnvRId5e2/NHNGszKXyoj5DUC9RDUs/GAij/aCY8XUnZ7UiqSR23c8p5ljTjBt9S4Jnja5LAHtD0FlJb1UiFegL9KC/pVFeLqhPQvQPU0+SWST7o80fvofXVqRzuw4ike3oWpmUmapmqoq0+rxJqrhEMiXFw7LTE="},{"id":"87d35f84-473c-49f7-8192-185a0a489619","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","name":"部署与运维","description":"deployment-operations","prompt":"制定完整的部署与运维方案文档。说明多环境配置管理策略:如何通过appsettings.json和launchSettings.json区分开发、测试、生产环境。描述数据库迁移流程:利用H.LowCode.DbMigrator工具执行EF Core迁移,确保元数据存储结构同步。介绍应用发布机制:设计引擎生成的元数据如何安全地同步到渲染引擎的meta目录。提供Docker容器化部署示例,包括多阶段构建与镜像优化。阐述监控与日志方案:集成Serilog(参考appsettings.serilog.json)进行结构化日志记录,配置健康检查端点。包含性能调优建议,如元数据缓存策略、静态资源压缩、数据库连接池配置。","order":9,"progress_status":"completed","dependent_files":"src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json,src/DesignEngine/H.LowCode.DesignEngine.Host/Properties/launchSettings.json,src/RenderEngine/H.LowCode.RenderEngine.Host/appsettings.json,src/Tools/H.LowCode.DbMigrator/appsettings.json","gmt_create":"2025-08-22T22:18:36.9733738+08:00","gmt_modified":"2025-08-24T21:05:42.7671453+08:00","raw_data":"WikiEncrypted:0IKfLNOWe9mZfG1jVts3w2XbjO+yyEmY3ONOjrL5GjA8+3c0QEcD9OcCVHu+1BW/N5NkoQV86wegqQ9ShX8iSYjr+qeLW21xdW/xLSHZ21VPZMSqCKTi5key4dc3pQ9ZGe57qQzsXZhcJM8ma/nIWfsfQlNbrKVYHaXSeJl6KNaejisLwpIp3TVf6ucBsHzFH0ZUeBKmakBs+k/WeG2q4LqJHPP4WdFuCeld3FlTT7cO1G7oyXEi6FaKjhPKZCn52/82oqkVp/iovtGyBS395Vc5FaKH9RutZKKO3NhKIqKONtsW2lxQ/HeHHq1RLU1Eu09Y9uQ/RMD7/ox7/rb63QNekFB4QsWDwxJQ2ypnpP5/tqPQbrg7EGtc0ljhWbK2RtJBa5WeTuDlP1oCFgzPVawm4ImGIeDGvrxfP6b8f8e65tIY7eBjAp7ZBnd6DY/mqZCLYplc8x+sVQ7LiHR3wtH/LzjMVNXTGzIbRSljUvmG/vkaztJ9lJXj9/YSOcRNr02/iczBj37wnEP+tAI8uSWlWbPw+4IATqJrQCIJj6g2080jOTkEaxhBHoeCNc7q0o32ECCVYUy5tX9NvvFvDJ0um2eTVYf7QTPky0WDfwvigyC65umx3z6zAagMTlK6s8PJY+xwq7DSD8+nTQX6yCYle32Bb60zueW26WeT+exST8bfLA2pyDpbodgcy6DcT3MGd8NXbmnbr1l8wmQpZjolCUJW3w814aL4WBC4q7711vgCxeDEHslgPWMR2KxcRB8wPUeJsAUkZh3gKuCbI/AzWMeop/09KVXJecpCaZFV/C1D3Q67vfXJG9u2rQrDPdtXcPN5zhWK3Fn2xGlFrgVS5RK94+l4wKNHv8gzh76WEHVCJYv/iQzPFwKWOdFAfkgBWMI5KiUuWBwPXOyzNkOcm8xiQIU5mU5Vuf09K0fK3OPAUNaBOcrAKZIsfpgGT+9MLSYxbinVcFDaxOBK2EhSBwTeIJUghUIgPMAUg0vl1IBjuG2HO7i3Yr0r37fe7TGNYCWHoWHWehQeqKTXSHsN+dOe8qtXBzMxdJwfKlPmQ0GhdmmiG5RQB7Hi1oMDkZhnQy6UxMdF1Hn0HkWPYargBqsZWzmdT2jcvzp7VCb9jXdZHX7Ova6TB0ycxj1RHt68JfYIzB+LEK//6Lai+2rV7YNFp7ya5To0XwgjoxiHKkuREoySbLPebUEf5kt+8VbYiER00R0zkKg8iuxQQckj9JztjxfF2izwb7y/R+y3b2OBc6k1RR54bS6v99lshZpM5wKbpRS2tDPD9/qvoOEc1mROLbLRx+D6sWuMi1s71syIZfWFiQVqM7UqxCYDfE8NBbTuMz6QpbChMndT1wIHixuAeL2x9BvS85pocSjaXpZ6jRULIZDA7Xnzgp2dbAUdmL60xZ5wEL7pk2emczz7SvZgsFKq/t0LIOmjwRnsPVOt7rMPAe3WBBiezMGoHdkZdpwMwW5xvb5/w4/p1XdgKbRtuID8F4ejdYeCTCD8bZmSOfRXzauRBK6HRd80krH7C+CITCecNfYyHtQXijEhebFeTaL7ML9gF5HRmmrSkyrYxci8Uthxrj1+TsrzBGN1LUj07gr2MswOpP50zcKO647sSIl7UcBKoS2f0dqYiKBVrYZSm6BORYKKG11TG7D4MHyLRzWJnXOdPZXfEj8skAWG+dTa9vYHKuK9yT0="}],"wiki_items":[{"catalog_id":"4ce5331a-49f0-439b-a805-1d5b0672cc0e","title":"项目概述","description":"project-overview","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"25223cc3-c435-4b2d-9d6e-2984bf3fcdb3","gmt_create":"2025-08-22T22:26:29.4466471+08:00","gmt_modified":"2025-08-22T22:26:29.4508352+08:00"},{"catalog_id":"8d73d789-bb4d-48ca-b28c-4969413d3977","title":"技术栈与依赖","description":"technology-stack","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"0c524ddd-40a8-4da2-8f8f-07fec6bed2d2","gmt_create":"2025-08-22T22:29:01.1241283+08:00","gmt_modified":"2025-08-22T22:29:01.1283243+08:00"},{"catalog_id":"f3b960b1-9f70-414f-aacf-f61651e56944","title":"目录结构详解","description":"directory-structure","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"929755aa-ca54-49c4-adc7-582a1a2e5327","gmt_create":"2025-08-22T22:31:18.8901164+08:00","gmt_modified":"2025-08-22T22:31:18.8943505+08:00"},{"catalog_id":"2574726c-e59a-4bac-8854-59598d892537","title":"核心概念","description":"core-concepts","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"68c38938-1ea6-4aff-b602-f7491d11bec4","gmt_create":"2025-08-22T22:33:31.7684727+08:00","gmt_modified":"2025-08-22T22:33:31.7722091+08:00"},{"catalog_id":"04fa9367-cb96-44c2-8ce6-6159b13f7fc3","title":"设计引擎","description":"design-engine","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"779db891-224d-480c-a1f6-cd45f05ec24f","gmt_create":"2025-08-22T22:36:52.4470366+08:00","gmt_modified":"2025-08-22T22:36:52.4523773+08:00"},{"catalog_id":"e7bba7a5-0426-47d3-9dfe-208b249694e5","title":"渲染引擎","description":"render-engine","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"6d7453ba-7542-47ef-bce0-c4dc101327b2","gmt_create":"2025-08-24T20:58:09.8762769+08:00","gmt_modified":"2025-08-24T20:58:09.882868+08:00"},{"catalog_id":"8aaaca53-5075-4175-a837-be8548ca26c8","title":"元数据架构","description":"metadata-architecture","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"e8a7501d-f01e-497f-8f10-78d0c36dbbec","gmt_create":"2025-08-24T21:00:06.0224465+08:00","gmt_modified":"2025-08-24T21:00:06.0283706+08:00"},{"catalog_id":"1e1f9cb3-49a3-430a-b3cd-3b2dd4bb2603","title":"扩展与集成","description":"extension-integration","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"23649ef6-2714-4508-8db3-da7c79f0758c","gmt_create":"2025-08-24T21:01:53.9381896+08:00","gmt_modified":"2025-08-24T21:01:53.9435266+08:00"},{"catalog_id":"1e2052c6-8d82-4bc5-87cd-652128f1cbcd","title":"开发者指南","description":"developer-guide","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"3e45fe33-bcb2-4eac-94b1-8f3e9d5a74ed","gmt_create":"2025-08-24T21:03:33.5211181+08:00","gmt_modified":"2025-08-24T21:03:33.5271897+08:00"},{"catalog_id":"87d35f84-473c-49f7-8192-185a0a489619","title":"部署与运维","description":"deployment-operations","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"39c35184-e954-4764-8812-b1096f985fa1","gmt_create":"2025-08-24T21:05:42.7621994+08:00","gmt_modified":"2025-08-24T21:05:42.7676831+08:00"},{"catalog_id":"c91fe434-c407-497c-b0a8-28a8d97f9bfb","title":"元数据(Meta)","description":"meta","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"203a66f3-9cc8-41c3-9d34-cb84dc4d84e1","gmt_create":"2025-08-24T21:07:39.1867852+08:00","gmt_modified":"2025-08-24T21:07:39.191569+08:00"},{"catalog_id":"be52f1c4-850c-4443-ba95-8808d1e5b997","title":"应用服务层","description":"design-engine-application-services","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"be91fa0a-2dc4-4738-868b-55ecf9d024a6","gmt_create":"2025-08-24T21:10:06.0862627+08:00","gmt_modified":"2025-08-24T21:10:06.0911242+08:00"},{"catalog_id":"7107c49c-e77c-4166-aa50-ed136792a235","title":"渲染引擎架构设计","description":"render-engine-architecture","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"bd8c617b-ae78-4032-937d-682fe7e7da0f","gmt_create":"2025-08-24T21:12:09.0143361+08:00","gmt_modified":"2025-08-24T21:12:09.0218579+08:00"},{"catalog_id":"dd4fca38-9892-4566-919f-c085a60e4f8c","title":"应用元数据结构","description":"app-meta-schema","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"2af2d914-b932-41c7-9c4a-1f0cfdc60c40","gmt_create":"2025-08-24T21:13:59.3559151+08:00","gmt_modified":"2025-08-24T21:13:59.362328+08:00"},{"catalog_id":"181a7e87-3336-43f0-9838-c9aa9e51900d","title":"自定义组件开发","description":"custom-component-development","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"a6823e8d-6215-466a-82f5-4894c0ebf4ff","gmt_create":"2025-08-24T21:16:15.0563037+08:00","gmt_modified":"2025-08-24T21:16:15.0648365+08:00"},{"catalog_id":"5f2e137a-01a9-4e46-b8f4-e6693fedc472","title":"环境搭建","description":"environment-setup","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"a5be60ac-c5cb-4af1-9cfc-693a5cba35e9","gmt_create":"2025-08-24T21:18:04.7029052+08:00","gmt_modified":"2025-08-24T21:18:04.7077318+08:00"},{"catalog_id":"12a7dbc7-c445-4d73-93b8-fe711309acf6","title":"多环境配置管理","description":"environment-configuration","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"dedb4619-395c-4c14-96a2-4221606cf927","gmt_create":"2025-08-24T21:19:46.3872082+08:00","gmt_modified":"2025-08-24T21:19:46.3916824+08:00"},{"catalog_id":"3be754e7-9541-435a-8ccd-d1a749c5053c","title":"应用(App)","description":"app","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"53dcfe8a-34fb-40f2-a47a-3b8a495f457b","gmt_create":"2025-08-24T21:21:36.6720988+08:00","gmt_modified":"2025-08-24T21:21:36.6774511+08:00"},{"catalog_id":"e52a6571-a012-4e2a-b5d2-e5f94c01d367","title":"领域服务层","description":"design-engine-domain-services","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"e0d60f25-2aca-40e2-b2ef-3e9b39fcf18e","gmt_create":"2025-08-24T21:23:19.0153873+08:00","gmt_modified":"2025-08-24T21:23:19.0212899+08:00"},{"catalog_id":"ebbc53b5-bf0f-4abe-b35d-ae36efe39917","title":"元数据驱动渲染流程","description":"meta-rendering-process","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"78e9f6aa-4c5d-4c0c-bcb8-8453feaa64cf","gmt_create":"2025-08-24T21:27:41.8186662+08:00","gmt_modified":"2025-08-24T21:27:41.8256934+08:00"},{"catalog_id":"5ab4ecd0-2c5e-449f-8d8b-b54169ea1de7","title":"页面元数据结构","description":"page-meta-schema","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"366036bd-0220-49f2-93d7-3cddf12e2540","gmt_create":"2025-08-24T21:29:38.8136218+08:00","gmt_modified":"2025-08-24T21:29:38.8194887+08:00"},{"catalog_id":"34d1c9bb-bc55-42ce-b93e-6e0e210ee024","title":"数据存储扩展","description":"data-storage-extension","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"f240d134-002b-4d5b-b243-3352574496bc","gmt_create":"2025-08-24T21:31:27.2012718+08:00","gmt_modified":"2025-08-24T21:31:27.2088583+08:00"},{"catalog_id":"f6ff38bf-eeae-4883-b8ee-0fca4824a1e2","title":"模块开发规范","description":"module-development","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"e3b30f07-1b92-49bd-8078-fe657fc7b881","gmt_create":"2025-08-24T21:33:21.0432903+08:00","gmt_modified":"2025-08-24T21:33:21.0486884+08:00"},{"catalog_id":"cabc80f8-c5bc-4872-98e8-da742ab3e679","title":"数据库迁移流程","description":"database-migration","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"35dbaf11-1833-4a9c-840a-39d4976a19a6","gmt_create":"2025-08-24T21:35:25.0518029+08:00","gmt_modified":"2025-08-24T21:35:25.0580003+08:00"},{"catalog_id":"248d9c53-8364-4f15-a960-a9edec151baf","title":"页面(Page)","description":"page","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"b95cc9b2-554a-4589-bbe4-a3bfb6fed2dd","gmt_create":"2025-08-24T21:37:16.4268729+08:00","gmt_modified":"2025-08-24T21:37:16.433807+08:00"},{"catalog_id":"d3062028-65d4-43ea-a57e-3d6daeb99be8","title":"仓储实现层","description":"design-engine-repositories","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"672e378f-57c8-4f6d-a79b-730b4780238c","gmt_create":"2025-08-24T21:38:47.3990756+08:00","gmt_modified":"2025-08-24T21:38:47.4039536+08:00"},{"catalog_id":"bc9736a7-f157-41b1-8432-687da240a40a","title":"数据访问机制","description":"data-access-mechanism","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"9baaaecc-9cac-47d4-a545-225ac807ccd3","gmt_create":"2025-08-24T21:40:22.7619835+08:00","gmt_modified":"2025-08-24T21:40:22.7685712+08:00"},{"catalog_id":"72ac7e91-db1f-4263-9b47-b6784e8b08c6","title":"组件元数据结构","description":"component-meta-schema","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"44c1635e-bafb-4913-8696-95dd5b196c3c","gmt_create":"2025-08-24T21:41:57.7326588+08:00","gmt_modified":"2025-08-24T21:41:57.7390231+08:00"},{"catalog_id":"6b51305e-fed3-40c9-ace4-74ffed8613ee","title":"主题定制","description":"theme-customization","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"87b9f03e-2fa1-460b-9cd7-7c9b1a540f3e","gmt_create":"2025-08-24T21:43:59.1354468+08:00","gmt_modified":"2025-08-24T21:43:59.1404238+08:00"},{"catalog_id":"3e42833f-debf-4ec1-97ae-33628d0eb521","title":"组件调试技巧","description":"component-debugging","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"459a2113-22f8-401b-ab96-6aece5f7a9a8","gmt_create":"2025-08-24T21:46:49.6231973+08:00","gmt_modified":"2025-08-24T21:46:49.6286676+08:00"},{"catalog_id":"8ce24715-ed98-4599-8450-cd4e92acf954","title":"元数据同步机制","description":"metadata-synchronization","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"aad8a2bf-f757-49c1-aaf7-7ca32a2cc846","gmt_create":"2025-08-24T21:48:57.3932551+08:00","gmt_modified":"2025-08-24T21:48:57.3986461+08:00"},{"catalog_id":"dc56074f-64cf-4511-a7aa-c69d30f2b042","title":"组件(Component)","description":"component","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"62c2f61b-d498-4f58-9b59-3580830c6560","gmt_create":"2025-08-24T21:51:23.4700564+08:00","gmt_modified":"2025-08-24T21:51:23.4760243+08:00"},{"catalog_id":"2efdc990-90c6-423a-9f5b-adf795fb3cbd","title":"UI组件与交互","description":"design-engine-ui-components","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"295c6fd6-65f8-4c58-af2e-ab08d27d07cb","gmt_create":"2025-08-24T21:53:26.9596095+08:00","gmt_modified":"2025-08-24T21:53:26.9652862+08:00"},{"catalog_id":"3689e15b-292b-4e92-b40b-0c1a8446fd21","title":"主题系统","description":"theme-system","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"ddd86ca7-139f-4e74-a6fb-9c30d5dd0678","gmt_create":"2025-08-24T21:55:27.7462519+08:00","gmt_modified":"2025-08-24T21:55:27.753192+08:00"},{"catalog_id":"ddca48e2-b166-4269-a644-dc7bc00ad3e5","title":"数据源元数据结构","description":"datasource-meta-schema","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"a2546f28-856e-455a-8793-93bb03349eef","gmt_create":"2025-08-24T21:57:33.2919265+08:00","gmt_modified":"2025-08-24T21:57:33.2978168+08:00"},{"catalog_id":"93ebef01-275e-4466-bd46-741408c9e061","title":"默认组件包管理","description":"default-component-management","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"9217137c-b4e9-432e-8821-cc1cfecfa572","gmt_create":"2025-08-24T21:59:38.2890771+08:00","gmt_modified":"2025-08-24T21:59:38.2952658+08:00"},{"catalog_id":"12a2718c-bc93-4d0b-99f8-53f8879be7c7","title":"常见问题排查","description":"troubleshooting","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"e2e2ed9b-ca7b-4806-9218-d12e9d0a39b5","gmt_create":"2025-08-24T22:01:29.5189842+08:00","gmt_modified":"2025-08-24T22:01:29.524714+08:00"},{"catalog_id":"3f7e22c2-c859-4f5a-b62b-4db9258f8e7a","title":"容器化部署","description":"container-deployment","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"868ef220-a297-4fb0-a5e0-382e83443de1","gmt_create":"2025-08-26T23:09:08.7030919+08:00","gmt_modified":"2025-08-26T23:09:08.7083212+08:00"},{"catalog_id":"78195675-062c-446d-9283-15af2c6a2063","title":"数据源(DataSource)","description":"datasource","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"dabc53e1-9ef7-4796-8918-42b5b9d8b678","gmt_create":"2025-08-26T23:11:27.4354278+08:00","gmt_modified":"2025-08-26T23:11:27.4401438+08:00"},{"catalog_id":"4c5cd926-f453-4694-9ce5-eb3057100423","title":"宿主配置与启动流程","description":"design-engine-host-configuration","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"7246ad3a-a609-41e6-8dc1-da8275970ac6","gmt_create":"2025-08-26T23:13:10.3892595+08:00","gmt_modified":"2025-08-26T23:13:10.3938796+08:00"},{"catalog_id":"bff9eb72-474a-4e2f-9217-1fa6747801dd","title":"存储实现","description":"repository-implementations","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"b56a7e73-74b0-4c65-8370-64bf96d9fc3b","gmt_create":"2025-08-26T23:15:00.9009394+08:00","gmt_modified":"2025-08-26T23:15:00.9066981+08:00"},{"catalog_id":"b917a6b4-fda0-445e-98d2-46452bac7789","title":"设计时与运行时元数据对比","description":"design-vs-runtime-meta","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"a2051317-8410-4e35-a8a6-42dcf139c6e8","gmt_create":"2025-08-26T23:17:04.2300012+08:00","gmt_modified":"2025-08-26T23:17:04.2357776+08:00"},{"catalog_id":"e2a3e381-beaf-41a1-ae35-53eac12640c1","title":"编码规范与性能优化","description":"coding-best-practices","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"c0913d8c-1c17-4764-9624-c2f356bedde7","gmt_create":"2025-08-26T23:18:49.1434767+08:00","gmt_modified":"2025-08-26T23:18:49.1493409+08:00"},{"catalog_id":"be444621-aee8-48fe-80a8-70612fceeeca","title":"监控与日志","description":"monitoring-logging","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"6a93a0c2-0e22-4aac-b5f8-af48c5df4f60","gmt_create":"2025-08-26T23:20:22.4661371+08:00","gmt_modified":"2025-08-26T23:20:22.4714294+08:00"},{"catalog_id":"21b4b5ed-9316-47fc-83d2-1017375d951f","title":"菜单(Menu)","description":"menu","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"e5fc9426-1569-40bb-b2bd-e1cefefe726f","gmt_create":"2025-08-26T23:22:17.7530811+08:00","gmt_modified":"2025-08-26T23:22:17.7583795+08:00"},{"catalog_id":"5a33b175-289f-4afe-96bd-ac6db90178c0","title":"性能调优","description":"performance-tuning","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"7d6f2d5f-0063-42fa-8b17-51c320a8726c","gmt_create":"2025-08-26T23:24:20.793877+08:00","gmt_modified":"2025-08-26T23:24:20.7987519+08:00"},{"catalog_id":"b855cf0a-08e5-4801-a00e-adfb1366fe60","title":"应用管理服务","description":"app-application-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"7efb18be-42a0-43c5-9071-793ae14345e0","gmt_create":"2025-08-26T23:26:44.709628+08:00","gmt_modified":"2025-08-26T23:26:44.7159489+08:00"},{"catalog_id":"8b6b6943-fb5f-4ee2-ac0a-f92d0b6128ae","title":"应用领域服务","description":"app-domain-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"d96544fc-e306-40df-bb89-0b75226e938b","gmt_create":"2025-08-26T23:28:36.9819109+08:00","gmt_modified":"2025-08-26T23:28:36.9871348+08:00"},{"catalog_id":"000e986d-7fe8-4380-9e19-31b9b9d2cc93","title":"JSON文件仓储实现","description":"json-file-repository","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"1b85f38e-97fc-4e44-aa30-989a85c2fbdb","gmt_create":"2025-08-26T23:30:45.651683+08:00","gmt_modified":"2025-08-26T23:30:45.65694+08:00"},{"catalog_id":"561256df-d655-4d28-9bcf-d05100719c92","title":"拖拽项视觉设计","description":"drag-item-visual-design","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"8b57fbd0-087e-4c09-ba79-5218e329a623","gmt_create":"2025-08-26T23:33:13.4979745+08:00","gmt_modified":"2025-08-26T23:33:13.5028246+08:00"},{"catalog_id":"c79a4d61-8b8c-4eb3-ad97-c40df1761a32","title":"页面管理服务","description":"page-application-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"7f4eb3e1-598d-4335-9db4-42b6f8884e26","gmt_create":"2025-08-26T23:35:42.5689452+08:00","gmt_modified":"2025-08-26T23:35:42.5751927+08:00"},{"catalog_id":"556efd3a-d209-43f0-b47e-da1f546c0a8a","title":"页面领域服务","description":"page-domain-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"25299769-7c0a-4c56-96c0-59a490d2bb25","gmt_create":"2025-08-26T23:38:04.5362161+08:00","gmt_modified":"2025-08-26T23:38:04.5419187+08:00"},{"catalog_id":"e0974464-a4b6-481c-8d66-bf594443d515","title":"Entity Framework Core仓储实现","description":"ef-core-repository","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"3d72c130-173f-45db-9c86-5e237fbcb4d0","gmt_create":"2025-08-26T23:40:38.2140527+08:00","gmt_modified":"2025-08-26T23:40:38.2198275+08:00"},{"catalog_id":"27bc9d6b-fba4-4279-9212-dad801474040","title":"页面属性设置界面","description":"page-setting-ui","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"60c78c83-1a21-46ae-b6ce-44a88fa601b8","gmt_create":"2025-08-26T23:43:18.3446694+08:00","gmt_modified":"2025-08-26T23:43:18.3494303+08:00"},{"catalog_id":"e1c12883-dce7-4ff3-a390-f443525a38d0","title":"菜单管理服务","description":"menu-application-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"9a174422-341b-49bf-9737-68c0f3b8bdb8","gmt_create":"2025-08-26T23:45:37.6265908+08:00","gmt_modified":"2025-08-26T23:45:37.6323565+08:00"},{"catalog_id":"74e284b2-0e9a-4572-ac84-c08bff07e383","title":"菜单领域服务","description":"menu-domain-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"364fde0e-2314-4e27-85ea-c6fbf237999c","gmt_create":"2025-08-26T23:47:53.4911568+08:00","gmt_modified":"2025-08-26T23:47:53.4958969+08:00"},{"catalog_id":"13b73928-f482-4f7f-99ab-1b3c3f8a8e75","title":"远程服务仓储实现","description":"remote-service-repository","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"92e0b8c5-3f1e-4dd8-b277-f452145fb591","gmt_create":"2025-08-26T23:49:38.7305398+08:00","gmt_modified":"2025-08-26T23:49:38.735291+08:00"},{"catalog_id":"e2934344-c534-4b98-910b-8dc2887cbcfd","title":"拖拽状态管理服务","description":"drag-drop-state-management","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"0f76c6a1-57f8-4f43-b402-c4937982fec9","gmt_create":"2025-08-26T23:52:12.7942083+08:00","gmt_modified":"2025-08-26T23:52:12.8003069+08:00"},{"catalog_id":"dc19c7a9-c262-4a86-a667-cf2206cde892","title":"数据源管理服务","description":"datasource-application-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"afc306cc-496e-4a79-885b-5e2a3ce5ce0c","gmt_create":"2025-08-26T23:54:07.4963986+08:00","gmt_modified":"2025-08-26T23:54:07.5011186+08:00"},{"catalog_id":"850cfe76-4777-4295-b053-5312874b8446","title":"数据源领域服务","description":"datasource-domain-service","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"5a86510c-4f6f-4b91-aa4f-cd2603b2d4c5","gmt_create":"2025-08-26T23:58:17.2088235+08:00","gmt_modified":"2025-08-26T23:58:17.2136035+08:00"},{"catalog_id":"9cc44fb0-22ae-4347-9095-e3dddff81e99","title":"仓储接口与依赖注入","description":"repository-interface-abstraction","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"ab5b8917-63b0-4ebd-b91b-0bedccd70d32","gmt_create":"2025-08-27T00:00:15.4430543+08:00","gmt_modified":"2025-08-27T00:00:15.4473135+08:00"},{"catalog_id":"00d767d8-e3ec-4706-ba62-8f445790c500","title":"DOM操作工具函数","description":"dom-utility-functions","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"9bd29bc7-2900-466b-a317-283f9ac41226","gmt_create":"2025-08-27T00:02:30.4455443+08:00","gmt_modified":"2025-08-27T00:02:30.4497993+08:00"},{"catalog_id":"edfa9ec9-83b3-47cf-a151-e4f404c340d0","title":"拖拽交互完整流程","description":"drag-drop-interaction-flow","extend":"{}","progress_status":"completed","repo_id":"fda9a566-a63e-4118-8074-0b326af71720","id":"d8e5d7df-fe8c-4f92-8832-8414126a1cea","gmt_create":"2025-08-27T21:42:52.9373521+08:00","gmt_modified":"2025-08-27T21:42:52.9420317+08:00"}],"wiki_overview":{"content":"\u003cblog\u003e\n# H.LowCode 项目综合分析\n\n## 1. 项目介绍\n\n### 项目目的\nH.LowCode 是一个基于 .NET 8.0 和 Blazor 实现的低代码实验性项目,旨在通过可视化设计和元数据驱动的方式快速构建应用程序。该项目支持多种页面类型(普通、表单、列表、报表)和多平台部署(Web、App、小程序)。\n\n### 核心目标\n- 提供可视化的设计引擎,允许用户通过拖拽方式构建应用界面\n- 实现元数据驱动的渲染引擎,将设计时的配置转化为运行时的应用\n- 支持多种数据源类型(API、SQL、组件、选项等),实现灵活的数据集成\n- 提供完整的应用生命周期管理,包括设计、开发、测试和发布\n\n### 目标受众\n- 企业级应用开发者\n- 需要快速原型开发的团队\n- 希望降低前端开发门槛的技术团队\n- 需要多平台统一开发方案的组织\n\n## 2. 技术架构\n\n### 组件分解\n项目采用模块化架构,主要分为以下几个核心部分:\n\n```mermaid\ngraph TD\n A[LowCode平台] --\u003e B[Common]\n A --\u003e C[DesignEngine]\n A --\u003e D[RenderEngine]\n A --\u003e E[Tools]\n \n B --\u003e B1[ComponentBase]\n B --\u003e B2[MetaSchema]\n B --\u003e B3[Entity]\n \n C --\u003e C1[Application]\n C --\u003e C2[Domain]\n C --\u003e C3[EntityFrameworkCore]\n C --\u003e C4[Repository]\n \n D --\u003e D1[Application]\n D --\u003e D2[Domain]\n D --\u003e D3[EntityFrameworkCore]\n D --\u003e D4[Repository]\n \n E --\u003e E1[DbMigrator]\n E --\u003e E2[MetaMigrator]\n```\n\n### 设计模式\n项目采用了典型的分层架构和领域驱动设计(DDD)模式:\n- **表现层**:Blazor 组件\n- **应用层**:Application Services\n- **领域层**:Domain Services 和 Aggregates\n- **基础设施层**:Repositories 和 Entity Framework Core\n\n### 系统关系\n```mermaid\nflowchart TD\n DesignEngine --\u003e|生成元数据| meta\n meta --\u003e|读取元数据| RenderEngine\n DbMigrator --\u003e|管理数据库迁移| Database\n DesignEngine --\u003e|持久化数据| Database\n RenderEngine --\u003e|读取数据| Database\n```\n\n### 数据流\n```mermaid\nflowchart LR\n User --\u003e|交互| RenderEngine\n RenderEngine --\u003e|请求数据| API\n API --\u003e|查询| Database\n Database --\u003e|返回结果| API\n API --\u003e|响应| RenderEngine\n RenderEngine --\u003e|更新UI| User\n```\n\n## 3. 实现细节\n\n### 主要入口点\n`Program.cs` 文件是应用程序的主要入口点,特别是在 `H.LowCode.DesignEngine.Host` 和 `H.LowCode.RenderEngine.Host` 项目中。\n\n```csharp\n// 示例:Host项目的Program.cs结构\npublic class Program\n{\n public static async Task Main(string[] args)\n {\n var builder = WebApplication.CreateBuilder(args);\n // 配置服务\n builder.Services.AddApplication\u003cDesignEngineHostModule\u003e();\n var app = builder.Build();\n // 配置管道\n app.InitializeApplication();\n await app.RunAsync();\n }\n}\n```\n\nSources:\n- [Program.cs](src/DesignEngine/H.LowCode.DesignEngine.Host/Program.cs)\n\n### 核心模块\n\n#### 元数据基础类\n`MetaSchemaBase` 类定义了所有元数据实体的基础属性,包括创建人、创建时间、修改人和修改时间。\n\n```csharp\npublic abstract class MetaSchemaBase : StateHasChangeSchema\n{\n [JsonPropertyName(\"cu\")]\n public string CreatedUser { get; set; }\n\n [JsonPropertyName(\"ct\")]\n public DateTime CreatedTime { get; set; }\n\n [JsonPropertyName(\"mu\")]\n public string ModifiedUser { get; set; }\n\n [JsonPropertyName(\"mt\")]\n public DateTime ModifiedTime { get; set; }\n}\n```\n\nSources:\n- [MetaSchemaBase.cs](src/Common/H.LowCode.MetaSchema/MetaSchemaBase.cs)\n\n#### 应用架构\n`AppSchemaBase` 类定义了应用的基本信息,包括名称、图标、描述、版本和支持的平台。\n\n```csharp\npublic abstract class AppSchemaBase : MetaSchemaBase\n{\n public string Id { get; set; }\n [JsonPropertyName(\"n\")]\n public string Name { get; set; }\n public string Icon { get; set; }\n [JsonPropertyName(\"pic\")]\n public string Picture { get; set; }\n [JsonPropertyName(\"desc\")]\n public string Description { get; set; }\n [JsonPropertyName(\"v\")]\n public string Version { get; set; }\n [JsonPropertyName(\"pub\")]\n public PublishStatusEnum PublishStatus { get; set; }\n [JsonPropertyName(\"platform\")]\n public SupportPlatformEnum[] SupportPlatforms { get; set; } = [0];\n}\n```\n\nSources:\n- [AppSchemaBase.cs](src/Common/H.LowCode.MetaSchema/AppSchemaBase.cs)\n\n#### 页面架构\n`PageSchemaBase` 类定义了页面的结构,包括页面类型、布局、数据源和事件处理。\n\n```csharp\npublic abstract class PageSchemaBase : MetaSchemaBase\n{\n [JsonPropertyName(\"aid\")]\n public string AppId { get; set; }\n [JsonPropertyName(\"id\")]\n public string Id { get; set; } = ShortIdGenerator.Generate();\n [JsonPropertyName(\"n\")]\n public string Name { get; set; }\n [JsonPropertyName(\"order\")]\n public int Order { get; set; }\n [JsonPropertyName(\"pt\")]\n public PageTypeEnum PageType { get; set; }\n [JsonPropertyName(\"pageprop\")]\n public PagePropertySchema PageProperty { get; set; } = new();\n [JsonPropertyName(\"ds\")]\n public PageDataSourceSchema DataSource { get; set; } = new();\n [JsonPropertyName(\"evs\")]\n public IList\u003cEventSchema\u003e Events { get; set; }\n}\n```\n\nSources:\n- [PageSchemaBase.cs](src/Common/H.LowCode.MetaSchema/PageSchemaBase.cs)\n\n#### 组件架构\n`ComponentSchemaBase` 类定义了组件的基本属性,包括ID、父级ID、标签、是否为容器组件等。\n\n```csharp\npublic abstract class ComponentSchemaBase : StateHasChangeSchema\n{\n [JsonPropertyName(\"id\")]\n public string Id { get; set; } = ShortIdGenerator.Generate();\n [JsonPropertyName(\"pid\")]\n public string ParentId { get; set; }\n [JsonPropertyName(\"n\")]\n public string Name { get; set; }\n [JsonPropertyName(\"lb\")]\n public string Label { get; set; }\n [JsonPropertyName(\"hlb\")]\n public bool IsHiddenLabel { get; set; }\n [JsonPropertyName(\"container\")]\n public bool IsContainer { get; set; }\n [JsonPropertyName(\"sptds\")]\n public bool IsSupportDataSource { get; set; }\n [JsonPropertyName(\"stl\")]\n public ComponentStyleSchema Style { get; set; } = new();\n [JsonPropertyName(\"evs\")]\n public IList\u003cEventSchema\u003e Events { get; set; }\n [JsonPropertyName(\"evcs\")]\n public IList\u003cEventConsumeSchema\u003e EventConsumes { get; set; }\n [JsonPropertyName(\"desc\")]\n public string Description { get; set; }\n}\n```\n\nSources:\n- [ComponentSchemaBase.cs](src/Common/H.LowCode.MetaSchema/ComponentSchemaBase.cs)\n\n### 配置方法\n项目使用标准的 .NET 配置系统,通过 `appsettings.json` 文件进行配置管理。\n\n```json\n{\n \"ConnectionStrings\": {\n \"Default\": \"Server=localhost;Database=LowCode;Trusted_Connection=true\"\n },\n \"MetaOption\": {\n \"MetaPath\": \"meta\"\n }\n}\n```\n\nSources:\n- [appsettings.json](src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json)\n\n### 外部依赖\n项目主要依赖以下外部库:\n- Microsoft.AspNetCore.Components (Blazor)\n- Volo.Abp.AspNetCore.Components\n- Entity Framework Core\n- System.Text.Json\n\n### 集成点\n设计引擎和渲染引擎通过元数据文件进行集成,这些文件存储在 `meta` 目录下。\n\n```mermaid\ngraph LR\n DesignEngine --\u003e|生成| meta/apps\n meta/apps --\u003e|读取| RenderEngine\n DesignEngine --\u003e|生成| meta/parts\n meta/parts --\u003e|读取| RenderEngine\n```\n\n## 4. 关键特性\n\n### 功能概述\n- **可视化设计**:提供拖拽式界面设计器\n- **多平台支持**:可生成适用于Web、App和小程序的应用\n- **多种数据源**:支持API、SQL、静态选项等多种数据源\n- **事件驱动**:支持标准事件和自定义脚本事件\n- **灵活布局**:支持1-4列的页面布局\n\n### 实现亮点\n\n#### 页面类型枚举\n```csharp\npublic enum PageTypeEnum\n{\n [Display(Name = \"普通\")]\n Normal = 0,\n [Display(Name = \"表单\")]\n Form = 1,\n [Display(Name = \"列表\")]\n Table = 2,\n [Display(Name = \"报表\")]\n Report = 5\n}\n```\n\nSources:\n- [PageTypeEnum.cs](src/Common/H.LowCode.MetaSchema/Enums/PageTypeEnum.cs)\n\n#### 支持平台枚举\n```csharp\npublic enum SupportPlatformEnum\n{\n [Display(Name = \"Web\")]\n Web,\n [Display(Name = \"App\")]\n Mobile,\n [Display(Name = \"小程序\")]\n WXMiniApp\n}\n```\n\nSources:\n- [SupportPlatformEnum.cs](src/Common/H.LowCode.MetaSchema/Enums/SupportPlatformEnum.cs)\n\n#### 事件处理\n```csharp\npublic class EventSchema\n{\n [JsonPropertyName(\"en\")]\n public string EventName { get; set; }\n [JsonPropertyName(\"eht\")]\n public EventTargetTypeEnum EventHandlerType { get; set; }\n [JsonPropertyName(\"etid\")]\n public string EventTargetId { get; set; }\n [JsonPropertyName(\"eta\")]\n public string EventTargetAction { get; set; }\n [JsonPropertyName(\"ecl\")]\n public EventCustomLanguageEnum EventCustomLanguage { get; set; }\n [JsonPropertyName(\"ecs\")]\n public string EventCustomScript { get; set; }\n public IDictionary\u003cstring, string\u003e EventArgs { get; set; }\n}\n```\n\nSources:\n- [EventSchema.cs](src/Common/H.LowCode.MetaSchema/PropertySchemas/EventSchema.cs)\n\n### 使用示例\n\n#### API数据源配置\n```csharp\npublic class APIDataSourceSchema\n{\n [JsonPropertyName(\"d\")]\n public string Domain { get; set; }\n [JsonPropertyName(\"p\")]\n public string Path { get; set; }\n [JsonPropertyName(\"m\")]\n public string Method { get; set; }\n [JsonPropertyName(\"qs\")]\n public IList\u003cAPIParamSchema\u003e Queries { get; set; } = [];\n [JsonPropertyName(\"bd\")]\n public APIBodySchema Body { get; set; } = new();\n [JsonPropertyName(\"hs\")]\n public IList\u003cAPIParamSchema\u003e Headers { get; set; } = [];\n}\n```\n\nSources:\n- [APIDataSourceSchema.cs](src/Common/H.LowCode.MetaSchema/DataSourceSchemas/APIDataSourceSchema.cs)\n\n#### SQL数据源配置\n```csharp\npublic class SQLDataSourceSchema\n{\n [JsonPropertyName(\"dt\")]\n public string DbType { get; set; }\n [JsonPropertyName(\"sql\")]\n public string Sql { get; set; }\n}\n```\n\nSources:\n- [SQLDataSourceSchema.cs](src/Common/H.LowCode.MetaSchema/DataSourceSchemas/SQLDataSourceSchema.cs)\n\n### 特性架构\n```mermaid\nstateDiagram-v2\n [*] --\u003e DesignMode\n DesignMode --\u003e PreviewMode: 预览\n PreviewMode --\u003e DesignMode: 返回编辑\n DesignMode --\u003e Publish: 发布\n Publish --\u003e RuntimeMode: 部署\n RuntimeMode --\u003e Maintenance: 维护\n Maintenance --\u003e DesignMode: 修改\n```\n\u003c/blog\u003e","gmt_create":"2025-08-22T22:16:04.5994693+08:00","gmt_modified":"2025-08-22T22:16:04.5994693+08:00","id":"a9c08a7b-45ea-4ac6-a578-222df2eafd33","repo_id":"fda9a566-a63e-4118-8074-0b326af71720"},"wiki_readme":{"content":"# H.LowCode\r\n\r\n### 介绍\r\n* 低代码实验性项目\r\n* 基于 .NET 8.0 + Blazor 实现\r\n\r\n### 分支规则\r\n* master: 最新稳定代码\r\n* release: 发布分支,基于 release 创建版本(当 release 分支足够稳定后,合并到 dev、master 分支)\r\n* dev: 开发分支(所有的 feature、hotfix 合并至 dev 分支,进行统一验证,并合并到 release 分支)\r\n* feature: 新特性分支(基于 dev 分支创建)\r\n* hotfix: 热修复分支(基于 dev 或 release 分支创建)\r\n\r\n### 版本规则\r\n* 正式版本: 遵循语义化版本 2.0 规范 (v0.0.1)\r\n* 非正式版本: v0.0.1-preview.1\r\n\r\n### 开发\r\n#### 生成迁移\r\n在 H.LowCode.DbMigrator 项目中执行以下命令,添加迁移文件:\r\ndotnet ef migrations add \u003cMigrationName\u003e\r\n\r\n#### 应用迁移\r\n运行 H.LowCode.DbMigrator","gmt_create":"2025-08-22T22:14:08.4989984+08:00","gmt_modified":"2025-08-22T22:14:08.4989984+08:00","id":"0dd60bec-5717-4274-bdf4-3d892bb0ed7f","repo_id":"fda9a566-a63e-4118-8074-0b326af71720"},"wiki_repo":{"id":"fda9a566-a63e-4118-8074-0b326af71720","name":"LowCode","progress_status":"completed","wiki_present_status":"COMPLETED","optimized_catalog":"\".\\n├── meta\\n│ ├── apps\\n│ │ ├── caseapp\\n│ │ │ ├── datasource\\n│ │ │ │ ├── iumn5yg5t.json\\n│ │ │ │ ├── qgzhc7w3z.json\\n│ │ │ │ ├── rsdjkqjz.json\\n│ │ │ │ └── s4sd6rvm.json\\n│ │ │ ├── menu\\n│ │ │ │ ├── 5omcgxevf.json\\n│ │ │ │ ├── atp4qtco.json\\n│ │ │ │ ├── bg8od2ni.json\\n│ │ │ │ ├── bu27d1nch.json\\n│ │ │ │ ├── bzowg2n5.json\\n│ │ │ │ ├── ckcbee4w.json\\n│ │ │ │ ├── eh02qoa2.json\\n│ │ │ │ ├── elw05oex.json\\n│ │ │ │ ├── g0nzkegz.json\\n│ │ │ │ ├── haqpjbqqn.json\\n│ │ │ │ ├── i7ftaaue.json\\n│ │ │ │ ├── jhx1bvst.json\\n│ │ │ │ ├── jyxsvsne.json\\n│ │ │ │ ├── kxfyxvds.json\\n│ │ │ │ ├── lamkwel7.json\\n│ │ │ │ ├── lbkmkoelq.json\\n│ │ │ │ ├── nty4afb4.json\\n│ │ │ │ ├── uxf9ol4ux.json\\n│ │ │ │ ├── uza6w4xk.json\\n│ │ │ │ ├── xjr5i6et.json\\n│ │ │ │ ├── xzk8d3pv.json\\n│ │ │ │ └── ylt35zso.json\\n│ │ │ ├── page\\n│ │ │ │ ├── 0lgu6xpop.json\\n│ │ │ │ ├── 2qceiqni.json\\n│ │ │ │ ├── 2qme5ln5e.json\\n│ │ │ │ ├── 4tnfvebp1.json\\n│ │ │ │ ├── 5kicsevr.json\\n│ │ │ │ ├── 7qa2yetz.json\\n│ │ │ │ ├── 85oldiqok.json\\n│ │ │ │ ├── fhumgxyk.json\\n│ │ │ │ ├── g0qcqxzd.json\\n│ │ │ │ ├── gndz2vecz.json\\n│ │ │ │ ├── huf12sk.json\\n│ │ │ │ ├── pl3juvaok.json\\n│ │ │ │ ├── rlswps5.json\\n│ │ │ │ ├── sf1duor2x.json\\n│ │ │ │ ├── uwz9o94b0.json\\n│ │ │ │ ├── xjvks1d3f.json\\n│ │ │ │ ├── xovrp6nz.json\\n│ │ │ │ └── ymb3bsw.json\\n│ │ │ └── caseapp.json\\n│ │ └── testapp\\n│ │ ├── menu\\n│ │ │ ├── b0owi2in.json\\n│ │ │ ├── d1hhoobmt.json\\n│ │ │ ├── w6nmv0hu.json\\n│ │ │ ├── wyzxwxf9d.json\\n│ │ │ └── yma35ysrl.json\\n│ │ ├── page\\n│ │ │ ├── ajzc8ywaa.json\\n│ │ │ ├── ehduqxwzm.json\\n│ │ │ ├── g0qcqxzd.json\\n│ │ │ ├── wjrxq0ft.json\\n│ │ │ └── xvdr8b6l.json\\n│ │ └── testapp.json\\n│ └── parts\\\\componentParts\\\\antdesign\\n│ ├── 52391a70.json\\n│ ├── 5icgyefr.json\\n│ ├── 6d997568.json\\n│ ├── 7bab5a19.json\\n│ ├── 85jlapqoc.json\\n│ ├── 8b0lapquf.json\\n│ ├── 9xulbbf5u.json\\n│ ├── antdesign.json\\n│ ├── csbjlezr.json\\n│ ├── elc02goef.json\\n│ ├── evuqdwzl.json\\n│ ├── f2b54b4c.json\\n│ ├── f63f79db.json\\n│ ├── fmiwu412.json\\n│ ├── jlcybdkg.json\\n│ ├── jmmybvkua.json\\n│ ├── nl9e6mko.json\\n│ ├── nwepem4i.json\\n│ ├── oikgmvkm.json\\n│ ├── ookcvyml.json\\n│ ├── sonvddk21.json\\n│ ├── vdcoqln1z.json\\n│ └── yo3v3smv.json\\n├── src\\n│ ├── Common\\n│ │ ├── H.LowCode.ComponentBase\\n│ │ │ ├── CascadingModels\\n│ │ │ │ ├── AppCascadingModel.cs\\n│ │ │ │ └── PageCascadingModel.cs\\n│ │ │ ├── LowCodeAppState.cs\\n│ │ │ ├── LowCodeComponentBase.cs\\n│ │ │ ├── LowCodeComponentBaseModule.cs\\n│ │ │ ├── LowCodeDynamicComponentBase.cs\\n│ │ │ ├── LowCodeLayoutComponentBase.cs\\n│ │ │ └── LowCodePageComponentBase.cs\\n│ │ ├── H.LowCode.Components.Defaults\\n│ │ │ └── LowCodeDefaultComponentModule.cs\\n│ │ ├── H.LowCode.Configuration\\\\Options\\n│ │ │ ├── MetaOption.cs\\n│ │ │ └── SiteOption.cs\\n│ │ ├── H.LowCode.Entity\\n│ │ │ ├── Base\\n│ │ │ │ ├── EntityBase.cs\\n│ │ │ │ └── FormEntity.cs\\n│ │ │ ├── EntityManager\\n│ │ │ │ ├── DynamicEntityInfo.cs\\n│ │ │ │ ├── EntityFactory.cs\\n│ │ │ │ ├── EntityProxyBuilder.cs\\n│ │ │ │ └── FieldTypeMapping.cs\\n│ │ │ └── Extensions\\n│ │ │ ├── EmitExtension.cs\\n│ │ │ └── ReflectionExtensions.cs\\n│ │ ├── H.LowCode.MetaSchema\\n│ │ │ ├── DataSourceSchemas\\n│ │ │ │ ├── APIDataSourceSchema.cs\\n│ │ │ │ ├── ComponentDataSourceSchema.cs\\n│ │ │ │ ├── OptionDataSourceSchema.cs\\n│ │ │ │ ├── PageDataSourceSchema.cs\\n│ │ │ │ ├── SQLDataSourceSchema.cs\\n│ │ │ │ └── TableFieldSchema.cs\\n│ │ │ ├── Enums\\n│ │ │ │ ├── ComponentDataSourceGroupTypeEnum.cs\\n│ │ │ │ ├── ComponentDataSourceTypeEnum.cs\\n│ │ │ │ ├── ComponentValueTypeEnum.cs\\n│ │ │ │ ├── EventTargetTypeEnum.cs\\n│ │ │ │ ├── PageDataSourceTypeEnum.cs\\n│ │ │ │ ├── PageTypeEnum.cs\\n│ │ │ │ ├── PublishStatusEnum.cs\\n│ │ │ │ └── SupportPlatformEnum.cs\\n│ │ │ ├── PropertySchemas\\n│ │ │ │ ├── TableSchemas\\n│ │ │ │ │ ├── TableButtonSchema.cs\\n│ │ │ │ │ ├── TableColumnSchema.cs\\n│ │ │ │ │ ├── TablePropertySchema.cs\\n│ │ │ │ │ └── TableSearchItemSchema.cs\\n│ │ │ │ ├── ComponentAttributeDefineSchemaBase.cs\\n│ │ │ │ ├── ComponentFragmentSchemaBase.cs\\n│ │ │ │ ├── ComponentStyleSchema.cs\\n│ │ │ │ ├── EventSchema.cs\\n│ │ │ │ ├── PagePropertySchema.cs\\n│ │ │ │ └── ValidationRuleSchema.cs\\n│ │ │ ├── Utils\\n│ │ │ │ └── ObjectMerger.cs\\n│ │ │ ├── AppSchemaBase.cs\\n│ │ │ ├── ComponentSchemaBase.cs\\n│ │ │ ├── DataSourceSchema.cs\\n│ │ │ ├── MenuSchema.cs\\n│ │ │ ├── MetaSchemaBase.cs\\n│ │ │ ├── PageSchemaBase.cs\\n│ │ │ └── StateHasChangeSchema.cs\\n│ │ ├── H.LowCode.MetaSchema.DesignEngine\\n│ │ │ ├── DataSourceSchemas\\n│ │ │ │ └── ComponentPartsDataSourceSchema.cs\\n│ │ │ ├── Enums\\n│ │ │ │ └── ComponentAttributeItemTypeEnum.cs\\n│ │ │ ├── PropertySchemas\\n│ │ │ │ ├── ComponentDesignStateSchema.cs\\n│ │ │ │ ├── ComponentPartsAttributeDefineGroupSchema.cs\\n│ │ │ │ ├── ComponentPartsAttributeDefineSchema.cs\\n│ │ │ │ ├── ComponentPartsEventSchema.cs\\n│ │ │ │ ├── ComponentPartsFragmentSchema.cs\\n│ │ │ │ └── ComponentPartsStyleSchema.cs\\n│ │ │ ├── AppPartsSchema.cs\\n│ │ │ ├── ComponentLibrarySchema.cs\\n│ │ │ ├── ComponentPartsSchema.cs\\n│ │ │ ├── PagePartsSchema.cs\\n│ │ │ └── PartsMetaSchemaBase.cs\\n│ │ └── H.LowCode.MetaSchema.RenderEngine\\n│ │ ├── DataSourceSchemas\\n│ │ │ └── ComponentDataSourceSchema.cs\\n│ │ ├── PropertySchemas\\n│ │ │ ├── ComponentAttributeDefineGroupSchema.cs\\n│ │ │ ├── ComponentAttributeDefineSchema.cs\\n│ │ │ └── ComponentFragmentSchema.cs\\n│ │ ├── AppSchema.cs\\n│ │ ├── ComponentSchema.cs\\n│ │ └── PageSchema.cs\\n│ ├── DesignEngine\\n│ │ ├── H.LowCode.DesignEngine\\n│ │ │ ├── ComponentPanel\\n│ │ │ │ └── DragItem.razor.css\\n│ │ │ ├── SettingPanel\\n│ │ │ │ └── PageSetting.razor.css\\n│ │ │ ├── wwwroot\\n│ │ │ │ └── designengine.css\\n│ │ │ └── DesignEngineModule.cs\\n│ │ ├── H.LowCode.DesignEngine.Application\\n│ │ │ ├── AppServices\\n│ │ │ │ ├── AppApplicationService.cs\\n│ │ │ │ ├── DataSourceAppService.cs\\n│ │ │ │ ├── MenuAppService.cs\\n│ │ │ │ └── PageAppService.cs\\n│ │ │ ├── PartsAppServices\\n│ │ │ │ ├── ComponentLibraryAppService.cs\\n│ │ │ │ └── ComponentPartsAppService.cs\\n│ │ │ └── DesignEngineApplicationModule.cs\\n│ │ ├── H.LowCode.DesignEngine.Application.Contracts\\n│ │ │ ├── AppServices\\n│ │ │ │ ├── IAppApplicationService.cs\\n│ │ │ │ ├── IDataSourceAppService.cs\\n│ │ │ │ ├── IMenuAppService.cs\\n│ │ │ │ └── IPageAppService.cs\\n│ │ │ ├── Inputs\\n│ │ │ │ └── DataSourceInput.cs\\n│ │ │ ├── PartsAppServices\\n│ │ │ │ ├── IComponentLibraryAppService.cs\\n│ │ │ │ └── IComponentPartsAppService.cs\\n│ │ │ └── DesignEngineApplicationContractsModule.cs\\n│ │ ├── H.LowCode.DesignEngine.Domain\\n│ │ │ ├── DataDomainServices\\n│ │ │ │ ├── FormDataDomainService.cs\\n│ │ │ │ ├── IFormDataDomainService.cs\\n│ │ │ │ ├── ITableDataDomainService.cs\\n│ │ │ │ └── TableDataDomainService.cs\\n│ │ │ ├── DataRepositories\\n│ │ │ │ ├── IFormDataRepository.cs\\n│ │ │ │ └── ITableDataRepository.cs\\n│ │ │ ├── MetaDomainServices\\n│ │ │ │ ├── AppDomainService.cs\\n│ │ │ │ ├── DataSourceDomainService.cs\\n│ │ │ │ ├── IAppDomainService.cs\\n│ │ │ │ ├── IDataSourceDomainService.cs\\n│ │ │ │ ├── IMenuDomainService.cs\\n│ │ │ │ ├── IMetaDomainService.cs\\n│ │ │ │ ├── IPageDomainService.cs\\n│ │ │ │ ├── MenuDomainService.cs\\n│ │ │ │ ├── MetaDomainService.cs\\n│ │ │ │ └── PageDomainService.cs\\n│ │ │ ├── MetaRepositories\\n│ │ │ │ ├── IAppRepository.cs\\n│ │ │ │ ├── IDataSourceRepository.cs\\n│ │ │ │ ├── IMenuRepository.cs\\n│ │ │ │ └── IPageRepository.cs\\n│ │ │ ├── PartsDomainServices\\n│ │ │ │ ├── ComponentLibraryDomainService.cs\\n│ │ │ │ ├── ComponentPartsDomainService.cs\\n│ │ │ │ ├── IComponentLibraryDomainService.cs\\n│ │ │ │ └── IComponentPartsDomainService.cs\\n│ │ │ ├── PartsRepositories\\n│ │ │ │ ├── IComponentLibraryRepository.cs\\n│ │ │ │ └── IComponentPartsRepository.cs\\n│ │ │ └── DesignEngineDomainModule.cs\\n│ │ ├── H.LowCode.DesignEngine.EntityFrameworkCore\\n│ │ │ ├── DataRepositories\\n│ │ │ │ ├── FormDataRepository.cs\\n│ │ │ │ └── TableDataRepository.cs\\n│ │ │ ├── EntityFrameworkCore\\n│ │ │ │ ├── Extensions\\n│ │ │ │ │ ├── CustomizeRelationalModelValidator.cs\\n│ │ │ │ │ ├── MapModelCacheKeyFactory.cs\\n│ │ │ │ │ ├── QueryWithNoLockDbCommandInterceptor.cs\\n│ │ │ │ │ └── ReadOnlySaveChangesInterceptor.cs\\n│ │ │ │ └── DesignEngineDbContext.cs\\n│ │ │ ├── EntityManager\\n│ │ │ │ └── EntityTypeManager.cs\\n│ │ │ └── DesignEngineEntityFrameworkCoreModule.cs\\n│ │ ├── H.LowCode.DesignEngine.Host\\n│ │ │ ├── Properties\\n│ │ │ │ └── launchSettings.json\\n│ │ │ ├── wwwroot\\n│ │ │ │ └── manifest.json\\n│ │ │ ├── DesignEngineHostModule.cs\\n│ │ │ ├── Program.cs\\n│ │ │ ├── appsettings.Development.json\\n│ │ │ └── appsettings.json\\n│ │ ├── H.LowCode.DesignEngine.Host.Client\\n│ │ │ ├── wwwroot\\n│ │ │ │ ├── appsettings.Development.json\\n│ │ │ │ └── appsettings.json\\n│ │ │ ├── DesignEngineHostClientModule.cs\\n│ │ │ ├── LowCodeGlobalVariables.cs\\n│ │ │ └── Program.cs\\n│ │ ├── H.LowCode.DesignEngine.Model\\n│ │ │ ├── Models\\n│ │ │ │ ├── AppListModel.cs\\n│ │ │ │ ├── ComponentListModel.cs\\n│ │ │ │ ├── DataSourceListModel.cs\\n│ │ │ │ └── PageListModel.cs\\n│ │ │ └── PartsModels\\n│ │ │ └── ComponentPartsListModel.cs\\n│ │ ├── H.LowCode.DesignEngine.Repository.JsonFile\\n│ │ │ ├── Base\\n│ │ │ │ ├── FileRepositoryBase.cs\\n│ │ │ │ └── PartsFileRepositoryBase.cs\\n│ │ │ ├── PartsRepositories\\n│ │ │ │ ├── ComponentLibraryRepository.cs\\n│ │ │ │ └── ComponentPartsRepository.cs\\n│ │ │ ├── Repositories\\n│ │ │ │ ├── AppFileRepository.cs\\n│ │ │ │ ├── DataSourceFileRepository.cs\\n│ │ │ │ ├── MenuFileRepository.cs\\n│ │ │ │ └── PageFileRepository.cs\\n│ │ │ └── DesignEngineJsonFileRepositoryModule.cs\\n│ │ ├── H.LowCode.DesignEngine.Repository.RemoteService\\n│ │ │ ├── Base\\n│ │ │ │ └── RemoteServiceRepositoryBase.cs\\n│ │ │ ├── Repositories\\n│ │ │ │ ├── AppRemoteServiceRepository.cs\\n│ │ │ │ ├── DataSourceRemoteServiceRepository.cs\\n│ │ │ │ ├── MenuRemoteServiceRepository.cs\\n│ │ │ │ └── PageRemoteServiceRepository.cs\\n│ │ │ └── DesignEngineRemoteServiceRepositoryModule.cs\\n│ │ ├── H.LowCode.DesignEngineBase\\n│ │ │ ├── DraggableComponents\\n│ │ │ │ ├── ComponentItem.razor.css\\n│ │ │ │ ├── DraggableContainer.razor.css\\n│ │ │ │ └── DraggableItem.razor.css\\n│ │ │ ├── Dtos\\n│ │ │ │ └── DragDropElementDimensions.cs\\n│ │ │ ├── Services\\n│ │ │ │ └── DragDropStateService.cs\\n│ │ │ ├── wwwroot\\\\js\\n│ │ │ │ └── elementUtils.js\\n│ │ │ ├── DesignEngineDynamicComponentBase.cs\\n│ │ │ ├── DesignEngineLowCodeComponentBase.cs\\n│ │ │ └── DesignEngineLowCodePageComponentBase.cs\\n│ │ ├── H.LowCode.MyApp\\n│ │ │ ├── wwwroot\\n│ │ │ │ └── myapp.css\\n│ │ │ └── MyAppModule.cs\\n│ │ ├── H.LowCode.PartsDesignEngine\\n│ │ │ ├── ComponentPanel\\n│ │ │ │ └── DragItem.razor.css\\n│ │ │ ├── Services\\n│ │ │ │ └── DragDropStateService.cs\\n│ │ │ ├── SettingPanel\\n│ │ │ │ └── PropertySetting.razor.css\\n│ │ │ ├── wwwroot\\n│ │ │ │ └── partsdesignengine.css\\n│ │ │ └── PartsDesignEngineModule.cs\\n│ │ └── H.LowCode.Workbench\\n│ │ └── LowCodeWorkbenchModule.cs\\n│ ├── RenderEngine\\n│ │ ├── H.LowCode.RenderEngine\\n│ │ │ └── RenderEngineModule.cs\\n│ │ ├── H.LowCode.RenderEngine.Abstraction\\n│ │ │ ├── RenderEngineDynamicComponentBase.cs\\n│ │ │ ├── RenderEngineLowCodeComponentBase.cs\\n│ │ │ └── ThemePartLayoutBase.cs\\n│ │ ├── H.LowCode.RenderEngine.Application\\n│ │ │ ├── DataAppServices\\n│ │ │ │ ├── FormDataAppService.cs\\n│ │ │ │ └── TableDataAppService.cs\\n│ │ │ ├── MapperProfiles\\n│ │ │ │ └── LowCodeAutoMapperProfile.cs\\n│ │ │ ├── RenderAppServices\\n│ │ │ │ └── MetaAppService.cs\\n│ │ │ └── RenderEngineApplicationModule.cs\\n│ │ ├── H.LowCode.RenderEngine.Application.Contracts\\n│ │ │ ├── DataAppServices\\n│ │ │ │ ├── IFormDataAppService.cs\\n│ │ │ │ └── ITableDataAppService.cs\\n│ │ │ ├── DataDTOs\\n│ │ │ │ ├── DataDTOBase.cs\\n│ │ │ │ ├── FormCreateOrUpdateDTO.cs\\n│ │ │ │ ├── FormDataDTO.cs\\n│ │ │ │ ├── TableGetListInput.cs\\n│ │ │ │ └── TableGetListOutput.cs\\n│ │ │ ├── RenderAppServices\\n│ │ │ │ └── IMetaAppService.cs\\n│ │ │ └── RenderEngineApplicationContractsModule.cs\\n│ │ ├── H.LowCode.RenderEngine.Domain\\n│ │ │ ├── DataDomainServices\\n│ │ │ │ ├── FormDataDomainService.cs\\n│ │ │ │ ├── IFormDataDomainService.cs\\n│ │ │ │ ├── ITableDataDomainService.cs\\n│ │ │ │ └── TableDataDomainService.cs\\n│ │ │ ├── DataRepositories\\n│ │ │ │ ├── IFormDataRepository.cs\\n│ │ │ │ └── ITableDataRepository.cs\\n│ │ │ ├── MetaDomainServices\\n│ │ │ │ ├── AppDomainService.cs\\n│ │ │ │ ├── DataSourceDomainService.cs\\n│ │ │ │ ├── IAppDomainService.cs\\n│ │ │ │ ├── IDataSourceDomainService.cs\\n│ │ │ │ ├── IMenuDomainService.cs\\n│ │ │ │ ├── IMetaDomainService.cs\\n│ │ │ │ ├── IPageDomainService.cs\\n│ │ │ │ ├── MenuDomainService.cs\\n│ │ │ │ ├── MetaDomainService.cs\\n│ │ │ │ └── PageDomainService.cs\\n│ │ │ ├── MetaRepositories\\n│ │ │ │ ├── IAppRepository.cs\\n│ │ │ │ ├── IDataSourceRepository.cs\\n│ │ │ │ ├── IMenuRepository.cs\\n│ │ │ │ └── IPageRepository.cs\\n│ │ │ └── RenderEngineDomainModule.cs\\n│ │ ├── H.LowCode.RenderEngine.EntityFrameworkCore\\n│ │ │ ├── DataRepositories\\n│ │ │ │ ├── FormDataRepository.cs\\n│ │ │ │ └── TableDataRepository.cs\\n│ │ │ ├── EntityFrameworkCore\\n│ │ │ │ ├── Extensions\\n│ │ │ │ │ ├── CustomizeRelationalModelValidator.cs\\n│ │ │ │ │ ├── MapModelCacheKeyFactory.cs\\n│ │ │ │ │ ├── QueryWithNoLockDbCommandInterceptor.cs\\n│ │ │ │ │ └── ReadOnlySaveChangesInterceptor.cs\\n│ │ │ │ └── RenderEngineDbContext.cs\\n│ │ │ ├── EntityManager\\n│ │ │ │ └── EntityTypeManager.cs\\n│ │ │ └── RenderEngineEntityFrameworkCoreModule.cs\\n│ │ ├── H.LowCode.RenderEngine.Host\\n│ │ │ ├── Properties\\n│ │ │ │ └── launchSettings.json\\n│ │ │ ├── wwwroot\\n│ │ │ │ └── manifest.json\\n│ │ │ ├── Program.cs\\n│ │ │ ├── RenderEngineHostModule.cs\\n│ │ │ ├── appsettings.Development.json\\n│ │ │ └── appsettings.json\\n│ │ ├── H.LowCode.RenderEngine.Host.Client\\n│ │ │ ├── wwwroot\\n│ │ │ │ ├── appsettings.Development.json\\n│ │ │ │ └── appsettings.json\\n│ │ │ ├── LowCodeGlobalVariables.cs\\n│ │ │ ├── Program.cs\\n│ │ │ └── RenderEngineHostClientModule.cs\\n│ │ ├── H.LowCode.RenderEngine.Repository.JsonFile\\n│ │ │ ├── Base\\n│ │ │ │ └── FileRepositoryBase.cs\\n│ │ │ ├── Repositories\\n│ │ │ │ ├── AppFileRepository.cs\\n│ │ │ │ ├── DataSourceFileRepository.cs\\n│ │ │ │ ├── MenuFileRepository.cs\\n│ │ │ │ └── PageFileRepository.cs\\n│ │ │ └── RenderEngineJsonFileRepositoryModule.cs\\n│ │ ├── H.LowCode.RenderEngine.Repository.RemoteService\\n│ │ │ ├── Base\\n│ │ │ │ └── RemoteServiceRepositoryBase.cs\\n│ │ │ ├── Repositories\\n│ │ │ │ ├── AppRemoteServiceRepository.cs\\n│ │ │ │ ├── DataSourceRemoteServiceRepository.cs\\n│ │ │ │ ├── MenuRemoteServiceRepository.cs\\n│ │ │ │ └── PageRemoteServiceRepository.cs\\n│ │ │ └── RenderEngineRemoteServiceRepositoryModule.cs\\n│ │ └── H.LowCode.Themes.AntBlazor\\n│ │ ├── ComponentRender\\n│ │ │ ├── ComponentRender.razor.css\\n│ │ │ ├── ContainerComponentRender.razor.css\\n│ │ │ ├── FormComponentRender.razor.css\\n│ │ │ └── FormContainerComponentRender.razor.css\\n│ │ ├── wwwroot\\n│ │ │ └── renderengine.css\\n│ │ └── AntBlazorThemeModule.cs\\n│ └── Tools\\n│ ├── H.LowCode.DbMigrator\\n│ │ ├── MigrationGenerator\\n│ │ │ └── MigratorDbContextFactory.cs\\n│ │ ├── MigrationServices\\n│ │ │ ├── EntityFrameworkCoreDbSchemaMigrator.cs\\n│ │ │ ├── IDbSchemaMigrator.cs\\n│ │ │ └── MigratorDbContext.cs\\n│ │ ├── Migrations\\n│ │ │ ├── 20250225020741_Initial.Designer.cs\\n│ │ │ ├── 20250225020741_Initial.cs\\n│ │ │ └── MigratorDbContextModelSnapshot.cs\\n│ │ ├── DbMigrationService.cs\\n│ │ ├── HostedService.cs\\n│ │ ├── LowCodeDbMigratorModule.cs\\n│ │ ├── Program.cs\\n│ │ ├── appsettings.json\\n│ │ └── appsettings.serilog.json\\n│ └── H.LowCode.MetaMigrator\\n│ └── Program.cs\\n├── README.md\\n├── TODO.md\\n└── global.json\\n\"","current_document_structure":"WikiEncrypted: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","catalogue_think_content":"WikiEncrypted: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","recovery_checkpoint":"wiki_generation_completed","last_commit_id":"2dbaaaee44fc6e37de957f2b29a903837e55fd2c","last_commit_update":"2025-08-20T00:58:05+08:00","gmt_create":"2025-08-22T22:14:07.9517371+08:00","gmt_modified":"2025-09-21T00:59:59.5505774+08:00","extend_info":"{\"language\":\"zh\",\"active\":true,\"branch\":\"dev\",\"shareStatus\":\"\",\"server_error_code\":\"\",\"cosy_version\":\"\"}"}} \ No newline at end of file diff --git a/README.md b/README.md index bfd3cf17b50b6839d99067dad8726f9a7de0cddb..4703299e44135d1d0864dcf8a32153799cdb86a2 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,11 @@ # H.LowCode ### 介绍 -* 低代码实验性项目,基于 .NET + Blazor 实现 +* 低代码实验性(功能仅达到demo级别,存在破坏性变更)项目,基于 .NET + Blazor 实现 ### 分支规则 * master: 最新稳定代码 -* release: 发布分支,基于 release 创建版本(当 release 分支足够稳定后,合并到 dev、master 分支) -* dev: 开发分支(所有的 feature、hotfix 合并至 dev 分支,进行统一验证,并合并到 release 分支) -* feature: 新特性分支(基于 dev 分支创建) -* hotfix: 热修复分支(基于 dev 或 release 分支创建) - -### 版本规则 -* 正式版本: 遵循语义化版本 2.0 规范 (v0.0.1) -* 非正式版本: v0.0.1-preview.1 +* dev: 开发分支 ### 开发 #### 生成迁移 diff --git a/meta/apps/attendance/page/0lsuhfpon.json b/meta/apps/attendance/page/0lsuhfpon.json index 7ad2e9d500e50694ddf2f0176c5bca6efe576ff1..a40c6aed8be7cde7d25315409d967261e93db224 100644 --- a/meta/apps/attendance/page/0lsuhfpon.json +++ b/meta/apps/attendance/page/0lsuhfpon.json @@ -1 +1 @@ -{"comps":[{"libid":"antdesign","compid":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"leave_request","dsv":"{\"tcols\":[{\"id\":\"f_id\",\"n\":\"f_id\",\"t\":\"id\",\"pk\":true},{\"id\":\"f_userid\",\"n\":\"f_userid\",\"t\":\"用户\"},{\"id\":\"f_deptid\",\"n\":\"f_deptid\",\"t\":\"部门\"},{\"id\":\"f_leave_type\",\"n\":\"f_leave_type\",\"t\":\"请假类型\"},{\"id\":\"f_start_time\",\"n\":\"f_start_time\",\"t\":\"开始时间\"},{\"id\":\"f_end_time\",\"n\":\"f_end_time\"},{\"id\":\"f_days\",\"n\":\"f_days\"},{\"id\":\"f_status\",\"n\":\"f_status\"},{\"id\":\"f_create_time\",\"n\":\"f_create_time\"}],\"searchs\":[{},{},{}],\"tbtns\":[{\"id\":\"create_leave\",\"n\":\"create\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"t7g1bfcyt\",\"eta\":\"14\"}]},{\"id\":\"batch_approve\",\"n\":\"batchApprove\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"view_detail\",\"n\":\"view\",\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"t7g1bfcyt\",\"eta\":\"14\"}],\"rowparams\":{\"id\":\"f_id\"}},{\"id\":\"approve\",\"n\":\"approve\",\"order\":2,\"sptevs\":[\"OnClick\"]},{\"id\":\"delete\",\"n\":\"delete\",\"order\":3,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"edit\",\"n\":\"edit\",\"order\":4,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]},{\"id\":\"save\",\"n\":\"save\",\"order\":5,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":30}]},{\"id\":\"cancel\",\"n\":\"cancel\",\"order\":6,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":40}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-11-17T10:00:00Z","id":"leave_table","pid":"root","n":"leave_table","lb":"请假申请列表","sptds":true,"stl":{"itemw":24,"itemh":400,"labelw":180},"valrules":[],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"0lsuhfpon","n":"请假申请管理","order":4,"pt":2,"pageprop":{"playout":2,"ds":{"dst":1}},"ds":{"dst":1},"mt":"2025-11-23T12:48:58.4631549Z"} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"leave_request","dsv":"{\"tcols\":[{\"id\":\"f_id\",\"n\":\"f_id\",\"t\":\"id\",\"pk\":true},{\"id\":\"f_userid\",\"n\":\"f_userid\",\"t\":\"用户\"},{\"id\":\"f_deptid\",\"n\":\"f_deptid\",\"t\":\"部门\"},{\"id\":\"f_leave_type\",\"n\":\"f_leave_type\",\"t\":\"请假类型\"},{\"id\":\"f_start_time\",\"n\":\"f_start_time\",\"t\":\"开始时间\"},{\"id\":\"f_end_time\",\"n\":\"f_end_time\"},{\"id\":\"f_days\",\"n\":\"f_days\"},{\"id\":\"f_status\",\"n\":\"f_status\"},{\"id\":\"f_create_time\",\"n\":\"f_create_time\"}],\"searchs\":[{},{},{}],\"tbtns\":[{\"id\":\"create_leave\",\"n\":\"create\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"t7g1bfcyt\",\"eta\":\"14\"}]},{\"id\":\"batch_approve\",\"n\":\"batchApprove\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"view_detail\",\"n\":\"view\",\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"t7g1bfcyt\",\"eta\":\"14\"}],\"rowparams\":{\"id\":\"f_id\"}},{\"id\":\"approve\",\"n\":\"approve\",\"order\":2,\"sptevs\":[\"OnClick\"]},{\"id\":\"delete\",\"n\":\"delete\",\"order\":3,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"edit\",\"n\":\"edit\",\"order\":4,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]},{\"id\":\"save\",\"n\":\"save\",\"order\":5,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":30}]},{\"id\":\"cancel\",\"n\":\"cancel\",\"order\":6,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":40}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-11-17T10:00:00Z","id":"leave_table","pid":"root","n":"leave_table","lb":"请假申请列表","hlb":true,"sptds":true,"stl":{"itemw":24,"itemh":400,"labelw":180},"valrules":[],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"0lsuhfpon","n":"请假申请管理","order":4,"pt":2,"pageprop":{"playout":2,"ds":{"dst":1}},"ds":{"dst":1},"mt":"2025-12-09T15:31:54.9888686Z"} \ No newline at end of file diff --git a/meta/apps/attendance/page/ehougawr.json b/meta/apps/attendance/page/ehougawr.json index b606f54505abf16dd535b11fef0812c7d8e3c460..33e80e5bf90d8d75ad08a664ae08ee022f604745 100644 --- a/meta/apps/attendance/page/ehougawr.json +++ b/meta/apps/attendance/page/ehougawr.json @@ -1,12 +1,13 @@ -{ +{ "comps": [ { "libid": "antdesign", - "compid": "datepicker", + "partsId": "datepicker", "ct": 1, "frag": { - "t": "AntDesign.DatePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign", - "valt": "System.Nullable\u00601[System.DateTime]", + "t": "AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", "attrs": [] }, "ds": { @@ -36,10 +37,10 @@ { "id": "f_overtime_date_required", "cid": "f_overtime_date", + "enabled": true, "type": 1, "errmsg": "加班日期不能为空", "trigger": 1, - "enabled": true, "order": 1 } ], @@ -47,11 +48,12 @@ }, { "libid": "antdesign", - "compid": "timepicker", + "partsId": "timepicker", "ct": 1, "frag": { - "t": "AntDesign.TimePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign", - "valt": "System.Nullable\u00601[System.DateTime]", + "t": "AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", "attrs": [] }, "ds": { @@ -77,10 +79,10 @@ { "id": "f_start_time_required", "cid": "f_start_time", + "enabled": true, "type": 1, "errmsg": "开始时间不能为空", "trigger": 1, - "enabled": true, "order": 1 } ], @@ -88,11 +90,12 @@ }, { "libid": "antdesign", - "compid": "timepicker", + "partsId": "timepicker", "ct": 1, "frag": { - "t": "AntDesign.TimePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign", - "valt": "System.Nullable\u00601[System.DateTime]", + "t": "AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", "attrs": [] }, "ds": { @@ -118,10 +121,10 @@ { "id": "f_end_time_required", "cid": "f_end_time", + "enabled": true, "type": 1, "errmsg": "结束时间不能为空", "trigger": 1, - "enabled": true, "order": 1 } ], @@ -129,10 +132,11 @@ }, { "libid": "antdesign", - "compid": "inputnumber", + "partsId": "inputnumber", "ct": 1, "frag": { - "t": "AntDesign.InputNumber\u00601[System.Int32], AntDesign", + "t": "AntDesign.InputNumber`1[System.Int32], AntDesign", + "childs": [], "valt": "System.Int32", "attrs": [] }, @@ -159,84 +163,31 @@ { "id": "f_hours_required", "cid": "f_hours", + "enabled": true, "type": 1, "errmsg": "加班小时数不能为空", "trigger": 1, - "enabled": true, "order": 1 }, { "id": "f_hours_min", "cid": "f_hours", - "type": 3, - "errmsg": "加班小时数必须大于0", - "trigger": 1, "enabled": true, - "order": 2, - "rulev": "1" - } - ], - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "select", - "ct": 1, - "frag": { - "t": "AntDesign.Select\u00602[[System.String],[System.String]], antdesign", - "valt": "System.String", - "attrs": [] - }, - "ds": { - "dsgt": 1, - "dsid": "overtime_type_options" - }, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 50, - "pub": 1, - "mt": "2025-11-17T10:00:00Z", - "id": "f_overtime_type", - "pid": "root", - "n": "f_overtime_type", - "lb": "加班类型", - "sptds": true, - "stl": { - "itemw": 8, - "itemh": 85, - "labelw": 120 - }, - "valrules": [ - { - "id": "f_reason_required", - "cid": "f_reason", - "type": 1, - "errmsg": "加班原因不能为空", - "trigger": 1, - "enabled": true, - "order": 1 - }, - { - "id": "f_reason_min", - "cid": "f_reason", "type": 3, - "errmsg": "加班原因不能少于5个字符", + "errmsg": "加班小时数必须大于0", "trigger": 1, - "enabled": true, - "order": 2, - "rulev": "5" + "order": 2 } ], "v": "0.0.1" }, { "libid": "antdesign", - "compid": "textarea", + "partsId": "textarea", "ct": 1, "frag": { "t": "AntDesign.TextArea, AntDesign", + "childs": [], "valt": "System.String", "attrs": [] }, @@ -253,7 +204,7 @@ "desc": "", "dftval": 4, "attrn": "Rows", - "attrt": "System.Int32", + "attrt": "System.UInt32", "attrv": 4 }, { @@ -283,151 +234,26 @@ "itemh": 120, "labelw": 120 }, - "valrules": [], - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "button", - "ct": 1, - "frag": { - "t": "AntDesign.Button, AntDesign", - "valt": "System.String", - "attrs": [ - { - "attrn": "Text", - "attrt": "System.String" - }, - { - "attrn": "Type", - "attrt": "System.String" - } - ] - }, - "ds": {}, - "attrdefgroups": [ - { - "gn": "基础属性", - "attrdefs": [ - { - "disn": "按钮文字", - "pt": 1, - "desc": "按钮显示的文本内容", - "dftval": "按钮", - "attrn": "Text", - "attrt": "System.String", - "attrv": "提交申请" - }, - { - "disn": "按钮类型", - "pt": 3, - "desc": "按钮的样式类型", - "dftval": "default", - "attrn": "Type", - "attrt": "System.String", - "attrv": "primary" - } - ] - } - ], - "childs": [], - "evdefs": [ - { - "en": "OnClick", - "disn": "点击事件", - "desc": "按钮被点击时触发的事件" - } - ], - "stydefs": [], - "order": 70, - "pub": 1, - "mt": "2025-11-17T10:00:00Z", - "id": "submit_btn", - "pid": "root", - "n": "submit_btn", - "lb": "提交按钮", - "stl": { - "itemw": 4, - "itemh": 50, - "labelw": 180 - }, - "evs": [ - { - "en": "OnClick", - "eht": 10, - "edat": 10 - } - ], - "valrules": [], - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "button", - "ct": 1, - "frag": { - "t": "AntDesign.Button, AntDesign", - "valt": "System.String", - "attrs": [ - { - "attrn": "Text", - "attrt": "System.String" - }, - { - "attrn": "Type", - "attrt": "System.String" - } - ] - }, - "ds": {}, - "attrdefgroups": [ + "valrules": [ { - "gn": "基础属性", - "attrdefs": [ - { - "disn": "按钮文字", - "pt": 1, - "desc": "按钮显示的文本内容", - "dftval": "按钮", - "attrn": "Text", - "attrt": "System.String", - "attrv": "重置" - }, - { - "disn": "按钮类型", - "pt": 3, - "desc": "按钮的样式类型", - "dftval": "default", - "attrn": "Type", - "attrt": "System.String", - "attrv": "default" - } - ] - } - ], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 80, - "pub": 1, - "mt": "2025-11-17T10:00:00Z", - "id": "reset_btn", - "pid": "root", - "n": "reset_btn", - "lb": "重置按钮", - "stl": { - "itemw": 4, - "itemh": 50, - "labelw": 180 - }, - "evs": [ + "id": "f_reason_required", + "cid": "f_reason", + "enabled": true, + "type": 1, + "errmsg": "加班原因不能为空", + "trigger": 1, + "order": 1 + }, { - "en": "OnClick", - "eht": 10, - "edat": 20 + "id": "f_reason_min", + "cid": "f_reason", + "enabled": true, + "type": 3, + "errmsg": "加班原因不能少于5个字符", + "trigger": 1, + "order": 2 } ], - "valrules": [], "v": "0.0.1" } ], @@ -446,11 +272,10 @@ } }, "ds": { - "dsgt": 1, "dst": 1, "dsid": "overtime_request", "dsn": "加班申请", "dsv": "tb_overtime_request" }, - "mt": "2025-11-23T10:52:08.2361057Z" + "mt": "2025-12-09T15:07:48.0166044Z" } \ No newline at end of file diff --git a/meta/apps/attendance/page/gcfqc7xzc.json b/meta/apps/attendance/page/gcfqc7xzc.json index 1b6cb37016c4b20fe54665f30b22444fb91823b2..5f4ff0a2edae5706e2bde558dfdaf700e8a014dc 100644 --- a/meta/apps/attendance/page/gcfqc7xzc.json +++ b/meta/apps/attendance/page/gcfqc7xzc.json @@ -1 +1 @@ -{"comps":[{"libid":"antdesign","compid":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"wmtnh0uv","dsv":"{\"tcols\":[{\"id\":\"f_id\",\"n\":\"f_id\",\"t\":\"id\",\"pk\":true},{\"id\":\"f_userid\",\"n\":\"f_userid\",\"t\":\"用户\"},{\"id\":\"f_deptid\",\"n\":\"f_deptid\",\"t\":\"部门\"},{\"id\":\"f_checktime\",\"n\":\"f_checktime\",\"t\":\"打卡时间\"},{\"id\":\"f_checklocation\",\"n\":\"f_checklocation\",\"t\":\"打卡地点\"},{\"id\":\"f_checktype\",\"n\":\"f_checktype\",\"t\":\"打卡类型\"}],\"searchs\":[{},{},{},{}],\"tbtns\":[{\"id\":\"manual_checkin\",\"n\":\"manualCheckin\",\"bt\":1,\"sptevs\":[\"OnClick\"]},{\"id\":\"export_data\",\"n\":\"export\",\"sptevs\":[\"OnClick\"]},{\"id\":\"batch_delete\",\"n\":\"deleteSelections\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"view_detail\",\"n\":\"view\",\"order\":1,\"sptevs\":[\"OnClick\"]},{\"id\":\"edit_record\",\"n\":\"edit\",\"order\":2,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]},{\"id\":\"delete_record\",\"n\":\"delete\",\"order\":3,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"save_record\",\"n\":\"save\",\"order\":4,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":30}]},{\"id\":\"cancel_edit\",\"n\":\"cancel\",\"order\":5,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":40}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-11-17T10:00:00Z","id":"checkin_table","pid":"root","n":"checkin_table","lb":"打卡记录列表","sptds":true,"stl":{"itemw":24,"itemh":450,"labelw":180},"valrules":[],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"gcfqc7xzc","n":"打卡管理","order":1,"pt":2,"pageprop":{"playout":2,"ds":{"dst":1}},"ds":{"dst":1},"mt":"2025-11-23T12:30:13.3927186Z"} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"wmtnh0uv","dsv":"{\"tcols\":[{\"id\":\"f_id\",\"n\":\"f_id\",\"t\":\"id\",\"pk\":true},{\"id\":\"f_userid\",\"n\":\"f_userid\",\"t\":\"用户\"},{\"id\":\"f_deptid\",\"n\":\"f_deptid\",\"t\":\"部门\"},{\"id\":\"f_checktime\",\"n\":\"f_checktime\",\"t\":\"打卡时间\"},{\"id\":\"f_checklocation\",\"n\":\"f_checklocation\",\"t\":\"打卡地点\"},{\"id\":\"f_checktype\",\"n\":\"f_checktype\",\"t\":\"打卡类型\"}],\"searchs\":[{},{},{},{}],\"tbtns\":[{\"id\":\"manual_checkin\",\"n\":\"manualCheckin\",\"t\":\"新增\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"nkeppmji\",\"eta\":\"14\",\"eventArgs\":{},\"rowparams\":{}}]},{\"id\":\"export_data\",\"n\":\"export\",\"t\":\"删除选中\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"view_detail\",\"n\":\"view\",\"t\":\"查看\",\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\"}]},{\"id\":\"edit_record\",\"n\":\"edit\",\"t\":\"编辑\",\"order\":2,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]},{\"id\":\"delete_record\",\"n\":\"delete\",\"t\":\"删除\",\"order\":3,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-11-17T10:00:00Z","id":"checkin_table","pid":"root","n":"checkin_table","lb":"打卡记录列表","hlb":true,"sptds":true,"stl":{"itemw":24,"itemh":450,"labelw":180},"valrules":[],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"gcfqc7xzc","n":"打卡管理","order":1,"pt":2,"pageprop":{"playout":2,"ds":{"dst":1}},"ds":{"dst":1},"mt":"2025-12-09T15:31:47.6146739Z"} \ No newline at end of file diff --git a/meta/apps/attendance/page/nkeppmji.json b/meta/apps/attendance/page/nkeppmji.json index ac60cd9d29b6922dd6eaa6214b40691f0a28edcc..db988cf74293a8976a1b4666cdb17b95f876dc36 100644 --- a/meta/apps/attendance/page/nkeppmji.json +++ b/meta/apps/attendance/page/nkeppmji.json @@ -1 +1 @@ -{"comps":[{"libid":"antdesign","compid":"input","ct":1,"frag":{"t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":20},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-02-24T15:36:15.8037414Z","id":"i7ittugb","pid":"root","n":"f_userid","lb":"打卡人","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_userid_required","cid":"i7ittugb","enabled":true,"type":1,"errmsg":"打卡人不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","compid":"select","ct":1,"frag":{"t":"AntDesign.Select`2[[System.String],[System.String]], antdesign","childs":[],"valt":"System.String","attrs":[]},"ds":{"dsgt":1,"dsid":"department_options"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":17,"pub":1,"mt":"2025-03-22T15:55:39.4807842Z","id":"be07hunku","pid":"root","n":"f_deptid","lb":"选择部门","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checktime_required","cid":"tw1qgcjp","type":1,"errmsg":"打卡时间不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","compid":"timepicker","ct":1,"frag":{"t":"AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign","childs":[],"valt":"System.Nullable`1[System.DateTime]","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":16,"pub":1,"mt":"2025-03-05T15:31:24.9654966Z","id":"tw1qgcjp","pid":"root","n":"f_checktime","lb":"打卡时间","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checktime_required","cid":"tw1qgcjp","enabled":true,"type":1,"errmsg":"打卡时间不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","compid":"input","ct":1,"frag":{"t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":50},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-02-24T15:36:15.8037414Z","id":"so4v7kba","pid":"root","n":"f_checklocation","lb":"打卡地点","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checklocation_required","cid":"so4v7kba","enabled":true,"type":1,"errmsg":"打卡地点不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","compid":"radio","ct":1,"frag":{"t":"AntDesign.RadioGroup`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsfrag":{"t":"AntDesign.Radio`1[System.String], AntDesign","childs":[],"attrs":[{"attrn":"Value"}]},"dsgt":1,"dst":8,"fxopds":[{"l":"上班打卡","v":"0"},{"l":"下班打卡","v":"1"}]},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":13,"pub":1,"mt":"2025-03-23T07:26:31.4273273Z","id":"wlxwhf96","pid":"root","n":"f_checktype","lb":"打卡选项","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checktype_required","cid":"wlxwhf96","enabled":true,"type":1,"errmsg":"请选择打卡类型","trigger":1,"order":1}],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"nkeppmji","n":"打卡","pt":1,"pageprop":{"playout":1,"ds":{}},"ds":{"dst":1,"dsid":"wmtnh0uv","dsn":"打卡","dsv":"tb_check"},"mt":"2025-11-29T16:51:31.7913039Z"} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":20},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-02-24T15:36:15.8037414Z","id":"i7ittugb","pid":"root","n":"f_userid","lb":"打卡人","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_userid_required","cid":"i7ittugb","enabled":true,"type":1,"errmsg":"打卡人不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","partsId":"select","ct":1,"frag":{"t":"AntDesign.Select`2[[System.String],[System.String]], antdesign","childs":[],"valt":"System.String","attrs":[]},"ds":{"dsgt":1,"dsid":"department_options"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":17,"pub":1,"mt":"2025-03-22T15:55:39.4807842Z","id":"be07hunku","pid":"root","n":"f_deptid","lb":"选择部门","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checktime_required","cid":"tw1qgcjp","type":1,"errmsg":"打卡时间不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","partsId":"timepicker","ct":1,"frag":{"t":"AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign","childs":[],"valt":"System.Nullable`1[System.DateTime]","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":16,"pub":1,"mt":"2025-03-05T15:31:24.9654966Z","id":"tw1qgcjp","pid":"root","n":"f_checktime","lb":"打卡时间","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checktime_required","cid":"tw1qgcjp","enabled":true,"type":1,"errmsg":"打卡时间不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","partsId":"input","ct":1,"frag":{"t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":50},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-02-24T15:36:15.8037414Z","id":"so4v7kba","pid":"root","n":"f_checklocation","lb":"打卡地点","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checklocation_required","cid":"so4v7kba","enabled":true,"type":1,"errmsg":"打卡地点不能为空","trigger":1,"order":1}],"v":"0.0.1"},{"libid":"antdesign","partsId":"radio","ct":1,"frag":{"t":"AntDesign.RadioGroup`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsfrag":{"t":"AntDesign.Radio`1[System.String], AntDesign","childs":[],"attrs":[{"attrn":"Value"}]},"dsgt":1,"dst":8,"fxopds":[{"l":"上班打卡","v":"0"},{"l":"下班打卡","v":"1"}]},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":13,"pub":1,"mt":"2025-03-23T07:26:31.4273273Z","id":"wlxwhf96","pid":"root","n":"f_checktype","lb":"打卡选项","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"f_checktype_required","cid":"wlxwhf96","enabled":true,"type":1,"errmsg":"请选择打卡类型","trigger":1,"order":1}],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"nkeppmji","n":"打卡","pt":1,"pageprop":{"playout":1,"ds":{}},"ds":{"dst":1,"dsid":"wmtnh0uv","dsn":"打卡","dsv":"tb_check"},"mt":"2025-11-29T16:51:31.7913039Z"} \ No newline at end of file diff --git a/meta/apps/attendance/page/s5v5kbsq.json b/meta/apps/attendance/page/s5v5kbsq.json index 8818837ba9e389e8c66710fdd31cd16bb852a71d..6b682b6e0073f49f2b95ed21a3433c358c5c47a5 100644 --- a/meta/apps/attendance/page/s5v5kbsq.json +++ b/meta/apps/attendance/page/s5v5kbsq.json @@ -1 +1 @@ -{"comps":[{"libid":"antdesign","compid":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"overtime_request","dsv":"{\"tcols\":[{\"id\":\"f_id\",\"n\":\"f_id\",\"disn\":\"主键\",\"pk\":true},{\"id\":\"f_userid\",\"n\":\"f_userid\",\"disn\":\"申请人\"},{\"id\":\"f_deptid\",\"n\":\"f_deptid\",\"disn\":\"部门\"},{\"id\":\"f_overtime_date\",\"n\":\"f_overtime_date\",\"disn\":\"加班日期\"},{\"id\":\"f_start_time\",\"n\":\"f_start_time\",\"disn\":\"开始时间\"},{\"id\":\"f_end_time\",\"n\":\"f_end_time\",\"disn\":\"结束时间\"},{\"id\":\"f_hours\",\"n\":\"f_hours\",\"disn\":\"加班小时\"},{\"id\":\"f_overtime_type\",\"n\":\"f_overtime_type\",\"disn\":\"加班类型\"},{\"id\":\"f_status\",\"n\":\"f_status\",\"disn\":\"审批状态\"},{\"id\":\"f_create_time\",\"n\":\"f_create_time\",\"disn\":\"申请时间\"}],\"searchs\":[{\"id\":\"search_userid\",\"n\":\"f_userid\",\"disn\":\"申请人\",\"t\":1},{\"id\":\"search_status\",\"n\":\"f_status\",\"disn\":\"审批状态\",\"t\":3,\"dsid\":\"approve_status_options\"},{\"id\":\"search_dept\",\"n\":\"f_deptid\",\"disn\":\"部门\",\"t\":3,\"dsid\":\"department_options\"},{\"id\":\"search_date\",\"n\":\"f_overtime_date\",\"disn\":\"加班日期\",\"t\":4}],\"tbtns\":[{\"id\":\"create_overtime\",\"n\":\"create\",\"disn\":\"新建申请\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"ehougawr\",\"eta\":\"14\"}]},{\"id\":\"batch_approve\",\"n\":\"batchApprove\",\"disn\":\"批量审批\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"view_detail\",\"n\":\"view\",\"disn\":\"查看详情\",\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"ehougawr\",\"eta\":\"14\"}],\"rowparams\":{\"id\":\"f_id\"}},{\"id\":\"approve\",\"n\":\"approve\",\"disn\":\"审批\",\"order\":2,\"sptevs\":[\"OnClick\"]},{\"id\":\"delete\",\"n\":\"delete\",\"disn\":\"删除\",\"order\":3,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"edit\",\"n\":\"edit\",\"disn\":\"编辑\",\"order\":4,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]},{\"id\":\"save\",\"n\":\"save\",\"disn\":\"保存\",\"order\":5,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":30}]},{\"id\":\"cancel\",\"n\":\"cancel\",\"disn\":\"取消\",\"order\":6,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":40}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-11-17T10:00:00Z","id":"overtime_table","pid":"root","n":"overtime_table","lb":"加班申请列表","sptds":true,"stl":{"itemw":24,"itemh":400,"labelw":180},"valrules":[],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"s5v5kbsq","n":"加班申请管理","order":7,"pt":2,"pageprop":{"playout":2,"ds":{"dst":1}},"ds":{"dst":1},"mt":"2025-11-23T12:44:57.5659015Z"} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"overtime_request","dsv":"{\"tcols\":[{\"id\":\"f_id\",\"n\":\"f_id\",\"disn\":\"主键\",\"pk\":true},{\"id\":\"f_userid\",\"n\":\"f_userid\",\"disn\":\"申请人\"},{\"id\":\"f_deptid\",\"n\":\"f_deptid\",\"disn\":\"部门\"},{\"id\":\"f_overtime_date\",\"n\":\"f_overtime_date\",\"disn\":\"加班日期\"},{\"id\":\"f_start_time\",\"n\":\"f_start_time\",\"disn\":\"开始时间\"},{\"id\":\"f_end_time\",\"n\":\"f_end_time\",\"disn\":\"结束时间\"},{\"id\":\"f_hours\",\"n\":\"f_hours\",\"disn\":\"加班小时\"},{\"id\":\"f_overtime_type\",\"n\":\"f_overtime_type\",\"disn\":\"加班类型\"},{\"id\":\"f_status\",\"n\":\"f_status\",\"disn\":\"审批状态\"},{\"id\":\"f_create_time\",\"n\":\"f_create_time\",\"disn\":\"申请时间\"}],\"searchs\":[{\"id\":\"search_userid\",\"n\":\"f_userid\",\"disn\":\"申请人\",\"t\":1},{\"id\":\"search_status\",\"n\":\"f_status\",\"disn\":\"审批状态\",\"t\":3,\"dsid\":\"approve_status_options\"},{\"id\":\"search_dept\",\"n\":\"f_deptid\",\"disn\":\"部门\",\"t\":3,\"dsid\":\"department_options\"},{\"id\":\"search_date\",\"n\":\"f_overtime_date\",\"disn\":\"加班日期\",\"t\":4}],\"tbtns\":[{\"id\":\"create_overtime\",\"n\":\"create\",\"disn\":\"新建申请\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"ehougawr\",\"eta\":\"14\"}]},{\"id\":\"batch_approve\",\"n\":\"batchApprove\",\"disn\":\"批量审批\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"view_detail\",\"n\":\"view\",\"disn\":\"查看详情\",\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"ehougawr\",\"eta\":\"14\"}],\"rowparams\":{\"id\":\"f_id\"}},{\"id\":\"approve\",\"n\":\"approve\",\"disn\":\"审批\",\"order\":2,\"sptevs\":[\"OnClick\"]},{\"id\":\"delete\",\"n\":\"delete\",\"disn\":\"删除\",\"order\":3,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"edit\",\"n\":\"edit\",\"disn\":\"编辑\",\"order\":4,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]},{\"id\":\"save\",\"n\":\"save\",\"disn\":\"保存\",\"order\":5,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":30}]},{\"id\":\"cancel\",\"n\":\"cancel\",\"disn\":\"取消\",\"order\":6,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":40}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-11-17T10:00:00Z","id":"overtime_table","pid":"root","n":"overtime_table","lb":"加班申请列表","hlb":true,"sptds":true,"stl":{"itemw":24,"itemh":400,"labelw":180},"valrules":[],"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"attendance","id":"s5v5kbsq","n":"加班申请管理","order":7,"pt":2,"pageprop":{"playout":2,"ds":{"dst":1}},"ds":{"dst":1},"mt":"2025-12-09T15:32:00.9420285Z"} \ No newline at end of file diff --git a/meta/apps/attendance/page/t7g1bfcyt.json b/meta/apps/attendance/page/t7g1bfcyt.json index 33e0ae3544398ae2a0d238ac43afb3a1a0fe5d2b..ea60756fd6494b9eb2aa45a2c7b6cf8ecac3ad0b 100644 --- a/meta/apps/attendance/page/t7g1bfcyt.json +++ b/meta/apps/attendance/page/t7g1bfcyt.json @@ -1,16 +1,18 @@ -{ +{ "comps": [ { "libid": "antdesign", - "compid": "select", + "partsId": "select", "ct": 1, "frag": { - "t": "AntDesign.Select\u00602[[System.String],[System.String]], antdesign", + "t": "AntDesign.Select`2[[System.String],[System.String]], antdesign", + "childs": [], "valt": "System.String", "attrs": [] }, "ds": { "dsgt": 1, + "dst": 8, "dsid": "leave_type_options" }, "attrdefgroups": [], @@ -34,10 +36,10 @@ { "id": "f_start_time_required", "cid": "f_start_time", + "enabled": true, "type": 1, "errmsg": "开始时间不能为空", "trigger": 1, - "enabled": true, "order": 1 } ], @@ -45,11 +47,12 @@ }, { "libid": "antdesign", - "compid": "datepicker", + "partsId": "datepicker", "ct": 1, "frag": { - "t": "AntDesign.DatePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign", - "valt": "System.Nullable\u00601[System.DateTime]", + "t": "AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", "attrs": [] }, "ds": { @@ -79,10 +82,10 @@ { "id": "f_end_time_required", "cid": "f_end_time", + "enabled": true, "type": 1, "errmsg": "结束时间不能为空", "trigger": 1, - "enabled": true, "order": 1 } ], @@ -90,11 +93,12 @@ }, { "libid": "antdesign", - "compid": "datepicker", + "partsId": "datepicker", "ct": 1, "frag": { - "t": "AntDesign.DatePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign", - "valt": "System.Nullable\u00601[System.DateTime]", + "t": "AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", "attrs": [] }, "ds": { @@ -124,31 +128,31 @@ { "id": "f_days_required", "cid": "f_days", + "enabled": true, "type": 1, "errmsg": "请假天数不能为空", "trigger": 1, - "enabled": true, "order": 1 }, { "id": "f_days_min", "cid": "f_days", + "enabled": true, "type": 3, "errmsg": "请假天数必须大于0", "trigger": 1, - "enabled": true, - "order": 2, - "rulev": "1" + "order": 2 } ], "v": "0.0.1" }, { "libid": "antdesign", - "compid": "inputnumber", + "partsId": "inputnumber", "ct": 1, "frag": { - "t": "AntDesign.InputNumber\u00601[System.Int32], AntDesign", + "t": "AntDesign.InputNumber`1[System.Int32], AntDesign", + "childs": [], "valt": "System.Int32", "attrs": [] }, @@ -175,31 +179,31 @@ { "id": "f_reason_required", "cid": "f_reason", + "enabled": true, "type": 1, "errmsg": "请假原因不能为空", "trigger": 1, - "enabled": true, "order": 1 }, { "id": "f_reason_min", "cid": "f_reason", + "enabled": true, "type": 3, "errmsg": "请假原因不能少于5个字符", "trigger": 1, - "enabled": true, - "order": 2, - "rulev": "5" + "order": 2 } ], "v": "0.0.1" }, { "libid": "antdesign", - "compid": "textarea", + "partsId": "textarea", "ct": 1, "frag": { "t": "AntDesign.TextArea, AntDesign", + "childs": [], "valt": "System.String", "attrs": [] }, @@ -216,7 +220,7 @@ "desc": "", "dftval": 4, "attrn": "Rows", - "attrt": "System.Int32", + "attrt": "System.UInt32", "attrv": 4 }, { @@ -248,144 +252,6 @@ }, "valrules": [], "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "button", - "ct": 1, - "frag": { - "t": "AntDesign.Button, AntDesign", - "valt": "System.String", - "attrs": [ - { - "attrn": "Text", - "attrt": "System.String" - }, - { - "attrn": "Type", - "attrt": "System.String" - } - ] - }, - "ds": {}, - "attrdefgroups": [ - { - "gn": "基础属性", - "attrdefs": [ - { - "disn": "按钮文字", - "pt": 1, - "desc": "按钮显示的文本内容", - "dftval": "按钮", - "attrn": "Text", - "attrt": "System.String", - "attrv": "提交申请" - }, - { - "disn": "按钮类型", - "pt": 3, - "desc": "按钮的样式类型", - "dftval": "default", - "attrn": "Type", - "attrt": "System.String", - "attrv": "primary" - } - ] - } - ], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 60, - "pub": 1, - "mt": "2025-11-17T10:00:00Z", - "id": "submit_btn", - "pid": "root", - "n": "submit_btn", - "lb": "提交按钮", - "stl": { - "itemw": 4, - "itemh": 50, - "labelw": 180 - }, - "evs": [ - { - "en": "OnClick", - "eht": 10, - "edat": 10 - } - ], - "valrules": [], - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "button", - "ct": 1, - "frag": { - "t": "AntDesign.Button, AntDesign", - "valt": "System.String", - "attrs": [ - { - "attrn": "Text", - "attrt": "System.String" - }, - { - "attrn": "Type", - "attrt": "System.String" - } - ] - }, - "ds": {}, - "attrdefgroups": [ - { - "gn": "基础属性", - "attrdefs": [ - { - "disn": "按钮文字", - "pt": 1, - "desc": "按钮显示的文本内容", - "dftval": "按钮", - "attrn": "Text", - "attrt": "System.String", - "attrv": "重置" - }, - { - "disn": "按钮类型", - "pt": 3, - "desc": "按钮的样式类型", - "dftval": "default", - "attrn": "Type", - "attrt": "System.String", - "attrv": "default" - } - ] - } - ], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 70, - "pub": 1, - "mt": "2025-11-17T10:00:00Z", - "id": "reset_btn", - "pid": "root", - "n": "reset_btn", - "lb": "重置按钮", - "stl": { - "itemw": 4, - "itemh": 50, - "labelw": 180 - }, - "evs": [ - { - "en": "OnClick", - "eht": 10, - "edat": 20 - } - ], - "valrules": [], - "v": "0.0.1" } ], "sptevs": [ @@ -403,11 +269,10 @@ } }, "ds": { - "dsgt": 1, "dst": 1, "dsid": "leave_request", "dsn": "请假申请", "dsv": "tb_leave_request" }, - "mt": "2025-11-23T10:51:59.3503316Z" + "mt": "2025-12-09T15:01:32.3954823Z" } \ No newline at end of file diff --git a/meta/apps/caseapp/page/2qme5ln5e.json b/meta/apps/caseapp/page/2qme5ln5e.json index a4f919b8108ef4b17f77533172417f79ea89193a..acee8f875ee6a8ae8efe0e2f1819e7e0f83f8c52 100644 --- a/meta/apps/caseapp/page/2qme5ln5e.json +++ b/meta/apps/caseapp/page/2qme5ln5e.json @@ -1,7 +1,7 @@ { "comps": [ { - "compid": "card", + "partsId": "card", "libid": "antdesign", "cn": "Card", "ct": 1, @@ -28,7 +28,7 @@ ], "childs": [ { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -79,7 +79,7 @@ "ev": {} }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -130,7 +130,7 @@ "ev": {} }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -197,7 +197,7 @@ "ev": {} }, { - "compid": "card", + "partsId": "card", "libid": "antdesign", "cn": "Card", "ct": 1, @@ -224,7 +224,7 @@ ], "childs": [ { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -275,7 +275,7 @@ "ev": {} }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -326,7 +326,7 @@ "ev": {} }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -393,7 +393,7 @@ "ev": {} }, { - "compid": "card", + "partsId": "card", "libid": "antdesign", "cn": "Card", "ct": 1, @@ -420,7 +420,7 @@ ], "childs": [ { - "compid": "radio", + "partsId": "radio", "libid": "antdesign", "cn": "Radio", "ct": 1, @@ -468,7 +468,7 @@ "ev": {} }, { - "compid": "switch", + "partsId": "switch", "libid": "antdesign", "cn": "Switch", "ct": 1, diff --git a/meta/apps/caseapp/page/5kicsevr.json b/meta/apps/caseapp/page/5kicsevr.json index 46a6ee352f9455e60b8c3fbdd37da9c3317cae50..12999394f92f4a2793ae0676c6b3dc12b6c0192f 100644 --- a/meta/apps/caseapp/page/5kicsevr.json +++ b/meta/apps/caseapp/page/5kicsevr.json @@ -1,7 +1,7 @@ { "comps": [ { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -69,7 +69,7 @@ "desc": "用户姓名输入框" }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -137,7 +137,7 @@ "desc": "用户手机号输入框" }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -205,7 +205,7 @@ "desc": "用户邮箱输入框" }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -273,7 +273,7 @@ "desc": "用户公司输入框" }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, @@ -341,7 +341,7 @@ "desc": "用户职位输入框" }, { - "compid": "input", + "partsId": "input", "libid": "antdesign", "cn": "Input", "ct": 1, diff --git a/meta/apps/caseapp/page/fhumgxyk.json b/meta/apps/caseapp/page/fhumgxyk.json index 0c93d7699571e862829e864b35130dba226293d2..7174c5c21efac810c668e7ef22deb70723b412e6 100644 --- a/meta/apps/caseapp/page/fhumgxyk.json +++ b/meta/apps/caseapp/page/fhumgxyk.json @@ -1,464 +1 @@ -{ - "comps": [ - { - "libid": "antdesign", - "compid": "input", - "cn": "Input", - "ct": 1, - "frag": { - "dt": "AntDesign.Input`1[System.String], AntDesign", - "t": "AntDesign.Input`1[System.String], AntDesign", - "childs": [], - "valt": "System.String", - "attrs": [ - { - "attrn": "TValue", - "attrt": "System.String" - } - ] - }, - "ds": { - "dsgt": 1 - }, - "attrdefgroups": [ - { - "gn": "基础属性", - "attrdefs": [ - { - "disn": "是否禁用", - "pt": 6, - "desc": "", - "dftval": false, - "attrn": "Disabled", - "attrt": "System.Boolean", - "attrv": false - }, - { - "disn": "最大长度", - "pt": 2, - "desc": "字段输入的最大长度,为0时表示不限制长度", - "dftval": 0, - "attrn": "MaxLength", - "attrt": "System.Int32", - "attrv": 20 - }, - { - "disn": "输入提示", - "pt": 1, - "desc": "组件输入时的 Placeholder 提示", - "dftval": "", - "attrn": "Placeholder", - "attrt": "System.String", - "attrv": "" - } - ] - } - ], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 10, - "pub": 1, - "mt": "2025-02-24T15:36:15.8037414Z", - "id": "0bd406f9", - "pid": "lyawwbh9f", - "n": "f_field1", - "lb": "输入框1", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "valrules": [ - { - "id": "648ea2de-8c82-414b-b669-3b581ab9a11c", - "cid": "0bd406f9", - "type": 1, - "errmsg": "必填111", - "trigger": 1, - "enabled": true, - "order": 1 - } - ], - "desc": "111", - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "input", - "cn": "Input", - "ct": 1, - "frag": { - "dt": "AntDesign.Input`1[System.String], AntDesign", - "t": "AntDesign.Input`1[System.String], AntDesign", - "childs": [], - "valt": "System.String", - "attrs": [ - { - "attrn": "TValue", - "attrt": "System.String" - } - ] - }, - "ds": {}, - "attrdefgroups": [ - { - "gn": "基础属性", - "attrdefs": [ - { - "disn": "是否禁用", - "pt": 6, - "desc": "", - "dftval": false, - "attrn": "Disabled", - "attrt": "System.Boolean", - "attrv": true - }, - { - "disn": "最大长度", - "pt": 2, - "desc": "字段输入的最大长度,为0时表示不限制长度", - "dftval": 0, - "attrn": "MaxLength", - "attrt": "System.Int32", - "attrv": 0 - }, - { - "disn": "输入提示", - "pt": 1, - "desc": "组件输入时的 Placeholder 提示", - "dftval": "", - "attrn": "Placeholder", - "attrt": "System.String", - "attrv": "xxx" - } - ] - } - ], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 10, - "pub": 1, - "mt": "2025-02-24T15:36:15.8037414Z", - "id": "299f6803", - "pid": "lyawwbh9f", - "n": "f_field3", - "lb": "输入框2", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "valrules": [], - "desc": "222", - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "radio", - "cn": "Radio", - "ct": 1, - "frag": { - "dt": "AntDesign.RadioGroup`1[System.String], AntDesign", - "t": "AntDesign.RadioGroup`1[System.String], AntDesign", - "childs": [], - "valt": "System.String", - "attrs": [ - { - "attrn": "TValue", - "attrt": "System.String" - } - ] - }, - "ds": { - "dsfrag": { - "t": "AntDesign.Radio`1[System.String], AntDesign", - "childs": [], - "attrs": [ - { - "attrn": "Value" - } - ] - }, - "dsgt": 1, - "dst": 8, - "fxopds": [ - { - "l": "选项1", - "v": "op1" - }, - { - "l": "选项2", - "v": "op2" - }, - { - "l": "选项3", - "v": "op3" - }, - { - "l": "选项4", - "v": "op4" - } - ] - }, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 13, - "pub": 1, - "mt": "2025-03-01T02:58:56.1519656Z", - "id": "vjolyn1r", - "pid": "zkgldg5b", - "n": "f_field6", - "lb": "单选框3", - "sptds": true, - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "checkbox", - "cn": "Checkbox", - "ct": 1, - "frag": { - "dt": "AntDesign.CheckboxGroup`1[System.String], AntDesign", - "t": "AntDesign.CheckboxGroup`1[System.String], AntDesign", - "childs": [], - "valt": "System.String[]", - "attrs": [] - }, - "ds": { - "dsfrag": { - "t": "AntDesign.Checkbox, AntDesign", - "childs": [], - "attrs": [ - { - "attrn": "Label" - } - ] - }, - "dsgt": 1, - "dst": 8, - "fxopds": [ - { - "l": "选项11", - "v": "ck1" - }, - { - "l": "选项22", - "v": "ck2" - }, - { - "l": "选项33", - "v": "字段8" - } - ] - }, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 14, - "pub": 1, - "mt": "2025-02-24T15:37:04.5563097Z", - "id": "4trfp5bk", - "pid": "zkgldg5b", - "n": "f_field8", - "lb": "复选框4", - "sptds": true, - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "datepicker", - "cn": "DatePicker", - "ct": 1, - "frag": { - "dt": "AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", - "t": "AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", - "childs": [], - "valt": "System.Nullable`1[System.DateTime]", - "attrs": [] - }, - "ds": { - "dsgt": 1 - }, - "attrdefgroups": [], - "childs": [], - "sptevs": [ - "OnClick", - "OnExpand" - ], - "evdefs": [], - "stydefs": [], - "order": 15, - "pub": 1, - "mt": "2025-02-24T15:59:32.6799272Z", - "id": "vdyv8q2ay", - "pid": "zkgldg5b", - "n": "f_field10", - "lb": "日期选择器5", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "timepicker", - "cn": "TimePicker", - "ct": 1, - "frag": { - "dt": "AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", - "t": "AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", - "childs": [], - "valt": "System.Nullable`1[System.DateTime]", - "attrs": [] - }, - "ds": {}, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 16, - "pub": 1, - "mt": "2025-03-05T15:31:24.9654966Z", - "id": "itnmgtzg", - "pid": "zkgldg5b", - "n": "f_field13", - "lb": "时间选择器6", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "textarea", - "cn": "TextArea", - "ct": 1, - "frag": { - "dt": "AntDesign.TextArea, AntDesign", - "t": "AntDesign.TextArea, AntDesign", - "childs": [], - "valt": "System.String", - "attrs": [] - }, - "ds": { - "dsgt": 1 - }, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 12, - "pub": 1, - "mt": "2025-02-24T15:36:40.7389762Z", - "id": "ibgtanur", - "pid": "ongkggvjy", - "n": "f_field7", - "lb": "文本框7", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "select", - "cn": "Select", - "ct": 1, - "frag": { - "dt": "AntDesign.Select`2[[System.String],[System.String]], antdesign", - "t": "AntDesign.Select`2[[System.String],[System.String]], antdesign", - "childs": [], - "valt": "System.String", - "attrs": [] - }, - "ds": {}, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 17, - "pub": 1, - "mt": "2025-03-05T15:31:30.1523166Z", - "id": "c9acpmcp", - "pid": "ongkggvjy", - "n": "f_field11", - "lb": "选择器8", - "sptds": true, - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - }, - { - "libid": "antdesign", - "compid": "switch", - "cn": "Switch", - "ct": 1, - "frag": { - "dt": "AntDesign.Switch, AntDesign", - "t": "AntDesign.Switch, AntDesign", - "childs": [], - "valt": "System.Boolean", - "attrs": [] - }, - "ds": {}, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "order": 19, - "pub": 1, - "mt": "2025-03-05T15:31:40.4314786Z", - "id": "cgfb0e64", - "pid": "ongkggvjy", - "n": "f_field9", - "lb": "开关9", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - }, - "v": "0.0.1" - } - ], - "sptevs": [ - "OnLoad" - ], - "aid": "caseapp", - "id": "fhumgxyk", - "n": "基础表单", - "order": 1, - "pt": 1, - "pageprop": { - "playout": 3, - "ds": {} - }, - "ds": { - "dst": 1, - "dsv": "tb_test1" - }, - "mt": "2025-10-26T15:04:35.7776707Z" -} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用输入框","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":20},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-02-24T15:36:15.8037414Z","id":"0bd406f9","pid":"lyawwbh9f","n":"f_field1","lb":"输入框1","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[{"id":"648ea2de-8c82-414b-b669-3b581ab9a11c","cid":"0bd406f9","enabled":true,"type":1,"errmsg":"必填111","trigger":1,"order":1}],"desc":"111","v":"0.0.1"},{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用输入框","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":true},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":0},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":"xxx"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":10,"pub":1,"mt":"2025-02-24T15:36:15.8037414Z","id":"299f6803","pid":"lyawwbh9f","n":"f_field3","lb":"输入框2","stl":{"itemw":4,"itemh":85,"labelw":180},"valrules":[],"desc":"222","v":"0.0.1"},{"libid":"antdesign","partsId":"radio","ct":1,"frag":{"dt":"AntDesign.RadioGroup`1[System.String], AntDesign","t":"AntDesign.RadioGroup`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsfrag":{"t":"AntDesign.Radio`1[System.String], AntDesign","childs":[],"attrs":[{"attrn":"Value"}]},"dsgt":1,"dst":8,"fxopds":[{"l":"选项1","v":"op1"},{"l":"选项2","v":"op2"},{"l":"选项3","v":"op3"},{"l":"选项4","v":"op4"}]},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":13,"pub":1,"mt":"2025-03-01T02:58:56.1519656Z","id":"vjolyn1r","pid":"zkgldg5b","n":"f_field6","lb":"单选框3","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"checkbox","ct":1,"frag":{"dt":"AntDesign.CheckboxGroup`1[System.String], AntDesign","t":"AntDesign.CheckboxGroup`1[System.String], AntDesign","childs":[],"valt":"System.String[]","attrs":[]},"ds":{"dsfrag":{"t":"AntDesign.Checkbox, AntDesign","childs":[],"attrs":[{"attrn":"Label"}]},"dsgt":1,"dst":8,"fxopds":[{"l":"选项11","v":"ck1"},{"l":"选项22","v":"ck2"},{"l":"选项33","v":"字段8"}]},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":14,"pub":1,"mt":"2025-02-24T15:37:04.5563097Z","id":"4trfp5bk","pid":"zkgldg5b","n":"f_field8","lb":"复选框4","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"datepicker","ct":1,"frag":{"dt":"AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign","t":"AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign","childs":[],"valt":"System.Nullable`1[System.DateTime]","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"sptevs":["OnClick","OnExpand"],"evdefs":[],"stydefs":[],"order":15,"pub":1,"mt":"2025-02-24T15:59:32.6799272Z","id":"vdyv8q2ay","pid":"zkgldg5b","n":"f_field10","lb":"日期选择器5","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"timepicker","ct":1,"frag":{"dt":"AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign","t":"AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign","childs":[],"valt":"System.Nullable`1[System.DateTime]","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":16,"pub":1,"mt":"2025-03-05T15:31:24.9654966Z","id":"itnmgtzg","pid":"zkgldg5b","n":"f_field13","lb":"时间选择器6","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"textarea","ct":1,"frag":{"dt":"AntDesign.TextArea, AntDesign","t":"AntDesign.TextArea, AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":12,"pub":1,"mt":"2025-02-24T15:36:40.7389762Z","id":"ibgtanur","pid":"ongkggvjy","n":"f_field7","lb":"文本框7","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"select","ct":1,"frag":{"dt":"AntDesign.Select`2[[System.String],[System.String]], antdesign","t":"AntDesign.Select`2[[System.String],[System.String]], antdesign","childs":[],"valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":17,"pub":1,"mt":"2025-03-05T15:31:30.1523166Z","id":"c9acpmcp","pid":"ongkggvjy","n":"f_field11","lb":"选择器8","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"switch","ct":1,"frag":{"dt":"AntDesign.Switch, AntDesign","t":"AntDesign.Switch, AntDesign","childs":[],"valt":"System.Boolean","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":19,"pub":1,"mt":"2025-03-05T15:31:40.4314786Z","id":"cgfb0e64","pid":"ongkggvjy","n":"f_field9","lb":"开关9","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"inputnumber","ct":1,"frag":{"dt":"AntDesign.InputNumber`1[System.Int32], AntDesign","t":"AntDesign.InputNumber`1[System.Int32], AntDesign","childs":[],"valt":"System.Int32","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用数字输入框","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false}]},{"gn":"数值范围","attrdefs":[{"disn":"最小值","pt":2,"desc":"数字输入框的最小值","dftval":0,"attrn":"Min","attrt":"System.Int32","attrv":0},{"disn":"最大值","pt":2,"desc":"数字输入框的最大值","dftval":0,"attrn":"Max","attrt":"System.Int32","attrv":0},{"disn":"步长","pt":2,"desc":"每次增加或减少的步长","dftval":1,"attrn":"Step","attrt":"System.Int32","attrv":1},{"disn":"精度","pt":2,"desc":"小数点后的位数","dftval":0,"attrn":"Precision","attrt":"System.Int32","attrv":0}]},{"gn":"样式属性","attrdefs":[{"disn":"数字输入框大小","pt":1,"desc":"数字输入框大小(large|middle|small)","dftval":"middle","attrn":"Size","attrt":"System.String","attrv":"middle"},{"disn":"边框样式","pt":6,"desc":"是否有边框","dftval":true,"attrn":"Bordered","attrt":"System.Boolean","attrv":true}]}],"childs":[],"evdefs":[],"stydefs":[],"order":12,"pub":1,"mt":"2025-12-11T22:45:00Z","id":"owcsbkey","pid":"root","n":"inputnumber_114","lb":"数字输入框-A","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.2"},{"libid":"antdesign","partsId":"autocomplete","ct":1,"frag":{"dt":"AntDesign.AutoComplete`1[System.String], AntDesign","t":"AntDesign.AutoComplete`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用自动完成","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"是否显示清除按钮","pt":6,"desc":"显示清除按钮","dftval":false,"attrn":"AllowClear","attrt":"System.Boolean","attrv":false},{"disn":"输入提示","pt":1,"desc":"自动完成的 Placeholder 提示","dftval":"请输入","attrn":"Placeholder","attrt":"System.String","attrv":"请输入"}]},{"gn":"高级属性","attrdefs":[{"disn":"选中时回填","pt":6,"desc":"选中选项后,是否回填输入框","dftval":true,"attrn":"BackfillOnSelect","attrt":"System.Boolean","attrv":true}]},{"gn":"样式属性","attrdefs":[{"disn":"自动完成大小","pt":1,"desc":"自动完成大小(large|middle|small)","dftval":"middle","attrn":"Size","attrt":"System.String","attrv":"middle"},{"disn":"边框样式","pt":6,"desc":"是否有边框","dftval":true,"attrn":"Bordered","attrt":"System.Boolean","attrv":true}]}],"childs":[],"evdefs":[],"stydefs":[],"order":16,"pub":1,"mt":"2025-12-11T22:45:00Z","id":"eqxuglwx","pid":"root","n":"autocomplete_847","lb":"自动完成-A","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.2"},{"libid":"antdesign","partsId":"cascader","ct":1,"frag":{"dt":"AntDesign.Cascader, AntDesign","t":"AntDesign.Cascader, AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用级联选择","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"是否显示清除按钮","pt":6,"desc":"显示清除按钮","dftval":false,"attrn":"AllowClear","attrt":"System.Boolean","attrv":false},{"disn":"显示搜索框","pt":6,"desc":"在下拉菜单中显示搜索框","dftval":false,"attrn":"ShowSearch","attrt":"System.Boolean","attrv":false},{"disn":"输入提示","pt":1,"desc":"级联选择的 Placeholder 提示","dftval":"请选择","attrn":"Placeholder","attrt":"System.String","attrv":"请选择"}]},{"gn":"高级属性","attrdefs":[{"disn":"多选模式","pt":6,"desc":"支持多选模式","dftval":false,"attrn":"Multiple","attrt":"System.Boolean","attrv":false},{"disn":"变更时触发父级","pt":6,"desc":"当一个选项改变时,父选项是否也受影响","dftval":false,"attrn":"ChangeOnSelect","attrt":"System.Boolean","attrv":false}]},{"gn":"样式属性","attrdefs":[{"disn":"级联选择大小","pt":1,"desc":"级联选择大小(large|middle|small)","dftval":"middle","attrn":"Size","attrt":"System.String","attrv":"middle"},{"disn":"边框样式","pt":6,"desc":"是否有边框","dftval":true,"attrn":"Bordered","attrt":"System.Boolean","attrv":true}]}],"childs":[],"evdefs":[],"stydefs":[],"order":17,"pub":1,"mt":"2025-12-11T22:45:00Z","id":"qohxw3fz","pid":"root","n":"cascader_165","lb":"级联选择-A","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.2"},{"libid":"antdesign","partsId":"tree","ct":1,"frag":{"dt":"AntDesign.Tree`1[System.String], AntDesign","t":"AntDesign.Tree`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用树组件","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"显示图标","pt":6,"desc":"在节点前显示文件类型图标","dftval":false,"attrn":"ShowIcon","attrt":"System.Boolean","attrv":false},{"disn":"可选择","pt":6,"desc":"节点是否可选择","dftval":false,"attrn":"Checkable","attrt":"System.Boolean","attrv":false}]},{"gn":"高级属性","attrdefs":[{"disn":"多选模式","pt":6,"desc":"支持多选","dftval":false,"attrn":"Multiple","attrt":"System.Boolean","attrv":false},{"disn":"默认全部展开","pt":6,"desc":"是否默认展开所有树节点","dftval":false,"attrn":"DefaultExpandAll","attrt":"System.Boolean","attrv":false},{"disn":"节点可拖拽","pt":6,"desc":"节点是否可以拖拽","dftval":false,"attrn":"Draggable","attrt":"System.Boolean","attrv":false}]},{"gn":"样式属性","attrdefs":[{"disn":"块级样式","pt":6,"desc":"将树设置为块级元素,宽度为100%","dftval":false,"attrn":"BlockNode","attrt":"System.Boolean","attrv":false}]}],"childs":[],"evdefs":[],"stydefs":[],"order":18,"pub":1,"mt":"2025-12-11T22:45:00Z","id":"4tvf7bbz","pid":"root","n":"tree_654","lb":"树-A","sptds":true,"stl":{"itemw":4,"itemh":300,"labelw":180},"v":"0.0.2"}],"sptevs":["OnLoad"],"aid":"caseapp","id":"fhumgxyk","n":"基础表单","order":1,"pt":1,"pageprop":{"playout":3,"ds":{}},"ds":{"dst":1,"dsv":"tb_test1"},"mt":"2025-12-12T15:03:56.4131898Z"} \ No newline at end of file diff --git a/meta/apps/caseapp/page/g0qcqxzd.json b/meta/apps/caseapp/page/g0qcqxzd.json index 0eb98d4c68df4da92700078d30928d458409f6dc..52b4cd63f9c5a23ed9a4e5ba91fea97876546578 100644 --- a/meta/apps/caseapp/page/g0qcqxzd.json +++ b/meta/apps/caseapp/page/g0qcqxzd.json @@ -1,52 +1 @@ -{ - "comps": [ - { - "compid": "table", - "libid": "antdesign", - "cn": "Table", - "ct": 1, - "frag": { - "dt": "H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults", - "t": "H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults", - "attrs": [] - }, - "ds": { - "dsgt": 2, - "dst": 1, - "dsid": "qgzhc7w3z", - "dsn": "tb_test1", - "dsv": "{\"tcols\":[{\"id\":\"i79talu1\",\"n\":\"f_field1\",\"t\":\"输入框1\"},{\"id\":\"vwvoqrn1s\",\"n\":\"f_field3\",\"t\":\"输入框2\"},{\"id\":\"ap0ceewr\",\"n\":\"f_field6\",\"t\":\"单选框3\"},{\"id\":\"ck9b6mez\",\"n\":\"Class\",\"t\":\"班级\"},{\"id\":\"es0qoauj\",\"n\":\"f_field10\",\"t\":\"日期选择5\"},{\"id\":\"t910chps\",\"n\":\"f_id\",\"t\":\"Id\",\"pk\":true}],\"searchs\":[],\"tbtns\":[{\"id\":\"wpnm70fe\",\"n\":\"create\",\"t\":\"新增\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"fhumgxyk\",\"eta\":\"14\"}]},{\"id\":\"2qsecnfo\",\"n\":\"deleteSelections\",\"t\":\"删除选中\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"za8gxxdz\",\"n\":\"edit\",\"t\":\"编辑\",\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"fhumgxyk\",\"eta\":\"14\",\"eventArgs\":{\"param1\":\"111\"},\"rowparams\":{\"id\":\"f_id\"}}]},{\"id\":\"b17d3nrc\",\"n\":\"del\",\"t\":\"删除\",\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"vwrounbq\",\"n\":\"editRow\",\"t\":\"行内编辑\",\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]}]}" - }, - "attrdefgroups": [], - "childs": [], - "order": 30, - "pub": 1, - "mt": "2025-05-22T14:26:07.7475675Z", - "id": "fqmcwygx", - "pid": "nupedwmm3", - "n": "Table_926", - "lb": "表格-A", - "hlb": true, - "sptds": true, - "stl": { - "itemw": 24, - "itemh": 300, - "labelw": 180 - } - } - ], - "sptevs": [ - "OnLoad" - ], - "aid": "caseapp", - "id": "g0qcqxzd", - "n": "基础列表", - "order": 31, - "pt": 2, - "pageprop": { - "playout": 2, - "ds": {} - }, - "ds": {}, - "mt": "2025-09-26T16:52:21.2061257Z" -} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"qgzhc7w3z","dsn":"tb_test1","dsv":"{\"tcols\":[{\"id\":\"i79talu1\",\"n\":\"f_field1\",\"t\":\"输入框1\"},{\"id\":\"vwvoqrn1s\",\"n\":\"f_field3\",\"t\":\"输入框2\"},{\"id\":\"ap0ceewr\",\"n\":\"f_field6\",\"t\":\"单选框3\"},{\"id\":\"ck9b6mez\",\"n\":\"Class\",\"t\":\"班级\"},{\"id\":\"es0qoauj\",\"n\":\"f_field10\",\"t\":\"日期选择5\"},{\"id\":\"t910chps\",\"n\":\"f_id\",\"t\":\"Id\",\"pk\":true}],\"searchs\":[],\"tbtns\":[{\"id\":\"wpnm70fe\",\"n\":\"create\",\"t\":\"新增\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"fhumgxyk\",\"eta\":\"14\"}]},{\"id\":\"2qsecnfo\",\"n\":\"deleteSelections\",\"t\":\"删除选中\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"za8gxxdz\",\"n\":\"edit\",\"t\":\"编辑\",\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"fhumgxyk\",\"eta\":\"14\",\"eventArgs\":{\"param1\":\"111\"},\"rowparams\":{\"id\":\"f_id\"}}]},{\"id\":\"b17d3nrc\",\"n\":\"del\",\"t\":\"删除\",\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]},{\"id\":\"vwrounbq\",\"n\":\"editRow\",\"t\":\"行内编辑\",\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":10}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":30,"pub":1,"mt":"2025-05-22T14:26:07.7475675Z","id":"fqmcwygx","pid":"nupedwmm3","n":"Table_926","lb":"表格-A","hlb":true,"sptds":true,"stl":{"itemw":24,"itemh":300,"labelw":180},"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"caseapp","id":"g0qcqxzd","n":"基础列表","order":31,"pt":2,"pageprop":{"playout":2,"ds":{}},"ds":{},"mt":"2025-12-05T16:28:54.7821571Z"} \ No newline at end of file diff --git a/meta/apps/caseapp/page/gndz2vecz.json b/meta/apps/caseapp/page/gndz2vecz.json index c414b625d74c4f2b1b1034df9ffb7841b216f2a9..51aa353ff12115b0bf437251ad66a0cd0cd1c1a5 100644 --- a/meta/apps/caseapp/page/gndz2vecz.json +++ b/meta/apps/caseapp/page/gndz2vecz.json @@ -2,7 +2,7 @@ "comps": [ { "libid": "antdesign", - "compid": "tabs", + "partsId": "tabs", "cn": "Tabs", "ct": 1, "frag": { @@ -90,7 +90,7 @@ ], "childs": [ { - "compid": "incontainer", + "partsId": "incontainer", "frag": { "childs": [], "attrs": [] diff --git a/meta/apps/caseapp/page/huf12sk.json b/meta/apps/caseapp/page/huf12sk.json index 8d1ba3378dde69c29e51f7c2793d1e7f5676b9a4..1d6f18b424bb07b52277b619936dfc91429f438c 100644 --- a/meta/apps/caseapp/page/huf12sk.json +++ b/meta/apps/caseapp/page/huf12sk.json @@ -1,7 +1,7 @@ { "comps": [ { - "compid": "table", + "partsId": "table", "ds": {}, "attrdefgroups": [], "childs": [], diff --git a/meta/apps/survey/datasource/ds_answer.json b/meta/apps/survey/datasource/ds_answer.json new file mode 100644 index 0000000000000000000000000000000000000000..ba42d4dc2df25b336bc424477dd974043099aafe --- /dev/null +++ b/meta/apps/survey/datasource/ds_answer.json @@ -0,0 +1 @@ +{"aid":"survey","id":"ds_answer","n":"tb_answer","disn":"问卷提交答案表","desc":"answer content","type":1,"fields":[{"id":"f_id","n":"f_id","disn":"primary key","type":"varchar","pk":true},{"id":"f_submission_id","n":"f_submission_id","disn":"submission id","type":"varchar"},{"id":"f_question_id","n":"f_question_id","disn":"question id","type":"varchar"},{"id":"f_answer_text","n":"f_answer_text","disn":"answer text","type":"varchar","nul":true},{"id":"f_selected_options","n":"f_selected_options","disn":"selected options","type":"varchar","nul":true},{"id":"f_create_time","n":"f_create_time","disn":"create time","type":"datetime"}],"ops":[],"mt":"2025-12-17T13:03:38.4362202Z"} \ No newline at end of file diff --git a/meta/apps/survey/datasource/ds_option.json b/meta/apps/survey/datasource/ds_option.json new file mode 100644 index 0000000000000000000000000000000000000000..af524f7b584cc076afa5dce27426440acd269b3c --- /dev/null +++ b/meta/apps/survey/datasource/ds_option.json @@ -0,0 +1 @@ +{"aid":"survey","id":"ds_option","n":"tb_question_option","disn":"问卷问题选项表","desc":"question options","type":1,"fields":[{"id":"f_id","n":"f_id","disn":"primary key","type":"varchar","pk":true},{"id":"f_question_id","n":"f_question_id","disn":"question id","type":"varchar"},{"id":"f_option_text","n":"f_option_text","disn":"option text","type":"varchar"},{"id":"f_order","n":"f_order","disn":"order","type":"int"},{"id":"f_create_time","n":"f_create_time","disn":"create time","type":"datetime"}],"ops":[],"mt":"2025-12-17T13:03:19.6096827Z"} \ No newline at end of file diff --git a/meta/apps/survey/datasource/ds_question.json b/meta/apps/survey/datasource/ds_question.json new file mode 100644 index 0000000000000000000000000000000000000000..3cdcef66514a89b06e53e1e0a63a73be651b284d --- /dev/null +++ b/meta/apps/survey/datasource/ds_question.json @@ -0,0 +1 @@ +{"aid":"survey","id":"ds_question","n":"tb_question","disn":"问卷问题表","desc":"question info","type":1,"fields":[{"id":"f_id","n":"f_id","disn":"primary key","type":"varchar","pk":true},{"id":"f_survey_id","n":"f_survey_id","disn":"survey id","type":"varchar"},{"id":"f_question_type","n":"f_question_type","disn":"question type","type":"int"},{"id":"f_title","n":"f_title","disn":"question title","type":"varchar"},{"id":"f_description","n":"f_description","disn":"question desc","type":"varchar","nul":true},{"id":"f_is_required","n":"f_is_required","disn":"is required","type":"bool"},{"id":"f_order","n":"f_order","disn":"order","type":"int"},{"id":"f_options_json","n":"f_options_json","disn":"options json","type":"text","nul":true},{"id":"f_create_time","n":"f_create_time","disn":"create time","type":"datetime"}],"ops":[{"id":"save","n":"保存问题","type":"insert_or_update","sql":"INSERT INTO tb_question (f_id, f_survey_id, f_question_type, f_title, f_description, f_is_required, f_order, f_options_json, f_create_time) VALUES (@f_id, @f_survey_id, @f_question_type, @f_title, @f_description, @f_is_required, @f_order, @f_options_json, NOW()) ON DUPLICATE KEY UPDATE f_question_type=@f_question_type, f_title=@f_title, f_description=@f_description, f_is_required=@f_is_required, f_order=@f_order, f_options_json=@f_options_json"},{"id":"delete","n":"删除问题","type":"delete","sql":"DELETE FROM tb_question WHERE f_id=@f_id"},{"id":"list","n":"获取问题列表","type":"select","sql":"SELECT * FROM tb_question WHERE f_survey_id=@f_survey_id ORDER BY f_order ASC"},{"id":"batch_save","n":"批量保存问题","type":"batch_insert_or_update","sql":"INSERT INTO tb_question (f_id, f_survey_id, f_question_type, f_title, f_description, f_is_required, f_order, f_options_json, f_create_time) VALUES (@f_id, @f_survey_id, @f_question_type, @f_title, @f_description, @f_is_required, @f_order, @f_options_json, NOW()) ON DUPLICATE KEY UPDATE f_question_type=@f_question_type, f_title=@f_title, f_description=@f_description, f_is_required=@f_is_required, f_order=@f_order, f_options_json=@f_options_json"}],"mt":"2025-12-25T23:15:00.0000000Z"} \ No newline at end of file diff --git a/meta/apps/survey/datasource/ds_submission.json b/meta/apps/survey/datasource/ds_submission.json new file mode 100644 index 0000000000000000000000000000000000000000..59dac1333dcf6a629f1b83745afea23bb567982d --- /dev/null +++ b/meta/apps/survey/datasource/ds_submission.json @@ -0,0 +1 @@ +{"aid":"survey","id":"ds_submission","n":"tb_submission","disn":"问卷提交记录表","desc":"submission record","type":1,"fields":[{"id":"f_id","n":"f_id","disn":"primary key","type":"varchar","pk":true},{"id":"f_survey_id","n":"f_survey_id","disn":"survey id","type":"varchar"},{"id":"f_submitter_id","n":"f_submitter_id","disn":"submitter id","type":"varchar","nul":true},{"id":"f_submitter_name","n":"f_submitter_name","disn":"submitter name","type":"varchar","nul":true},{"id":"f_submit_time","n":"f_submit_time","disn":"submit time","type":"datetime"},{"id":"f_ip_address","n":"f_ip_address","disn":"ip address","type":"varchar","nul":true},{"id":"f_is_complete","n":"f_is_complete","disn":"is complete","type":"bool"}],"ops":[],"mt":"2025-12-17T13:02:55.0395416Z"} \ No newline at end of file diff --git a/meta/apps/survey/datasource/ds_survey.json b/meta/apps/survey/datasource/ds_survey.json new file mode 100644 index 0000000000000000000000000000000000000000..5fb874c660abc744913d9921f1511a7bb9f59aff --- /dev/null +++ b/meta/apps/survey/datasource/ds_survey.json @@ -0,0 +1 @@ +{"aid":"survey","id":"ds_survey","n":"tb_survey","disn":"问卷表","desc":"survey info","type":1,"fields":[{"id":"f_id","n":"f_id","disn":"primary key","type":"varchar","pk":true},{"id":"f_title","n":"f_title","disn":"survey title","type":"varchar"},{"id":"f_description","n":"f_description","disn":"survey desc","type":"varchar","nul":true},{"id":"f_status","n":"f_status","disn":"survey status","type":"int"},{"id":"f_is_template","n":"f_is_template","disn":"is template","type":"bool"},{"id":"f_template_category","n":"f_template_category","disn":"template category","type":"varchar","nul":true},{"id":"f_source_template_id","n":"f_source_template_id","disn":"source template id","type":"varchar","nul":true},{"id":"f_allow_anonymous","n":"f_allow_anonymous","disn":"allow anonymous","type":"bool"},{"id":"f_start_time","n":"f_start_time","disn":"start time","type":"datetime","nul":true},{"id":"f_end_time","n":"f_end_time","disn":"end time","type":"datetime","nul":true},{"id":"f_max_submissions","n":"f_max_submissions","disn":"max submissions","type":"int","nul":true},{"id":"f_creator_id","n":"f_creator_id","disn":"creator id","type":"varchar","nul":true},{"id":"f_create_time","n":"f_create_time","disn":"create time","type":"datetime"},{"id":"f_update_time","n":"f_update_time","disn":"update time","type":"datetime","nul":true}],"ops":[{"id":"save","n":"保存问卷","type":"insert_or_update","sql":"INSERT INTO tb_survey (f_id, f_title, f_description, f_status, f_create_time) VALUES (@f_id, @f_title, @f_description, 0, NOW()) ON DUPLICATE KEY UPDATE f_title=@f_title, f_description=@f_description, f_update_time=NOW()"}],"mt":"2025-12-25T22:35:00.0000000Z"} \ No newline at end of file diff --git a/meta/apps/survey/menu/menu_my_surveys.json b/meta/apps/survey/menu/menu_my_surveys.json new file mode 100644 index 0000000000000000000000000000000000000000..20ca3dd13c63fb420479f185730b660d56157a29 --- /dev/null +++ b/meta/apps/survey/menu/menu_my_surveys.json @@ -0,0 +1,11 @@ +{ + "aid": "survey", + "id": "menu_my_surveys", + "pid": "menu_survey_root", + "t": "我的问卷", + "type": 0, + "icon": "home", + "path": "page_my_surveys", + "order": 1, + "childs": [] +} diff --git a/meta/apps/survey/menu/menu_records.json b/meta/apps/survey/menu/menu_records.json new file mode 100644 index 0000000000000000000000000000000000000000..f7afaebade7120d374ac01156e5c0978beb19450 --- /dev/null +++ b/meta/apps/survey/menu/menu_records.json @@ -0,0 +1,11 @@ +{ + "aid": "survey", + "id": "menu_records", + "pid": "", + "t": "填写记录", + "type": 0, + "icon": "file-text", + "path": "page_submission_records", + "order": 2, + "childs": [] +} diff --git a/meta/apps/survey/menu/menu_survey_root.json b/meta/apps/survey/menu/menu_survey_root.json new file mode 100644 index 0000000000000000000000000000000000000000..f19e1e7c4524d0c2414fad97b54641f14bd6cca3 --- /dev/null +++ b/meta/apps/survey/menu/menu_survey_root.json @@ -0,0 +1,11 @@ +{ + "aid": "survey", + "id": "menu_survey_root", + "pid": "", + "t": "问卷管理", + "type": 1, + "icon": "file-text", + "path": "", + "order": 1, + "childs": [] +} diff --git a/meta/apps/survey/menu/menu_templates.json b/meta/apps/survey/menu/menu_templates.json new file mode 100644 index 0000000000000000000000000000000000000000..030f1e49eefbc2e8143ef3e652769fb2f7a19bd0 --- /dev/null +++ b/meta/apps/survey/menu/menu_templates.json @@ -0,0 +1,11 @@ +{ + "aid": "survey", + "id": "menu_templates", + "pid": "menu_survey_root", + "t": "问卷模板", + "type": 0, + "icon": "template", + "path": "page_survey_templates", + "order": 2, + "childs": [] +} diff --git a/meta/apps/survey/page/page_my_surveys.json b/meta/apps/survey/page/page_my_surveys.json new file mode 100644 index 0000000000000000000000000000000000000000..f15689cd5c9a1768115572579fb81e44fa9f00ad --- /dev/null +++ b/meta/apps/survey/page/page_my_surveys.json @@ -0,0 +1 @@ +{"comps":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"placeholder","pt":1,"attrn":"Placeholder","attrt":"System.String","attrv":"Search survey"}]},{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用输入框","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":0},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""},{"disn":"是否显示清除按钮","pt":6,"desc":"显示清除按钮","dftval":false,"attrn":"AllowClear","attrt":"System.Boolean","attrv":false},{"disn":"只读","pt":6,"desc":"设置为只读状态","dftval":false,"attrn":"ReadOnly","attrt":"System.Boolean","attrv":false},{"disn":"验证状态","pt":1,"desc":"输入框的验证状态(success|warning|error|)","dftval":"","attrn":"Status","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"search_input","pid":"","n":"search","lb":"Search Input","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","t":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dst":1,"dsid":"ds_survey","dsv":"{\"tcols\":[],\"searchs\":[],\"tbtns\":[{\"id\":\"wpnm70fe\",\"n\":\"create\",\"t\":\"新增\",\"bt\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":10,\"etid\":\"page_survey_editor\",\"eta\":\"14\",\"eventArgs\":{},\"rowparams\":{}}]},{\"id\":\"2qsecnfo\",\"n\":\"deleteSelections\",\"t\":\"删除选中\",\"sptevs\":[\"OnClick\"]}],\"rbtns\":[{\"id\":\"delete_row\",\"n\":\"delete\",\"t\":\"删除\",\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":21,"pub":1,"mt":"2025-12-11T12:38:31.5219484Z","id":"cjsakm4k","pid":"root","n":"table_248","lb":"表格-A","hlb":true,"sptds":true,"stl":{"itemw":24,"itemh":300,"labelw":180},"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"survey","id":"page_my_surveys","n":"我的问卷","pt":2,"pageprop":{"playout":3,"ds":{"dsid":"ds_survey","dsn":"tb_survey"}},"ds":{},"mt":"2025-12-17T14:40:05.5414086Z"} \ No newline at end of file diff --git a/meta/apps/survey/page/page_submission_records.json b/meta/apps/survey/page/page_submission_records.json new file mode 100644 index 0000000000000000000000000000000000000000..08bb2f2cf1a425ec5925ce1dafacb205a43b5e13 --- /dev/null +++ b/meta/apps/survey/page/page_submission_records.json @@ -0,0 +1 @@ +{"comps":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"placeholder","pt":1,"attrn":"Placeholder","attrt":"System.String","attrv":"Search submitter name"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"search_submitter_input","pid":"","n":"search","lb":"Search Input","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"button","ct":1,"frag":{"dt":"AntDesign.Button, AntDesign","t":"AntDesign.Button, AntDesign","childs":[],"attrs":[]},"ds":{},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"text","pt":1,"attrn":"ChildContent","attrt":"System.String","attrv":"Export Records"},{"disn":"type","pt":1,"attrn":"Type","attrt":"System.String","attrv":"default"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":2,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"export_records_btn","pid":"","n":"export","lb":"Export Button","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"survey","id":"page_submission_records","n":"提交记录","order":3,"pt":2,"pageprop":{"playout":3,"ds":{"dsid":"ds_submission","dsn":"tb_submission"}},"ds":{},"mt":"2025-12-17T14:29:40.7218271Z"} \ No newline at end of file diff --git a/meta/apps/survey/page/page_survey_editor.json b/meta/apps/survey/page/page_survey_editor.json new file mode 100644 index 0000000000000000000000000000000000000000..ea5a369da1f1041644ee3820311b90d79742a760 --- /dev/null +++ b/meta/apps/survey/page/page_survey_editor.json @@ -0,0 +1,581 @@ +{ + "aid": "survey", + "id": "page_survey_editor", + "n": "问卷编辑", + "order": 1, + "pt": 1, + "sptevs": ["OnLoad"], + "pageprop": { + "playout": 3, + "ds": { + "dsid": "ds_survey", + "dsn": "tb_survey" + } + }, + "ds": { + "dst": 1, + "dsid": "ds_survey", + "dsn": "问卷表", + "dsv": "tb_survey" + }, + "comps": [ + { + "libid": "antdesign", + "partsId": "flex", + "ct": 1, + "frag": { + "dt": "AntDesign.Flex, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Style", + "attrt": "System.String", + "attrv": "height: 100%; flex-direction: column; gap: 16px; padding: 16px;" + } + ], + "content": "$(DraggableContainer)" + }, + "ds": {"dsgt": 1}, + "attrdefgroups": [], + "childs": [ + { + "libid": "antdesign", + "partsId": "flex", + "ct": 1, + "frag": { + "dt": "AntDesign.Flex, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Justify", + "attrt": "System.String", + "attrv": "end" + }, + { + "attrn": "Gap", + "attrt": "System.String", + "attrv": "16" + }, + { + "attrn": "Style", + "attrt": "System.String", + "attrv": "margin-bottom: 16px;" + } + ], + "content": "$(DraggableContainer)" + }, + "ds": {}, + "attrdefgroups": [], + "childs": [ + { + "libid": "antdesign", + "partsId": "button", + "ct": 1, + "frag": { + "dt": "AntDesign.Button, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Text", + "attrt": "System.String", + "attrv": "保存问卷" + }, + { + "attrn": "Type", + "attrt": "System.String", + "attrv": "primary" + } + ] + }, + "ds": {}, + "attrdefgroups": [], + "childs": [], + "evdefs": [ + { + "evn": "OnClick", + "evtype": 1, + "actions": [ + { + "actiontype": "DataSourceAction", + "dsaction": "Save", + "target": "ds_survey" + } + ] + } + ], + "evs": [ + { + "en": "OnClick", + "eht": 40, + "edat": 30, + "etid": "list_questions" + } + ], + "stydefs": [], + "id": "btn_save_survey", + "n": "btn_save_survey", + "order": 1, + "pub": 1 + } + ], + "evdefs": [], + "stydefs": [], + "id": "flex_actions", + "n": "flex_actions", + "order": 0, + "pub": 1, + "container": true + }, + { + "libid": "antdesign", + "partsId": "card", + "ct": 1, + "frag": { + "dt": "AntDesign.Card, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Title", + "attrt": "System.String", + "attrv": "问卷基本信息" + }, + { + "attrn": "Hoverable", + "attrt": "System.Boolean", + "attrv": false + } + ], + "content": "$(DraggableContainer)" + }, + "ds": {}, + "attrdefgroups": [], + "childs": [ + { + "libid": "antdesign", + "partsId": "flex", + "ct": 1, + "frag": { + "dt": "AntDesign.Flex, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Vertical", + "attrt": "System.Boolean", + "attrv": true + }, + { + "attrn": "Gap", + "attrt": "System.String", + "attrv": "16" + }, + { + "attrn": "Style", + "attrt": "System.String", + "attrv": "width: 100%;" + } + ], + "content": "$(DraggableContainer)" + }, + "ds": {}, + "attrdefgroups": [], + "childs": [ + { + "libid": "antdesign", + "partsId": "input", + "cn": "input", + "ct": 1, + "frag": { + "dt": "AntDesign.Input, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请输入问卷标题" + } + ] + }, + "ds": {}, + "attrdefgroups": [], + "childs": [], + "evdefs": [], + "stydefs": [], + "id": "input_survey_title", + "n": "input_survey_title", + "order": 1, + "pub": 1 + }, + { + "libid": "antdesign", + "partsId": "textarea", + "cn": "textarea", + "ct": 1, + "frag": { + "dt": "AntDesign.TextArea, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请输入问卷描述" + }, + { + "attrn": "Rows", + "attrt": "System.Int32", + "attrv": 3 + } + ] + }, + "ds": {}, + "attrdefgroups": [], + "childs": [], + "evdefs": [], + "stydefs": [], + "id": "textarea_survey_desc", + "n": "textarea_survey_desc", + "order": 2, + "pub": 1 + } + ], + "evdefs": [], + "stydefs": [], + "id": "flex_survey_info", + "n": "flex_survey_info", + "order": 1, + "pub": 1, + "container": true + } + ], + "evdefs": [], + "stydefs": [], + "id": "card_survey_info", + "n": "card_survey_info", + "order": 1, + "pub": 1, + "container": true + }, + { + "libid": "antdesign", + "partsId": "card", + "ct": 1, + "frag": { + "dt": "AntDesign.Card, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Title", + "attrt": "System.String", + "attrv": "问卷问题" + }, + { + "attrn": "Hoverable", + "attrt": "System.Boolean", + "attrv": false + } + ], + "content": "$(DraggableContainer)" + }, + "ds": {}, + "attrdefgroups": [], + "childs": [ + { + "libid": "antdesign", + "partsId": "list", + "cn": "list", + "ct": 1, + "frag": { + "dt": "AntDesign.List, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Style", + "attrt": "System.String", + "attrv": "width:100%; margin-bottom: 16px;" + } + ] + }, + "ds": { + "dsgt": 4, + "dst": 0, + "listds": { + "fxdata": [ + { + "f_id": "q1", + "f_survey_id": "survey_1", + "f_question_type": 1, + "f_title": "示例问题 1:您的性别?", + "f_description": "", + "f_is_required": true, + "f_order": 1, + "f_options_json": "[{\"Label\":\"男\",\"Value\":\"1\"},{\"Label\":\"女\",\"Value\":\"2\"}]" + }, + { + "f_id": "q2", + "f_survey_id": "survey_1", + "f_question_type": 2, + "f_title": "示例问题 2:您的兴趣爱好?(多选)", + "f_description": "可以选择多个选项", + "f_is_required": false, + "f_order": 2, + "f_options_json": "[{\"Label\":\"运动\",\"Value\":\"1\"},{\"Label\":\"阅读\",\"Value\":\"2\"},{\"Label\":\"音乐\",\"Value\":\"3\"},{\"Label\":\"美食\",\"Value\":\"4\"}]" + }, + { + "f_id": "q3", + "f_survey_id": "survey_1", + "f_question_type": 4, + "f_title": "示例问题 3:您对我们的服务有什么建议?", + "f_description": "请详细描述您的建议", + "f_is_required": false, + "f_order": 3, + "f_options_json": "[]" + } + ] + }, + "itemtpl": { + "id": "question_item", + "partsId": "card", + "ct": 1, + "frag": { + "dt": "AntDesign.Card, AntDesign", + "attrs": [ + {"attrn": "Style", "attrt": "System.String", "attrv": "margin-bottom: 16px;"} + ], + "childs": [ + { + "dt": "AntDesign.Flex, AntDesign", + "attrs": [ + {"attrn": "Vertical", "attrt": "System.Boolean", "attrv": true}, + {"attrn": "Gap", "attrt": "System.String", "attrv": "12"} + ], + "childs": [ + { + "dt": "AntDesign.Flex, AntDesign", + "attrs": [ + {"attrn": "Gap", "attrt": "System.String", "attrv": "16"}, + {"attrn": "Align", "attrt": "System.String", "attrv": "center"}, + {"attrn": "Justify", "attrt": "System.String", "attrv": "space-between"} + ], + "childs": [ + { + "dt": "AntDesign.Flex, AntDesign", + "attrs": [ + {"attrn": "Gap", "attrt": "System.String", "attrv": "12"}, + {"attrn": "Align", "attrt": "System.String", "attrv": "center"}, + {"attrn": "Style", "attrt": "System.String", "attrv": "flex: 1;"} + ], + "childs": [ + { + "dt": "AntDesign.Input, AntDesign", + "attrs": [ + {"attrn": "Value", "attrt": "System.String", "attrv": "$(item.f_title)"}, + {"attrn": "Placeholder", "attrt": "System.String", "attrv": "请输入问题标题"}, + {"attrn": "Style", "attrt": "System.String", "attrv": "flex: 1;"} + ] + }, + { + "dt": "AntDesign.Tag, AntDesign", + "attrs": [ + {"attrn": "Color", "attrt": "System.String", "attrv": "blue"} + ], + "content": "$(item.f_question_type)" + } + ] + }, + { + "dt": "AntDesign.Space, AntDesign", + "attrs": [ + {"attrn": "Size", "attrt": "System.String", "attrv": "small"} + ], + "childs": [ + { + "dt": "AntDesign.Button, AntDesign", + "attrs": [ + {"attrn": "Icon", "attrt": "System.String", "attrv": "up"}, + {"attrn": "Size", "attrt": "System.String", "attrv": "small"}, + {"attrn": "Type", "attrt": "System.String", "attrv": "text"} + ], + "evs": [{"en": "OnClick", "eht": 40, "edat": 70}] + }, + { + "dt": "AntDesign.Button, AntDesign", + "attrs": [ + {"attrn": "Icon", "attrt": "System.String", "attrv": "down"}, + {"attrn": "Size", "attrt": "System.String", "attrv": "small"}, + {"attrn": "Type", "attrt": "System.String", "attrv": "text"} + ], + "evs": [{"en": "OnClick", "eht": 40, "edat": 80}] + }, + { + "dt": "AntDesign.Button, AntDesign", + "attrs": [ + {"attrn": "Icon", "attrt": "System.String", "attrv": "copy"}, + {"attrn": "Size", "attrt": "System.String", "attrv": "small"}, + {"attrn": "Type", "attrt": "System.String", "attrv": "text"} + ], + "evs": [{"en": "OnClick", "eht": 40, "edat": 90}] + }, + { + "dt": "AntDesign.Button, AntDesign", + "attrs": [ + {"attrn": "Icon", "attrt": "System.String", "attrv": "delete"}, + {"attrn": "Size", "attrt": "System.String", "attrv": "small"}, + {"attrn": "Type", "attrt": "System.String", "attrv": "text"}, + {"attrn": "Danger", "attrt": "System.Boolean", "attrv": true} + ], + "evs": [{"en": "OnClick", "eht": 40, "edat": 20}] + } + ] + } + ] + }, + { + "dt": "AntDesign.Text, AntDesign", + "attrs": [ + {"attrn": "Type", "attrt": "System.String", "attrv": "secondary"} + ], + "content": "$(item.f_description)" + } + ] + } + ] + }, + "cases": { + "1": { + "id": "case_radio", + "partsId": "text", + "ct": 1, + "frag": { + "dt": "AntDesign.Text, AntDesign", + "attrs": [ + {"attrn": "Type", "attrt": "System.String", "attrv": "secondary"} + ], + "content": "单选题类型" + } + }, + "2": { + "id": "case_checkbox", + "partsId": "text", + "ct": 1, + "frag": { + "dt": "AntDesign.Text, AntDesign", + "attrs": [ + {"attrn": "Type", "attrt": "System.String", "attrv": "secondary"} + ], + "content": "多选题类型" + } + }, + "3": { + "id": "case_input", + "partsId": "input", + "ct": 1, + "frag": { + "dt": "AntDesign.Input, AntDesign", + "attrs": [ + {"attrn": "Placeholder", "attrt": "System.String", "attrv": "请输入答案"}, + {"attrn": "Disabled", "attrt": "System.Boolean", "attrv": true} + ] + } + }, + "4": { + "id": "case_textarea", + "partsId": "textarea", + "ct": 1, + "frag": { + "dt": "AntDesign.TextArea, AntDesign", + "attrs": [ + {"attrn": "Placeholder", "attrt": "System.String", "attrv": "请输入详细内容"}, + {"attrn": "Rows", "attrt": "System.Int32", "attrv": 3}, + {"attrn": "Disabled", "attrt": "System.Boolean", "attrv": true} + ] + } + } + }, + "default": { + "id": "case_default", + "partsId": "input", + "ct": 1, + "frag": { + "dt": "AntDesign.Input, AntDesign", + "attrs": [ + {"attrn": "Placeholder", "attrt": "System.String", "attrv": "请输入答案"}, + {"attrn": "Disabled", "attrt": "System.Boolean", "attrv": true} + ] + } + } + } + }, + "attrdefgroups": [], + "childs": [], + "evdefs": [], + "stydefs": [], + "id": "list_questions", + "n": "list_questions", + "order": 1, + "pub": 1, + "sptds": true + }, + { + "libid": "antdesign", + "partsId": "button", + "ct": 1, + "frag": { + "dt": "AntDesign.Button, AntDesign", + "childs": [], + "attrs": [ + { + "attrn": "Text", + "attrt": "System.String", + "attrv": "+ 添加新问题" + }, + { + "attrn": "Type", + "attrt": "System.String", + "attrv": "dashed" + }, + { + "attrn": "Block", + "attrt": "System.Boolean", + "attrv": true + } + ] + }, + "ds": {}, + "attrdefgroups": [], + "childs": [], + "evdefs": [], + "stydefs": [], + "evs": [ + { + "en": "OnClick", + "eht": 40, + "edat": 50, + "etid": "list_questions" + } + ], + "id": "btn_add_question", + "n": "btn_add_question", + "order": 2, + "pub": 1 + } + ], + "evdefs": [], + "stydefs": [], + "id": "card_questions", + "n": "card_questions", + "order": 2, + "pub": 1, + "container": true + } + ], + "evdefs": [], + "stydefs": [], + "id": "flex_main", + "n": "flex_main", + "order": 32, + "pub": 1, + "container": true, + "lb": "问卷编辑主布局" + } + ], + "mt": "2025-12-18T23:10:00.0000000Z" +} diff --git a/meta/apps/survey/page/page_survey_fill.json b/meta/apps/survey/page/page_survey_fill.json new file mode 100644 index 0000000000000000000000000000000000000000..be5114c2ce7a4da49daf8d3abf0db600238ab6df --- /dev/null +++ b/meta/apps/survey/page/page_survey_fill.json @@ -0,0 +1 @@ +{"comps":[{"libid":"antdesign","partsId":"card","ct":1,"frag":{"dt":"AntDesign.Card, AntDesign","t":"AntDesign.Card, AntDesign","childs":[],"attrs":[]},"ds":{},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"title","pt":1,"attrn":"Title","attrt":"System.String","attrv":"Survey Questions"}]},{"gn":"基础属性","attrdefs":[{"disn":"标题","pt":1,"desc":"卡片标题","dftval":"","attrn":"Title","attrt":"System.String"},{"disn":"尺寸","pt":1,"desc":"卡片尺寸","dftval":"Default","attrn":"Size","attrt":"AntDesign.CardSize"},{"disn":"显示边框","pt":6,"desc":"是否显示边框","dftval":true,"attrn":"Bordered","attrt":"System.Boolean"},{"disn":"悬浮效果","pt":6,"desc":"鼠标悬浮时是否显示阴影","dftval":false,"attrn":"Hoverable","attrt":"System.Boolean"},{"disn":"加载状态","pt":6,"desc":"是否显示加载状态","dftval":false,"attrn":"Loading","attrt":"System.Boolean"}]},{"gn":"样式属性","attrdefs":[{"disn":"自定义样式","pt":1,"desc":"自定义CSS样式","dftval":"","attrn":"Style","attrt":"System.String"},{"disn":"内容区样式","pt":1,"desc":"卡片内容区域的自定义样式","dftval":"","attrn":"BodyStyle","attrt":"System.String"},{"disn":"头部样式","pt":1,"desc":"卡片头部的自定义样式","dftval":"","attrn":"HeadStyle","attrt":"System.String"}]}],"childs":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"placeholder","pt":1,"attrn":"Placeholder","attrt":"System.String","attrv":"Your answer"}]},{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用输入框","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":0},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""},{"disn":"是否显示清除按钮","pt":6,"desc":"显示清除按钮","dftval":false,"attrn":"AllowClear","attrt":"System.Boolean","attrv":false},{"disn":"只读","pt":6,"desc":"设置为只读状态","dftval":false,"attrn":"ReadOnly","attrt":"System.Boolean","attrv":false},{"disn":"验证状态","pt":1,"desc":"输入框的验证状态(success|warning|error|)","dftval":"","attrn":"Status","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"fill_answer1","pid":"fill_card","n":"q1_answer","lb":"Question 1 Answer","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"textarea","ct":1,"frag":{"dt":"AntDesign.TextArea, AntDesign","t":"AntDesign.TextArea, AntDesign","childs":[],"attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"placeholder","pt":1,"attrn":"Placeholder","attrt":"System.String","attrv":"Your detailed answer"}]},{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"禁用文本框","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":0},{"disn":"输入提示","pt":1,"desc":"文本框的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""},{"disn":"是否显示清除按钮","pt":6,"desc":"显示清除按钮","dftval":false,"attrn":"AllowClear","attrt":"System.Boolean","attrv":false},{"disn":"只读","pt":6,"desc":"设置为只读状态","dftval":false,"attrn":"ReadOnly","attrt":"System.Boolean","attrv":false}]},{"gn":"样式属性","attrdefs":[{"disn":"行数","pt":2,"desc":"文本框的行数","dftval":4,"attrn":"Rows","attrt":"System.Int32","attrv":4},{"disn":"显示计数","pt":6,"desc":"显示字符计数","dftval":false,"attrn":"ShowCount","attrt":"System.Boolean","attrv":false},{"disn":"边框样式","pt":6,"desc":"是否有边框","dftval":true,"attrn":"Bordered","attrt":"System.Boolean","attrv":true}]}],"childs":[],"evdefs":[],"stydefs":[],"order":2,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"fill_answer2","pid":"fill_card","n":"q2_answer","lb":"Question 2 Answer","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"}],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"fill_card","pid":"","n":"survey_fill","lb":"Fill Survey","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"survey","id":"page_survey_fill","n":"问卷填写","order":2,"pt":1,"pageprop":{"playout":1,"ds":{"dsid":"ds_survey","dsn":"tb_survey"}},"ds":{},"mt":"2025-12-20T13:58:53.9725347Z"} \ No newline at end of file diff --git a/meta/apps/survey/page/page_survey_templates.json b/meta/apps/survey/page/page_survey_templates.json new file mode 100644 index 0000000000000000000000000000000000000000..86d1d4ea7bb958a8ae2b8df83852589875a3cbfb --- /dev/null +++ b/meta/apps/survey/page/page_survey_templates.json @@ -0,0 +1 @@ +{"comps":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{"dsgt":1},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"placeholder","pt":1,"attrn":"Placeholder","attrt":"System.String","attrv":"Search template"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"search_template_input","pid":"","n":"search","lb":"Search Input","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"},{"libid":"antdesign","partsId":"button","ct":1,"frag":{"dt":"AntDesign.Button, AntDesign","t":"AntDesign.Button, AntDesign","childs":[],"attrs":[]},"ds":{},"attrdefgroups":[{"gn":"basic","attrdefs":[{"disn":"text","pt":1,"attrn":"ChildContent","attrt":"System.String","attrv":"Use Template"},{"disn":"type","pt":1,"attrn":"Type","attrt":"System.String","attrv":"primary"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":2,"pub":1,"mt":"2025-12-17T00:00:00Z","id":"use_template_btn","pid":"","n":"use_button","lb":"Use Template","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"survey","id":"page_survey_templates","n":"问卷模板","order":7,"pt":2,"pageprop":{"playout":3,"ds":{"dsid":"ds_survey","dsn":"tb_survey"}},"ds":{},"mt":"2025-12-17T14:29:20.2111906Z"} \ No newline at end of file diff --git a/meta/apps/survey/survey.json b/meta/apps/survey/survey.json new file mode 100644 index 0000000000000000000000000000000000000000..4c8df76056ef1c95b92834c4bec3b78e4c884eb4 --- /dev/null +++ b/meta/apps/survey/survey.json @@ -0,0 +1 @@ +{"id":"survey","n":"问卷系统","desc":"支持问卷创建、编辑、分发和数据收集的低代码平台应用","order":3,"platform":[0],"mt":"2025-12-16T14:30:00.000Z"} diff --git a/meta/apps/testapp/page/g0qcqxzd.json b/meta/apps/testapp/page/g0qcqxzd.json index 1f9b5e3992934cb8198894751e18588c3701d47d..c53b8e086d2d52014840825578b7966d7355db31 100644 --- a/meta/apps/testapp/page/g0qcqxzd.json +++ b/meta/apps/testapp/page/g0qcqxzd.json @@ -1 +1 @@ -{"comps":[],"aid":"testapp","id":"g0qcqxzd","n":"页面11","pageprop":{"playout":2,"ds":{}},"ds":{},"mt":"2025-05-26T15:29:01.5525837Z"} \ No newline at end of file +{"comps":[{"libid":"antdesign","partsId":"input","ct":1,"frag":{"dt":"AntDesign.Input`1[System.String], AntDesign","t":"AntDesign.Input`1[System.String], AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"TValue","attrt":"System.String"}]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"是否禁用","pt":6,"desc":"","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"最大长度","pt":2,"desc":"字段输入的最大长度,为0时表示不限制长度","dftval":0,"attrn":"MaxLength","attrt":"System.Int32","attrv":0},{"disn":"输入提示","pt":1,"desc":"组件输入时的 Placeholder 提示","dftval":"","attrn":"Placeholder","attrt":"System.String","attrv":""}]}],"childs":[],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-12-11T12:58:52.0236835Z","id":"358xv0sq","pid":"root","n":"input_819","lb":"输入框-A","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"}],"sptevs":["OnLoad"],"aid":"testapp","id":"g0qcqxzd","n":"页面11","pageprop":{"playout":2,"ds":{}},"ds":{},"mt":"2025-12-12T15:00:52.8115166Z"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/antdesign.json b/meta/parts/componentParts/antdesign/antdesign.json index 1951a5d122b3167c3c91e8bf4c2c88a779ca181a..9c2c2ad6a3860f883d03b9dab0ec892287c7a211 100644 --- a/meta/parts/componentParts/antdesign/antdesign.json +++ b/meta/parts/componentParts/antdesign/antdesign.json @@ -1 +1,8 @@ -{"libid":"antdesign","libname":"antdesign","desc":"antdesign 风格的基础组件库","platform":[0],"mt":"2025-10-12T12:12:29.9587419Z"} \ No newline at end of file +{ + "libid": "antdesign", + "libname": "AntDesign", + "desc": "antdesign 风格的基础组件库", + "pub": 1, + "platform": [0], + "mt": "2025-12-26T00:00:00.0000000Z" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/autocomplete.json b/meta/parts/componentParts/antdesign/autocomplete.json index e1cb8580152417be246e4ed21d7977c2ac82446e..cfa7df5fdfb5386d05889629544fc8c140ae8705 100644 --- a/meta/parts/componentParts/antdesign/autocomplete.json +++ b/meta/parts/componentParts/antdesign/autocomplete.json @@ -1 +1,102 @@ -{"compid":"autocomplete","libid":"antdesign","cn":"AutoComplete","ct":1,"frag":{"dt":"AntDesign.AutoComplete\u00601[System.String], AntDesign","valt":"System.String","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"order":18,"pub":1,"mt":"2025-03-22T15:55:52.1413161Z","id":"pqxzqsh2","lb":"自动完成-A","sptds":true,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{}} \ No newline at end of file +{ + "libid": "antdesign", + "partsId": "autocomplete", + "ct": 1, + "frag": { + "dt": "AntDesign.AutoComplete`1[System.String], AntDesign", + "childs": [], + "valt": "System.String", + "attrs": [] + }, + "ds": { + "dsgt": 1 + }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用自动完成", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "输入提示", + "pt": 1, + "desc": "自动完成的 Placeholder 提示", + "dftval": "请输入", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请输入" + } + ] + }, + { + "gn": "高级属性", + "attrdefs": [ + { + "disn": "选中时回填", + "pt": 6, + "desc": "选中选项后,是否回填输入框", + "dftval": true, + "attrn": "BackfillOnSelect", + "attrt": "System.Boolean", + "attrv": true + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "自动完成大小", + "pt": 1, + "desc": "自动完成大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], + "childs": [], + "evdefs": [ + + ], + "stydefs": [], + "order": 16, + "pub": 1, + "mt": "2025-12-11T22:45:00Z", + "id": "pqxzqsh2", + "lb": "自动完成-A", + "sptds": true, + "stl": { + "itemw": 4, + "itemh": 85, + "labelw": 180 + }, + "v": "0.0.2" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/button.json b/meta/parts/componentParts/antdesign/button.json index d59fe3637d76f63c95e62249b9db2c15967a98e6..bcac26478094dfddc49756b6a85aa3e51346e969 100644 --- a/meta/parts/componentParts/antdesign/button.json +++ b/meta/parts/componentParts/antdesign/button.json @@ -1 +1 @@ -{"compid":"button","libid":"antdesign","cn":"Button","ct":1,"frag":{"dt":"AntDesign.Button, AntDesign","valt":"System.String","attrs":[{"attrn":"Text","attrt":"System.String"},{"attrn":"Type","attrt":"System.String"}]},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"按钮文字","pt":1,"desc":"按钮显示的文本内容","dftval":"按钮","attrn":"Text","attrt":"System.String","attrv":"按钮"},{"disn":"按钮类型","pt":3,"desc":"按钮的样式类型","dftval":"default","attrn":"Type","attrt":"System.String","attrv":"default"},{"disn":"是否禁用","pt":6,"desc":"是否禁用按钮","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"加载状态","pt":6,"desc":"按钮是否显示加载状态","dftval":false,"attrn":"Loading","attrt":"System.Boolean","attrv":false}]}],"childs":[],"evdefs":[{"en":"OnClick","disn":"点击事件","desc":"按钮被点击时触发的事件"}],"order":15,"pub":1,"mt":"2025-11-17T10:00:00.0000000Z","id":"button_parts","lb":"按钮-A","sptds":false,"container":false,"stl":{"itemh":50,"labelw":180,"display":"inline","pos":"static"},"ev":{}} \ No newline at end of file +{"libid":"antdesign","partsId":"button","ct":1,"frag":{"dt":"AntDesign.Button, AntDesign","childs":[],"valt":"System.String","attrs":[{"attrn":"Text","attrt":"System.String"},{"attrn":"Type","attrt":"System.String"}]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"按钮文字","pt":1,"desc":"按钮显示的文本内容","dftval":"按钮","attrn":"Text","attrt":"System.String","attrv":"按钮"},{"disn":"按钮类型","pt":3,"desc":"按钮的样式类型","dftval":"default","attrn":"Type","attrt":"System.String","attrv":"default"},{"disn":"是否禁用","pt":6,"desc":"是否禁用按钮","dftval":false,"attrn":"Disabled","attrt":"System.Boolean","attrv":false},{"disn":"加载状态","pt":6,"desc":"按钮是否显示加载状态","dftval":false,"attrn":"Loading","attrt":"System.Boolean","attrv":false}]}],"childs":[],"evdefs":[{"en":"OnClick","disn":"点击事件","desc":"按钮被点击时触发的事件"}],"stydefs":[],"order":41,"pub":1,"mt":"2025-12-11T13:02:02.0445359Z","id":"button_parts","lb":"按钮-A","stl":{"itemw":4,"itemh":50,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/card.json b/meta/parts/componentParts/antdesign/card.json index 5141ae1e193fc24b136e2ad3ee2d36212e7048c9..2588eb3bf9180b8cc44d5a0a0415e8f69da2fd15 100644 --- a/meta/parts/componentParts/antdesign/card.json +++ b/meta/parts/componentParts/antdesign/card.json @@ -1,104 +1 @@ -{ - "cn": "Card", - "ct": 1, - "frag": { - "dt": "AntDesign.Card, AntDesign", - "attrs": [] - }, - "attrdefgroups": [ - { - "gn": "基础属性", - "attrdefs": [ - { - "attrn": "Title", - "disn": "标题", - "attrt": "System.String", - "dftval": "", - "desc": "卡片标题", - "pt": 1 - }, - { - "attrn": "Size", - "disn": "尺寸", - "attrt": "AntDesign.CardSize", - "dftval": "Default", - "desc": "卡片尺寸", - "pt": 1 - }, - { - "attrn": "Bordered", - "disn": "显示边框", - "attrt": "System.Boolean", - "dftval": true, - "desc": "是否显示边框", - "pt": 6 - }, - { - "attrn": "Hoverable", - "disn": "悬浮效果", - "attrt": "System.Boolean", - "dftval": false, - "desc": "鼠标悬浮时是否显示阴影", - "pt": 6 - }, - { - "attrn": "Loading", - "disn": "加载状态", - "attrt": "System.Boolean", - "dftval": false, - "desc": "是否显示加载状态", - "pt": 6 - } - ] - }, - { - "gn": "样式属性", - "attrdefs": [ - { - "attrn": "Style", - "disn": "自定义样式", - "attrt": "System.String", - "dftval": "", - "desc": "自定义CSS样式", - "pt": 1 - }, - { - "attrn": "BodyStyle", - "disn": "内容区样式", - "attrt": "System.String", - "dftval": "", - "desc": "卡片内容区域的自定义样式", - "pt": 1 - }, - { - "attrn": "HeadStyle", - "disn": "头部样式", - "attrt": "System.String", - "dftval": "", - "desc": "卡片头部的自定义样式", - "pt": 1 - } - ] - } - ], - "childs": [], - "sptds": false, - "order": 34, - "pub": 1, - "mt": "2025-03-05T15:32:20.4958136Z", - "id": "12nblk6r", - "libid": "antdesign", - "compid": "card", - "lb": "卡片-A", - "container": false, - "stl": { - "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" - }, - "ev": {}, - "ds": { - "dst": 0 - } -} \ No newline at end of file +{"libid":"antdesign","partsId":"card","ct":1,"frag":{"dt":"AntDesign.Card, AntDesign","childs":[],"attrs":[]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"标题","pt":1,"desc":"卡片标题","dftval":"","attrn":"Title","attrt":"System.String"},{"disn":"尺寸","pt":1,"desc":"卡片尺寸","dftval":"Default","attrn":"Size","attrt":"AntDesign.CardSize"},{"disn":"显示边框","pt":6,"desc":"是否显示边框","dftval":true,"attrn":"Bordered","attrt":"System.Boolean"},{"disn":"悬浮效果","pt":6,"desc":"鼠标悬浮时是否显示阴影","dftval":false,"attrn":"Hoverable","attrt":"System.Boolean"},{"disn":"加载状态","pt":6,"desc":"是否显示加载状态","dftval":false,"attrn":"Loading","attrt":"System.Boolean"}]},{"gn":"样式属性","attrdefs":[{"disn":"自定义样式","pt":1,"desc":"自定义CSS样式","dftval":"","attrn":"Style","attrt":"System.String"},{"disn":"内容区样式","pt":1,"desc":"卡片内容区域的自定义样式","dftval":"","attrn":"BodyStyle","attrt":"System.String"},{"disn":"头部样式","pt":1,"desc":"卡片头部的自定义样式","dftval":"","attrn":"HeadStyle","attrt":"System.String"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":23,"pub":1,"mt":"2025-12-11T13:03:30.0823969Z","id":"12nblk6r","lb":"卡片-A","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/cascader.json b/meta/parts/componentParts/antdesign/cascader.json index 460b18f7d56ef6913a2a9dccdb44ec3422294cb2..544464bb99fa1083542a56c549b51f016bf9a484 100644 --- a/meta/parts/componentParts/antdesign/cascader.json +++ b/meta/parts/componentParts/antdesign/cascader.json @@ -1 +1,120 @@ -{"libid":"antdesign","compid":"cascader","ct":1,"frag":{"dt":"AntDesign.Cascader, AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"pub":1,"mt":"2025-11-21T17:03:58.9571236Z","id":"vwbvub2r","lb":"级联选择-A","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file +{ + "libid": "antdesign", + "partsId": "cascader", + "ct": 1, + "frag": { + "dt": "AntDesign.Cascader, AntDesign", + "childs": [], + "valt": "System.String", + "attrs": [] + }, + "ds": { + "dsgt": 1 + }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用级联选择", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "显示搜索框", + "pt": 6, + "desc": "在下拉菜单中显示搜索框", + "dftval": false, + "attrn": "ShowSearch", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "输入提示", + "pt": 1, + "desc": "级联选择的 Placeholder 提示", + "dftval": "请选择", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请选择" + } + ] + }, + { + "gn": "高级属性", + "attrdefs": [ + { + "disn": "多选模式", + "pt": 6, + "desc": "支持多选模式", + "dftval": false, + "attrn": "Multiple", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "变更时触发父级", + "pt": 6, + "desc": "当一个选项改变时,父选项是否也受影响", + "dftval": false, + "attrn": "ChangeOnSelect", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "级联选择大小", + "pt": 1, + "desc": "级联选择大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], + "childs": [], + "evdefs": [ + + ], + "stydefs": [], + "order": 17, + "pub": 1, + "mt": "2025-12-11T22:45:00Z", + "id": "vwbvub2r", + "lb": "级联选择-A", + "sptds": true, + "stl": { + "itemw": 4, + "itemh": 85, + "labelw": 180 + }, + "v": "0.0.2" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/checkbox.json b/meta/parts/componentParts/antdesign/checkbox.json index 2623350469466f9d11e642b3b87d53a7510fc868..2ad5175c8f14bc0c3f84691b035a527a7fa84639 100644 --- a/meta/parts/componentParts/antdesign/checkbox.json +++ b/meta/parts/componentParts/antdesign/checkbox.json @@ -1,16 +1,17 @@ -{ - "compid": "checkbox", +{ "libid": "antdesign", - "cn": "Checkbox", + "partsId": "checkbox", "ct": 1, "frag": { - "dt": "AntDesign.CheckboxGroup\u00601[System.String], AntDesign", + "dt": "AntDesign.CheckboxGroup`1[System.String], AntDesign", + "childs": [], "valt": "System.String[]", "attrs": [] }, "ds": { "dsfrag": { "t": "AntDesign.Checkbox, AntDesign", + "childs": [], "attrs": [ { "attrn": "Label" @@ -19,19 +20,51 @@ }, "dsgt": 1 }, - "attrdefgroups": [], + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用复选框组", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "复选框方向", + "pt": 1, + "desc": "排列方向(horizontal|vertical)", + "dftval": "horizontal", + "attrn": "Direction", + "attrt": "System.String", + "attrv": "horizontal" + } + ] + } + ], "childs": [], - "order": 14, + "evdefs": [ + + ], + "stydefs": [], + "order": 3, "pub": 1, - "mt": "2025-03-23T08:24:39.8300016Z", + "mt": "2025-12-11T22:45:00Z", "id": "epurwzyy", "lb": "复选框-A", "sptds": true, "stl": { + "itemw": 4, "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" + "labelw": 180 }, - "ev": {} + "v": "0.0.2" } \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/datepicker.json b/meta/parts/componentParts/antdesign/datepicker.json index d6f8523d3f09ddb28da1df50ae6bad75791d5147..998a70d1928a2b4052be1830060f8cab3237b513 100644 --- a/meta/parts/componentParts/antdesign/datepicker.json +++ b/meta/parts/componentParts/antdesign/datepicker.json @@ -1,27 +1,112 @@ -{ - "cn": "DatePicker", +{ + "libid": "antdesign", + "partsId": "datepicker", "ct": 1, "frag": { - "dt": "AntDesign.DatePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign", - "valt": "System.Nullable\u00601[System.DateTime]", + "dt": "AntDesign.DatePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", "attrs": [] }, - "attrdefgroups": [], + "ds": {}, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用日期选择器", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "输入提示", + "pt": 1, + "desc": "日期选择器的 Placeholder 提示", + "dftval": "请选择日期", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请选择日期" + } + ] + }, + { + "gn": "格式属性", + "attrdefs": [ + { + "disn": "日期格式", + "pt": 1, + "desc": "日期格式字符串,例如yyyy-MM-dd", + "dftval": "yyyy-MM-dd", + "attrn": "Format", + "attrt": "System.String", + "attrv": "yyyy-MM-dd" + }, + { + "disn": "选择器类型", + "pt": 1, + "desc": "选择器类型(date|month|year|week)", + "dftval": "date", + "attrn": "Picker", + "attrt": "System.String", + "attrv": "date" + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "日期选择器大小", + "pt": 1, + "desc": "日期选择器大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], "childs": [], - "sptds": false, - "order": 15, + "sptevs": [ + "OnClick", + "OnExpand" + ], + "evdefs": [ + + ], + "stydefs": [], + "order": 7, "pub": 1, - "mt": "2025-02-24T15:59:32.6799272Z", + "mt": "2025-12-11T22:45:00Z", "id": "xrckidu5", - "libid": "antdesign", - "compid": "datepicker", "lb": "日期选择器-A", - "container": false, "stl": { + "itemw": 4, "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" + "labelw": 180 }, - "sptevs": ["OnClick", "OnExpand"] + "v": "0.0.2" } \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/flex.json b/meta/parts/componentParts/antdesign/flex.json index 8f5c9a365e8f0652e8c9155133e0ce13a9514a8a..37185de89a2aed4793971c2a9558b4da4b2a5756 100644 --- a/meta/parts/componentParts/antdesign/flex.json +++ b/meta/parts/componentParts/antdesign/flex.json @@ -1 +1 @@ -{"libid":"antdesign","compid":"flex","ct":1,"frag":{"dt":"AntDesign.Flex, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"height:100%;"}],"content":"$(DraggableContainer)"},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":1,"pub":1,"mt":"2025-11-22T13:10:54.9227361Z","id":"7d2lne5o","lb":"Flex 布局-A","container":true,"stl":{"itemw":24,"itemh":85,"labelw":180,"dfstl":"height: 200px;"},"v":"0.0.1"} \ No newline at end of file +{"libid":"antdesign","partsId":"flex","ct":1,"frag":{"dt":"AntDesign.Flex, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"height:100%;"}],"content":"$(DraggableContainer)"},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":32,"pub":1,"mt":"2025-12-11T12:37:00.6328062Z","id":"7d2lne5o","lb":"Flex 布局-A","container":true,"stl":{"itemw":24,"itemh":85,"labelw":180,"dfstl":"height: 200px;"},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/grid.json b/meta/parts/componentParts/antdesign/grid.json index 095fc2ca89d25b14e3105c72e646e72d5ad252d3..f7960681d536c3c2df3cb8c54a565ef7893ebbe7 100644 --- a/meta/parts/componentParts/antdesign/grid.json +++ b/meta/parts/componentParts/antdesign/grid.json @@ -1 +1 @@ -{"libid":"antdesign","compid":"grid","ct":1,"frag":{"dt":"AntDesign.GridRow, AntDesign","childs":[{"dt":"AntDesign.GridCol, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:33.33%; height:100%;"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.GridCol, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:33.33%; height:100%;"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.GridCol, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:33.33%; height:100%;"}],"content":"$(DraggableContainer)"}],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"height:100%;"}]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":2,"pub":1,"mt":"2025-11-23T01:40:01.1069114Z","id":"2meifnfm","lb":"Grid 栅格-A","container":true,"stl":{"itemw":24,"itemh":85,"labelw":180,"dfstl":"height: 200px;"},"v":"0.0.1"} \ No newline at end of file +{"libid":"antdesign","partsId":"grid","ct":1,"frag":{"dt":"AntDesign.GridRow, AntDesign","childs":[{"dt":"AntDesign.GridCol, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:33.33%; height:100%;"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.GridCol, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:33.33%; height:100%;"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.GridCol, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:33.33%; height:100%;"}],"content":"$(DraggableContainer)"}],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"height:100%;"}]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":33,"pub":1,"mt":"2025-12-11T12:37:08.4478546Z","id":"2meifnfm","lb":"Grid 栅格-A","container":true,"stl":{"itemw":24,"itemh":85,"labelw":180,"dfstl":"height: 200px;"},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/image.json b/meta/parts/componentParts/antdesign/image.json index 07f61cb9b767750e44aad4597327cae096eb4b21..4bb265e48a0d9a3e5f46445918be39bf58cdcb81 100644 --- a/meta/parts/componentParts/antdesign/image.json +++ b/meta/parts/componentParts/antdesign/image.json @@ -1 +1 @@ -{"cn":"Image","ct":1,"frag":{"dt":"AntDesign.Image, AntDesign","valt":"System.String","attrs":[]},"attrdefgroups":[],"childs":[],"sptds":false,"order":26,"pub":1,"mt":"2025-03-05T15:31:51.2912846Z","id":"nuned6mm7","libid":"antdesign","compid":"image","lb":"图片-A","container":false,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{},"ds":{"dst":0}} \ No newline at end of file +{"libid":"antdesign","partsId":"image","ct":1,"frag":{"dt":"AntDesign.Image, AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":36,"pub":1,"mt":"2025-12-11T12:40:00.0717513Z","id":"nuned6mm7","lb":"图片-A","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/input.json b/meta/parts/componentParts/antdesign/input.json index c18dd46e1564231f34c568971e9f5ee2d576f538..29e2182c0b96fa3c95400c76067d0d0192f0beca 100644 --- a/meta/parts/componentParts/antdesign/input.json +++ b/meta/parts/componentParts/antdesign/input.json @@ -1,8 +1,10 @@ -{ - "cn": "Input", +{ + "libid": "antdesign", + "partsId": "input", "ct": 1, "frag": { - "dt": "AntDesign.Input\u00601[System.String], AntDesign", + "dt": "AntDesign.Input`1[System.String], AntDesign", + "childs": [], "valt": "System.String", "attrs": [ { @@ -11,6 +13,7 @@ } ] }, + "ds": {}, "attrdefgroups": [ { "gn": "基础属性", @@ -18,15 +21,15 @@ { "disn": "是否禁用", "pt": 6, - "desc": "", + "desc": "禁用输入框", "dftval": false, "attrn": "Disabled", "attrt": "System.Boolean", "attrv": false }, { - "pt": 2, "disn": "最大长度", + "pt": 2, "desc": "字段输入的最大长度,为0时表示不限制长度", "dftval": 0, "attrn": "MaxLength", @@ -34,31 +37,56 @@ "attrv": 0 }, { - "pt": 1, "disn": "输入提示", + "pt": 1, "desc": "组件输入时的 Placeholder 提示", "dftval": "", "attrn": "Placeholder", "attrt": "System.String", "attrv": "" + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "只读", + "pt": 6, + "desc": "设置为只读状态", + "dftval": false, + "attrn": "ReadOnly", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "验证状态", + "pt": 1, + "desc": "输入框的验证状态(success|warning|error|)", + "dftval": "", + "attrn": "Status", + "attrt": "System.String", + "attrv": "" } ] } ], "childs": [], - "sptds": false, - "order": 10, + "evdefs": [], + "stydefs": [], + "order": 1, "pub": 1, - "mt": "2025-02-24T15:36:15.8037414Z", + "mt": "2025-12-11T22:45:00Z", "id": "cj8ac3m42", - "libid": "antdesign", - "compid": "input", "lb": "输入框-A", - "container": false, "stl": { + "itemw": 4, "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" - } + "labelw": 180 + }, + "v": "0.0.2" } \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/inputnumber.json b/meta/parts/componentParts/antdesign/inputnumber.json index b3f05525f5fdd8297e8957129db57883f8c111de..42cc1b38e46b12a8b95aabb5ffc21a8690a28d0a 100644 --- a/meta/parts/componentParts/antdesign/inputnumber.json +++ b/meta/parts/componentParts/antdesign/inputnumber.json @@ -1,30 +1,110 @@ -{ - "cn": "InputNumber", +{ + "libid": "antdesign", + "partsId": "inputnumber", "ct": 1, "frag": { - "dt": "AntDesign.InputNumber\u00601[System.Int32], AntDesign", + "dt": "AntDesign.InputNumber`1[System.Int32], AntDesign", + "childs": [], "valt": "System.Int32", "attrs": [] }, - "attrdefgroups": [], + "ds": { + "dsgt": 1 + }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用数字输入框", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "数值范围", + "attrdefs": [ + { + "disn": "最小值", + "pt": 2, + "desc": "数字输入框的最小值", + "dftval": 0, + "attrn": "Min", + "attrt": "System.Int32", + "attrv": 0 + }, + { + "disn": "最大值", + "pt": 2, + "desc": "数字输入框的最大值", + "dftval": 0, + "attrn": "Max", + "attrt": "System.Int32", + "attrv": 0 + }, + { + "disn": "步长", + "pt": 2, + "desc": "每次增加或减少的步长", + "dftval": 1, + "attrn": "Step", + "attrt": "System.Int32", + "attrv": 1 + }, + { + "disn": "精度", + "pt": 2, + "desc": "小数点后的位数", + "dftval": 0, + "attrn": "Precision", + "attrt": "System.Int32", + "attrv": 0 + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "数字输入框大小", + "pt": 1, + "desc": "数字输入框大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], "childs": [], - "sptds": false, - "order": 11, + "evdefs": [ + + ], + "stydefs": [], + "order": 12, "pub": 1, - "mt": "2025-02-24T15:36:33.0043266Z", + "mt": "2025-12-11T22:45:00Z", "id": "wymxwrfpw", - "libid": "antdesign", - "compid": "inputnumber", "lb": "数字输入框-A", - "container": false, "stl": { + "itemw": 4, "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" + "labelw": 180 }, - "ev": {}, - "ds": { - "dsgt": 1 - } + "v": "0.0.2" } \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/layout.json b/meta/parts/componentParts/antdesign/layout.json index 6086b326b0baa45180005920d45d6a3ea5a669a6..1e8ecce26b2ef4e534f36ca908aea0202fd94f0f 100644 --- a/meta/parts/componentParts/antdesign/layout.json +++ b/meta/parts/componentParts/antdesign/layout.json @@ -1,56 +1 @@ -{ - "compid": "layout", - "libid": "antdesign", - "cn": "Layout", - "ct": 1, - "frag": { - "dt": "AntDesign.Layout, AntDesign", - "childs": [ - { - "dt": "AntDesign.Sider, AntDesign", - "attrs": [ - { - "attrn": "Style", - "attrt": "System.String", - "attrv": "background: #f4f7fa; height:100%;" - } - ], - "content": "$(DraggableContainer)" - }, - { - "dt": "AntDesign.Content, AntDesign", - "attrs": [ - { - "attrn": "Style", - "attrt": "System.String", - "attrv": "height: 100%;" - } - ], - "content": "$(DraggableContainer)" - } - ], - "attrs": [ - { - "attrn": "Style", - "attrt": "System.String", - "attrv": "height:100%;" - } - ] - }, - "ds": {}, - "attrdefgroups": [], - "childs": [], - "order": 3, - "pub": 1, - "mt": "2025-04-26T07:33:07.231997Z", - "id": "phzwohoq", - "lb": "Layout 布局-A", - "container": true, - "stl": { - "itemw": 24, - "itemh": 85, - "dfstl": "height:100%;", - "labelw": 180 - }, - "ev": {} -} \ No newline at end of file +{"libid":"antdesign","partsId":"layout","ct":1,"frag":{"dt":"AntDesign.Layout, AntDesign","childs":[{"dt":"AntDesign.Sider, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"background: #f4f7fa; height:100%;"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.Content, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"height: 100%;"}],"content":"$(DraggableContainer)"}],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"height:100%;"}]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":31,"pub":1,"mt":"2025-12-11T12:36:51.947495Z","id":"phzwohoq","lb":"Layout 布局-A","container":true,"stl":{"itemw":24,"itemh":85,"labelw":180,"dfstl":"height:100%;"},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/list.json b/meta/parts/componentParts/antdesign/list.json index b948c6b4e4d7579e87ff3f011715940c77de28d0..b9c154be5e60b4a853a3286f2f10e67b8b10027a 100644 --- a/meta/parts/componentParts/antdesign/list.json +++ b/meta/parts/componentParts/antdesign/list.json @@ -1 +1 @@ -{"libid":"antdesign","compid":"list","ct":1,"frag":{"dt":"AntDesign.List, AntDesign","childs":[{"dt":"AntDesign.ListItem, AntDesign","childs":[],"attrs":[],"content":"$(DraggableContainer)"}],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:100%;"}]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":35,"pub":1,"mt":"2025-11-22T09:55:42.369244Z","id":"lbemleqn","lb":"列表-A","container":true,"stl":{"itemw":24,"itemh":200,"labelw":180},"v":"0.0.1"} \ No newline at end of file +{"libid":"antdesign","partsId":"list","ct":1,"frag":{"dt":"AntDesign.List, AntDesign","childs":[],"attrs":[{"attrn":"Style","attrt":"System.String","attrv":"width:100%;"}]},"ds":{"dsgt":4},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":38,"pub":1,"mt":"2025-12-25T14:20:00.000Z","id":"lbemleqn","lb":"列表-A","container":true,"sptds":true,"stl":{"itemw":24,"itemh":200,"labelw":180},"v":"0.0.2"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/radio.json b/meta/parts/componentParts/antdesign/radio.json index fe3208d29ea760528d2f4d79fb8105926ee0b498..48f7e16a1fc71b43b126a66311632bd73fe60e3b 100644 --- a/meta/parts/componentParts/antdesign/radio.json +++ b/meta/parts/componentParts/antdesign/radio.json @@ -1,10 +1,10 @@ -{ - "compid": "radio", +{ "libid": "antdesign", - "cn": "Radio", + "partsId": "radio", "ct": 1, "frag": { - "dt": "AntDesign.RadioGroup\u00601[System.String], AntDesign", + "dt": "AntDesign.RadioGroup`1[System.String], AntDesign", + "childs": [], "valt": "System.String", "attrs": [ { @@ -15,7 +15,8 @@ }, "ds": { "dsfrag": { - "t": "AntDesign.Radio\u00601[System.String], AntDesign", + "t": "AntDesign.Radio`1[System.String], AntDesign", + "childs": [], "attrs": [ { "attrn": "Value" @@ -24,19 +25,69 @@ }, "dsgt": 1 }, - "attrdefgroups": [], + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用单选框组", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "使用按钮样式", + "pt": 6, + "desc": "以按钮形式显示单选框", + "dftval": false, + "attrn": "OptionType", + "attrt": "System.String", + "attrv": "" + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "单选框大小", + "pt": 1, + "desc": "单选框大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "单选框方向", + "pt": 1, + "desc": "排列方向(horizontal|vertical)", + "dftval": "horizontal", + "attrn": "Direction", + "attrt": "System.String", + "attrv": "horizontal" + } + ] + } + ], "childs": [], - "order": 13, + "evdefs": [ + + ], + "stydefs": [], + "order": 2, "pub": 1, - "mt": "2025-03-23T07:26:31.4273273Z", + "mt": "2025-12-11T22:45:00Z", "id": "lkmww2hq", "lb": "单选框-A", "sptds": true, "stl": { + "itemw": 4, "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" + "labelw": 180 }, - "ev": {} + "v": "0.0.2" } \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/select.json b/meta/parts/componentParts/antdesign/select.json index 50b9a7f67ad3c02432d12ddd00f3872193e48dc5..84d9207c53522539b141a123fdd6ea0578ff290b 100644 --- a/meta/parts/componentParts/antdesign/select.json +++ b/meta/parts/componentParts/antdesign/select.json @@ -1 +1,111 @@ -{"compid":"select","libid":"antdesign","cn":"Select","ct":1,"frag":{"dt":"AntDesign.Select\u00602[[System.String],[System.String]], antdesign","valt":"System.String","attrs":[]},"ds":{"dsgt":1},"attrdefgroups":[],"childs":[],"order":17,"pub":1,"mt":"2025-03-22T15:55:39.4807842Z","id":"76b2alet3","lb":"选择器-A","sptds":true,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{}} \ No newline at end of file +{ + "libid": "antdesign", + "partsId": "select", + "ct": 1, + "frag": { + "dt": "AntDesign.Select`2[[System.String],[System.String]], antdesign", + "childs": [], + "valt": "System.String", + "attrs": [] + }, + "ds": { + "dsgt": 1 + }, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用选择器", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "显示搜索框", + "pt": 6, + "desc": "在下拉菜单中显示搜索框", + "dftval": false, + "attrn": "ShowSearch", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "输入提示", + "pt": 1, + "desc": "选择器的 Placeholder 提示", + "dftval": "请选择", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请选择" + } + ] + }, + { + "gn": "高级属性", + "attrdefs": [ + { + "disn": "选择模式", + "pt": 1, + "desc": "选择模式(single|multiple|tags)", + "dftval": "single", + "attrn": "Mode", + "attrt": "System.String", + "attrv": "single" + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "选择器大小", + "pt": 1, + "desc": "选择器大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], + "childs": [], + "evdefs": [ + + ], + "stydefs": [], + "order": 11, + "pub": 1, + "mt": "2025-12-11T22:45:00Z", + "id": "76b2alet3", + "lb": "选择器-A", + "sptds": true, + "stl": { + "itemw": 4, + "itemh": 85, + "labelw": 180 + }, + "v": "0.0.2" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/switch.json b/meta/parts/componentParts/antdesign/switch.json index 625c1ea1ce869d0cf37115aa038884c9610b6d9e..ed16c55c4bdf0205b3f412708aec394f822bc8bc 100644 --- a/meta/parts/componentParts/antdesign/switch.json +++ b/meta/parts/componentParts/antdesign/switch.json @@ -1 +1,85 @@ -{"cn":"Switch","ct":1,"frag":{"dt":"AntDesign.Switch, AntDesign","valt":"System.Boolean","attrs":[]},"attrdefgroups":[],"childs":[],"sptds":false,"order":19,"pub":1,"mt":"2025-03-05T15:31:40.4314786Z","id":"eouljwau","libid":"antdesign","compid":"switch","lb":"开关-A","container":false,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{},"ds":{"dst":0}} \ No newline at end of file +{ + "libid": "antdesign", + "partsId": "switch", + "ct": 1, + "frag": { + "dt": "AntDesign.Switch, AntDesign", + "childs": [], + "valt": "System.Boolean", + "attrs": [] + }, + "ds": {}, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用开关", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "加载状态", + "pt": 6, + "desc": "加载状态中的开关", + "dftval": false, + "attrn": "Loading", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "未选中文字", + "pt": 1, + "desc": "未选中时显示的文字", + "dftval": "", + "attrn": "UnCheckedChildren", + "attrt": "System.String", + "attrv": "" + }, + { + "disn": "选中文字", + "pt": 1, + "desc": "选中时显示的文字", + "dftval": "", + "attrn": "CheckedChildren", + "attrt": "System.String", + "attrv": "" + }, + { + "disn": "开关大小", + "pt": 1, + "desc": "开关大小(small|default)", + "dftval": "default", + "attrn": "Size", + "attrt": "System.String", + "attrv": "default" + } + ] + } + ], + "childs": [], + "evdefs": [ + + ], + "stydefs": [], + "order": 13, + "pub": 1, + "mt": "2025-12-11T22:45:00Z", + "id": "eouljwau", + "lb": "开关-A", + "stl": { + "itemw": 4, + "itemh": 85, + "labelw": 180 + }, + "v": "0.0.2" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/table.json b/meta/parts/componentParts/antdesign/table.json index fa058555d10103a6866b0b4af827c04e128d77d1..4084c5e167991bcdfa02709fe05c07501ab9de3f 100644 --- a/meta/parts/componentParts/antdesign/table.json +++ b/meta/parts/componentParts/antdesign/table.json @@ -1,28 +1 @@ -{ - "compid": "table", - "libid": "antdesign", - "cn": "Table", - "ct": 1, - "frag": { - "dt": "H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults" - }, - "attrdefgroups": [], - "childs": [], - "order": 30, - "pub": 1, - "mt": "2025-05-22T14:26:07.7475675Z", - "id": "4jf7nbak", - "lb": "表格-A", - "hlb": true, - "sptds": true, - "ds": { - "dsgt":2, - "dsv": "{\"tbtns\":[{\"id\":\"wpnm70fe\",\"n\":\"create\",\"t\":\"新增\",\"bt\":1,\"tgId\":\"xxx\"},{\"id\":\"2qsecnfo\",\"n\":\"deleteSelections\",\"t\":\"删除选中\",\"tgId\":\"xxx\"}],\"rbtns\":[{\"id\":\"delete_row\",\"n\":\"delete\",\"t\":\"删除\",\"bt\":0,\"disabled\":false,\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]}]}" - }, - "stl": { - "itemw": 24, - "itemh": 300, - "labelw": 180 - }, - "ev": {} -} \ No newline at end of file +{"libid":"antdesign","partsId":"table","ct":1,"frag":{"dt":"H.LowCode.Components.Defaults.LcTable, H.LowCode.Components.Defaults","childs":[],"attrs":[]},"ds":{"dsgt":2,"dsv":"{\"tbtns\":[{\"id\":\"wpnm70fe\",\"n\":\"create\",\"t\":\"新增\",\"bt\":1,\"tgId\":\"xxx\"},{\"id\":\"2qsecnfo\",\"n\":\"deleteSelections\",\"t\":\"删除选中\",\"tgId\":\"xxx\"}],\"rbtns\":[{\"id\":\"delete_row\",\"n\":\"delete\",\"t\":\"删除\",\"bt\":0,\"disabled\":false,\"order\":1,\"sptevs\":[\"OnClick\"],\"evs\":[{\"en\":\"OnClick\",\"eht\":40,\"edat\":20}]}]}"},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":21,"pub":1,"mt":"2025-12-11T12:38:31.5219484Z","id":"4jf7nbak","lb":"表格-A","hlb":true,"sptds":true,"stl":{"itemw":24,"itemh":300,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/tabs.json b/meta/parts/componentParts/antdesign/tabs.json index 990183c9aa59966b8a81cbf0034d42d3a579474d..8648bb938b4f2750e22b1aa0deb0bd68cf1b561f 100644 --- a/meta/parts/componentParts/antdesign/tabs.json +++ b/meta/parts/componentParts/antdesign/tabs.json @@ -1 +1 @@ -{"compid":"tabs","libid":"antdesign","cn":"Tabs","ct":1,"frag":{"dt":"AntDesign.Tabs, AntDesign","childs":[{"dt":"AntDesign.TabPane, AntDesign","childs":[],"attrs":[{"attrn":"Key","attrt":"System.String","attrv":"tab1"},{"attrn":"Tab","attrt":"System.String","attrv":"标签页1"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.TabPane, AntDesign","childs":[],"attrs":[{"attrn":"Key","attrt":"System.String","attrv":"tab2"},{"attrn":"Tab","attrt":"System.String","attrv":"标签页2"}],"content":"$(DraggableContainer)"}],"attrs":[]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"默认激活标签","pt":1,"desc":"默认激活的标签页键值","dftval":"tab1","attrn":"DefaultActiveKey","attrt":"System.String"},{"disn":"标签位置","pt":1,"desc":"标签页的位置","dftval":"Top","attrn":"TabPosition","attrt":"AntDesign.TabPosition"},{"disn":"标签大小","pt":1,"desc":"标签页的大小","dftval":"Default","attrn":"Size","attrt":"AntDesign.TabSize"},{"disn":"是否动画","pt":6,"desc":"是否使用动画效果","dftval":true,"attrn":"Animated","attrt":"System.Boolean"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":33,"pub":1,"mt":"2025-10-18T13:14:02.3929554Z","id":"iu1nxkgtk","lb":"标签页-A","hlb":true,"stl":{"itemw":4,"itemh":200,"labelw":180}} \ No newline at end of file +{"libid":"antdesign","partsId":"tabs","ct":1,"frag":{"dt":"AntDesign.Tabs, AntDesign","childs":[{"dt":"AntDesign.TabPane, AntDesign","childs":[],"attrs":[{"attrn":"Key","attrt":"System.String","attrv":"tab1"},{"attrn":"Tab","attrt":"System.String","attrv":"标签页1"}],"content":"$(DraggableContainer)"},{"dt":"AntDesign.TabPane, AntDesign","childs":[],"attrs":[{"attrn":"Key","attrt":"System.String","attrv":"tab2"},{"attrn":"Tab","attrt":"System.String","attrv":"标签页2"}],"content":"$(DraggableContainer)"}],"attrs":[]},"ds":{},"attrdefgroups":[{"gn":"基础属性","attrdefs":[{"disn":"默认激活标签","pt":1,"desc":"默认激活的标签页键值","dftval":"tab1","attrn":"DefaultActiveKey","attrt":"System.String"},{"disn":"标签位置","pt":1,"desc":"标签页的位置","dftval":"Top","attrn":"TabPosition","attrt":"AntDesign.TabPosition"},{"disn":"标签大小","pt":1,"desc":"标签页的大小","dftval":"Default","attrn":"Size","attrt":"AntDesign.TabSize"},{"disn":"是否动画","pt":6,"desc":"是否使用动画效果","dftval":true,"attrn":"Animated","attrt":"System.Boolean"}]}],"childs":[],"evdefs":[],"stydefs":[],"order":22,"pub":1,"mt":"2025-12-11T13:03:18.4639637Z","id":"iu1nxkgtk","lb":"标签页-A","hlb":true,"stl":{"itemw":4,"itemh":200,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/textarea.json b/meta/parts/componentParts/antdesign/textarea.json index 3b7ba528506c1212ecc6038c44339f099e9d3a37..4b5237cedf8a48f04f064c9ba8b8f64ab46ad697 100644 --- a/meta/parts/componentParts/antdesign/textarea.json +++ b/meta/parts/componentParts/antdesign/textarea.json @@ -1,27 +1,112 @@ -{ - "cn": "TextArea", +{ + "libid": "antdesign", + "partsId": "textarea", "ct": 1, "frag": { "dt": "AntDesign.TextArea, AntDesign", + "childs": [], "valt": "System.String", "attrs": [] }, - "attrdefgroups": [], + "ds": {}, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用文本框", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "最大长度", + "pt": 2, + "desc": "字段输入的最大长度,为0时表示不限制长度", + "dftval": 0, + "attrn": "MaxLength", + "attrt": "System.Int32", + "attrv": 0 + }, + { + "disn": "输入提示", + "pt": 1, + "desc": "文本框的 Placeholder 提示", + "dftval": "", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "" + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "只读", + "pt": 6, + "desc": "设置为只读状态", + "dftval": false, + "attrn": "ReadOnly", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "行数", + "pt": 2, + "desc": "文本框的行数", + "dftval": 4, + "attrn": "Rows", + "attrt": "System.Int32", + "attrv": 4 + }, + { + "disn": "显示计数", + "pt": 6, + "desc": "显示字符计数", + "dftval": false, + "attrn": "ShowCount", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], "childs": [], - "sptds": false, - "order": 12, + "evdefs": [ + + ], + "stydefs": [], + "order": 8, "pub": 1, - "mt": "2025-02-24T15:36:40.7389762Z", + "mt": "2025-12-11T22:45:00Z", "id": "dtqhqbmc", - "libid": "antdesign", - "compid": "textarea", "lb": "文本框-A", - "container": false, "stl": { - "itemh": 85, - "labelw": 180, - "display": "inline", - "pos": "static" + "itemw": 4, + "itemh": 150, + "labelw": 180 }, - "ev": {} + "v": "0.0.2" } \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/timepicker.json b/meta/parts/componentParts/antdesign/timepicker.json index b55cc32c4dfd030decad80c810e3b780de0392c7..dbbc90f425cd18cf8901055e37ae1aeb9d1a3e9f 100644 --- a/meta/parts/componentParts/antdesign/timepicker.json +++ b/meta/parts/componentParts/antdesign/timepicker.json @@ -1 +1,99 @@ -{"cn":"TimePicker","ct":1,"frag":{"dt":"AntDesign.TimePicker\u00601[[System.Nullable\u00601[[System.DateTime]]]], AntDesign","valt":"System.Nullable\u00601[System.DateTime]","attrs":[]},"attrdefgroups":[],"childs":[],"sptds":false,"order":16,"pub":1,"mt":"2025-03-05T15:31:24.9654966Z","id":"sbvdck2o","libid":"antdesign","compid":"timepicker","lb":"时间选择器-A","container":false,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{},"ds":{"dst":0}} \ No newline at end of file +{ + "libid": "antdesign", + "partsId": "timepicker", + "ct": 1, + "frag": { + "dt": "AntDesign.TimePicker`1[[System.Nullable`1[[System.DateTime]]]], AntDesign", + "childs": [], + "valt": "System.Nullable`1[System.DateTime]", + "attrs": [] + }, + "ds": {}, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用时间选择器", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "是否显示清除按钮", + "pt": 6, + "desc": "显示清除按钮", + "dftval": false, + "attrn": "AllowClear", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "输入提示", + "pt": 1, + "desc": "时间选择器的 Placeholder 提示", + "dftval": "请选择时间", + "attrn": "Placeholder", + "attrt": "System.String", + "attrv": "请选择时间" + } + ] + }, + { + "gn": "格式属性", + "attrdefs": [ + { + "disn": "时间格式", + "pt": 1, + "desc": "时间格式字符串,例如HH:mm:ss", + "dftval": "HH:mm:ss", + "attrn": "Format", + "attrt": "System.String", + "attrv": "HH:mm:ss" + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "时间选择器大小", + "pt": 1, + "desc": "时间选择器大小(large|middle|small)", + "dftval": "middle", + "attrn": "Size", + "attrt": "System.String", + "attrv": "middle" + }, + { + "disn": "边框样式", + "pt": 6, + "desc": "是否有边框", + "dftval": true, + "attrn": "Bordered", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], + "childs": [], + "evdefs": [ + + ], + "stydefs": [], + "order": 6, + "pub": 1, + "mt": "2025-12-11T22:45:00Z", + "id": "sbvdck2o", + "lb": "时间选择器-A", + "stl": { + "itemw": 4, + "itemh": 85, + "labelw": 180 + }, + "v": "0.0.2" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/tree.json b/meta/parts/componentParts/antdesign/tree.json index ad8b35b1a77f927ac2196899016e2cae67dbf20f..d569f56ffdf467500786eb7199c6c14013f6274f 100644 --- a/meta/parts/componentParts/antdesign/tree.json +++ b/meta/parts/componentParts/antdesign/tree.json @@ -1 +1,109 @@ -{"compid":"tree","libid":"antdesign","cn":"Tree","ct":1,"frag":{"dt":"AntDesign.Tree\u00601[System.String], AntDesign","valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"order":31,"pub":1,"mt":"2025-03-23T11:02:45.2781898Z","id":"hepj4qcm","lb":"树-A","sptds":true,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{}} \ No newline at end of file +{ + "libid": "antdesign", + "partsId": "tree", + "ct": 1, + "frag": { + "dt": "AntDesign.Tree`1[System.String], AntDesign", + "childs": [], + "valt": "System.String", + "attrs": [] + }, + "ds": {}, + "attrdefgroups": [ + { + "gn": "基础属性", + "attrdefs": [ + { + "disn": "是否禁用", + "pt": 6, + "desc": "禁用树组件", + "dftval": false, + "attrn": "Disabled", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "显示图标", + "pt": 6, + "desc": "在节点前显示文件类型图标", + "dftval": false, + "attrn": "ShowIcon", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "可选择", + "pt": 6, + "desc": "节点是否可选择", + "dftval": false, + "attrn": "Checkable", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "高级属性", + "attrdefs": [ + { + "disn": "多选模式", + "pt": 6, + "desc": "支持多选", + "dftval": false, + "attrn": "Multiple", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "默认全部展开", + "pt": 6, + "desc": "是否默认展开所有树节点", + "dftval": false, + "attrn": "DefaultExpandAll", + "attrt": "System.Boolean", + "attrv": false + }, + { + "disn": "节点可拖拽", + "pt": 6, + "desc": "节点是否可以拖拽", + "dftval": false, + "attrn": "Draggable", + "attrt": "System.Boolean", + "attrv": false + } + ] + }, + { + "gn": "样式属性", + "attrdefs": [ + { + "disn": "块级样式", + "pt": 6, + "desc": "将树设置为块级元素,宽度为100%", + "dftval": false, + "attrn": "BlockNode", + "attrt": "System.Boolean", + "attrv": false + } + ] + } + ], + "childs": [], + "evdefs": [ + + ], + "stydefs": [], + "order": 18, + "pub": 1, + "mt": "2025-12-11T22:45:00Z", + "id": "hepj4qcm", + "lb": "树-A", + "sptds": true, + "stl": { + "itemw": 4, + "itemh": 300, + "labelw": 180 + }, + "v": "0.0.2" +} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/treeselect.json b/meta/parts/componentParts/antdesign/treeselect.json index 7e663bd3d82462f0abb1d2ba817464faa64e9e34..96ed5a129f310348a84c956ff238c4a7d8832937 100644 --- a/meta/parts/componentParts/antdesign/treeselect.json +++ b/meta/parts/componentParts/antdesign/treeselect.json @@ -1 +1 @@ -{"compid":"treeselect","libid":"antdesign","cn":"TreeSelect","ct":1,"frag":{"dt":"AntDesign.TreeSelect\u00602[[System.String], [System.String]], AntDesign","valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"order":32,"pub":1,"mt":"2025-03-23T11:02:57.0710744Z","id":"jtx10vsi","lb":"树选择-A","sptds":true,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{}} \ No newline at end of file +{"libid":"antdesign","partsId":"treeselect","ct":1,"frag":{"dt":"AntDesign.TreeSelect`2[[System.String], [System.String]], AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":38,"pub":1,"mt":"2025-12-11T13:02:39.8614772Z","id":"jtx10vsi","lb":"树选择-A","sptds":true,"stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/antdesign/upload.json b/meta/parts/componentParts/antdesign/upload.json index 56feec8bfa5998edd97c980b75a56507b6e68673..248960f8895515614b517de84c5e80eaab6a74c1 100644 --- a/meta/parts/componentParts/antdesign/upload.json +++ b/meta/parts/componentParts/antdesign/upload.json @@ -1 +1 @@ -{"cn":"Upload","ct":1,"frag":{"dt":"AntDesign.Upload, AntDesign","valt":"System.String","attrs":[]},"attrdefgroups":[],"childs":[],"sptds":false,"order":25,"pub":1,"mt":"2025-03-05T15:31:46.5454492Z","id":"35r8zuv0e","libid":"antdesign","compid":"upload","lb":"上传-A","container":false,"stl":{"itemh":85,"labelw":180,"display":"inline","pos":"static"},"ev":{},"ds":{"dst":0}} \ No newline at end of file +{"libid":"antdesign","partsId":"upload","ct":1,"frag":{"dt":"AntDesign.Upload, AntDesign","childs":[],"valt":"System.String","attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"order":37,"pub":1,"mt":"2025-12-11T13:01:34.7791041Z","id":"35r8zuv0e","lb":"上传-A","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/common/common.json b/meta/parts/componentParts/common/common.json index 5607382204a1d1604aa97cac87ec5c32719ae9eb..2dc5e77736c517e6eb5398345f7ce2eacfa1ab29 100644 --- a/meta/parts/componentParts/common/common.json +++ b/meta/parts/componentParts/common/common.json @@ -1 +1,8 @@ -{"libid":"common","libname":"common","desc":"常用组件库,如行政区划、组织用户等","platform":[0],"mt":"2025-10-12T12:38:38.3811663Z"} \ No newline at end of file +{ + "libid": "common", + "libname": "通用组件", + "desc": "常用组件库,如条件渲染、行政区划、组织用户等", + "pub": 1, + "platform": [0], + "mt": "2025-12-26T00:00:00.0000000Z" +} \ No newline at end of file diff --git a/meta/parts/componentParts/common/conditional.json b/meta/parts/componentParts/common/conditional.json new file mode 100644 index 0000000000000000000000000000000000000000..ddee2ca285a4eb585744e2093a90c4671df77f60 --- /dev/null +++ b/meta/parts/componentParts/common/conditional.json @@ -0,0 +1,50 @@ +{ + "libid": "common", + "partsId": "conditional", + "lb": "条件分支", + "frag": { + "dt": "H.LowCode.Components.Defaults.Conditional, H.LowCode.Components.Defaults", + "childs": [], + "attrs": [ + { + "attrn": "ConditionValue", + "attrt": "System.Object" + }, + { + "attrn": "Visible", + "attrt": "System.Boolean", + "attrv": true + } + ] + }, + "ds": {}, + "attrdefgroups": [ + { + "gn": "条件配置", + "attrdefs": [ + { + "attrn": "ConditionValue", + "attrt": "System.Object" + }, + { + "attrn": "Visible", + "attrt": "System.Boolean", + "attrv": true + } + ] + } + ], + "childs": [], + "evdefs": [], + "stydefs": [], + "pub": 1, + "mt": "2025-12-26T16:15:04.0074557Z", + "id": "conditional_001", + "stl": { + "itemw": 4, + "itemh": 85, + "labelw": 180 + }, + "desc": "根据条件值动态渲染不同的子组件", + "v": "0.0.1" +} \ No newline at end of file diff --git a/meta/parts/componentParts/common/region.json b/meta/parts/componentParts/common/region.json index 970ad44996a1bd28c1cf7b0b15b3bb7a032e96b3..71e640b9f1330ce7892ae03f791714bdbbc5ded5 100644 --- a/meta/parts/componentParts/common/region.json +++ b/meta/parts/componentParts/common/region.json @@ -1,20 +1 @@ -{ - "compid": "region", - "libid": "common", - "cn": "region", - "ct": 2, - "ds": {}, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "mt": "2025-10-12T14:11:50.0909771Z", - "id": "76g2ae5m", - "n": "region", - "lb": "行政区划组件", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - } -} \ No newline at end of file +{"libid":"common","partsId":"region","ct":2,"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"mt":"2025-12-26T16:18:01.0435952Z","id":"76g2ae5m","n":"region","lb":"行政区划","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/meta/parts/componentParts/common/userselect.json b/meta/parts/componentParts/common/userselect.json index 7611852428fd6a075fa2ba46f0a755a59b3f7cbe..f5acc9997dad231fb6f574a2cc70122066aa2925 100644 --- a/meta/parts/componentParts/common/userselect.json +++ b/meta/parts/componentParts/common/userselect.json @@ -1,22 +1 @@ -{ - "compid": "userselect", - "libid": "common", - "cn": "userselect", - "ct": 2, - "frag": { - "attrs": [] - }, - "ds": {}, - "attrdefgroups": [], - "childs": [], - "evdefs": [], - "stydefs": [], - "mt": "2025-10-12T14:12:11.9143366Z", - "id": "t2f1qecpq", - "lb": "用户选择组件", - "stl": { - "itemw": 4, - "itemh": 85, - "labelw": 180 - } -} \ No newline at end of file +{"libid":"common","partsId":"userselect","ct":2,"frag":{"childs":[],"attrs":[]},"ds":{},"attrdefgroups":[],"childs":[],"evdefs":[],"stydefs":[],"mt":"2025-12-26T16:18:09.8035367Z","id":"t2f1qecpq","lb":"用户选择","stl":{"itemw":4,"itemh":85,"labelw":180},"v":"0.0.1"} \ No newline at end of file diff --git a/src/Common/H.LowCode.Application.Contracts/Dtos/TableDataInput.cs b/src/Common/H.LowCode.Application.Contracts/Dtos/TableDataInput.cs index 0d826e138e1503b111c08916cb0024ff2db94f81..1581925943664818324cdfe0b7fe9c036b7f4a21 100644 --- a/src/Common/H.LowCode.Application.Contracts/Dtos/TableDataInput.cs +++ b/src/Common/H.LowCode.Application.Contracts/Dtos/TableDataInput.cs @@ -11,20 +11,20 @@ public class TableDataInput : PagedAndSortedResultRequestDto /// /// 应用ID /// - public string AppId { get; set; } + public required string AppId { get; set; } /// /// 页面ID /// - public string PageId { get; set; } + public required string PageId { get; set; } /// /// 数据源ID /// - public string DataSourceId { get; set; } + public required string? DataSourceId { get; set; } /// /// 筛选条件 /// - public Dictionary Filters { get; set; } + public Dictionary? Filters { get; set; } } \ No newline at end of file diff --git a/src/Common/H.LowCode.Application/LowCodeApplicationModule.cs b/src/Common/H.LowCode.Application/LowCodeApplicationModule.cs index 8bf9cfa3fde0489d7945257d83966603d4c28ebd..31c920d534480521a661e2988ffc0185397a952f 100644 --- a/src/Common/H.LowCode.Application/LowCodeApplicationModule.cs +++ b/src/Common/H.LowCode.Application/LowCodeApplicationModule.cs @@ -8,6 +8,6 @@ public class LowCodeApplicationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddScoped(); + context.Services.AddTransient(); } } diff --git a/src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs b/src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs index 5dabc132fa00803e0cf2f7fb69afdef161db21a2..9bb4c8fde1bc65004879d0f6468955f85820c634 100644 --- a/src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs +++ b/src/Common/H.LowCode.ComponentBase/CascadingModels/PageCascadingModel.cs @@ -5,11 +5,11 @@ namespace H.LowCode.ComponentBase; public class PageCascadingModel { - public string AppId { get; set; } + public required string AppId { get; set; } - public string PageId { get; set; } + public required string PageId { get; set; } - public string PageName { get; set; } + public required string PageName { get; set; } /// /// 页面布局(1:一列、2:二列、3:三列、4:四列) diff --git a/src/Common/H.LowCode.ComponentBase/CascadingModels/PartsCascadingModel.cs b/src/Common/H.LowCode.ComponentBase/CascadingModels/PartsCascadingModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..b02509f96a031d3982ac6bc22e6edeaa3a69dc2b --- /dev/null +++ b/src/Common/H.LowCode.ComponentBase/CascadingModels/PartsCascadingModel.cs @@ -0,0 +1,12 @@ +using System; + +namespace H.LowCode.ComponentBase; + +public class PartsCascadingModel +{ + public required string LibraryId { get; set; } + + public required string PartsId { get; set; } + + public required string PartsName { get; set; } +} diff --git a/src/Common/H.LowCode.ComponentBase/H.LowCode.ComponentBase.csproj b/src/Common/H.LowCode.ComponentBase/H.LowCode.ComponentBase.csproj index f727529cc09a50c9335602390b0dcdcd49878cf3..e07262f33deb171cb2d53f6612cab1b7e0a1c056 100644 --- a/src/Common/H.LowCode.ComponentBase/H.LowCode.ComponentBase.csproj +++ b/src/Common/H.LowCode.ComponentBase/H.LowCode.ComponentBase.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs b/src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs index 3fb0806e3cf2098430540debeebdd8498b74a889..6da9e64038653b995acdb91617ab5f1d600c1d73 100644 --- a/src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs +++ b/src/Common/H.LowCode.ComponentBase/LowCodeComponentBase.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Components; +using AntDesign; +using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.WebUtilities; using System.Diagnostics.CodeAnalysis; using Volo.Abp.AspNetCore.Components; @@ -10,11 +11,11 @@ namespace H.LowCode.ComponentBase; /// public abstract class LowCodeComponentBase : AbpComponentBase { - [Inject] - private LowCodeAppState LowCodeAppState { get; set; } + [Inject] private LowCodeAppState LowCodeAppState { get; set; } - [Inject] - protected NavigationManager NavigationManager { get; set; } + [Inject] protected NavigationManager NavigationManager { get; set; } + + [Inject] protected new IMessageService Message { get; set; } /// /// 组件状态标识 (用于 ShouldRender 判断) diff --git a/src/Common/H.LowCode.ComponentBase/LowCodePageComponentBase.cs b/src/Common/H.LowCode.ComponentBase/LowCodePageComponentBase.cs index 0a5839d3d5d2c79e5fa19df3dfc27662be4e178d..0cf8e8f8056a62003583d81a1f37a0bfdf50db14 100644 --- a/src/Common/H.LowCode.ComponentBase/LowCodePageComponentBase.cs +++ b/src/Common/H.LowCode.ComponentBase/LowCodePageComponentBase.cs @@ -1,5 +1,5 @@ -using Microsoft.AspNetCore.Components; -using Microsoft.Extensions.Logging; +using AntDesign; +using Microsoft.AspNetCore.Components; namespace H.LowCode.ComponentBase; @@ -8,11 +8,18 @@ namespace H.LowCode.ComponentBase; /// public abstract class LowCodePageComponentBase : LowCodeComponentBase { + [Parameter] public string AppId { get; set; } + + [Inject] protected ISessionStorageService SessionStorageService { get; set; } + protected override async Task OnInitializedAsync() { - await base.OnInitializedAsync(); + if (!string.IsNullOrEmpty(AppId)) + { + await SessionStorageService.SetAsync("appid", AppId); + } - Logger.LogInformation($"渲染模式: {RendererInfo.Name}, path=/{NavigationManager.ToBaseRelativePath(NavigationManager.Uri)}"); + await base.OnInitializedAsync(); } protected static T GetQueryValue(string name) diff --git a/src/Common/H.LowCode.Components.Defaults/Components/Conditional.razor b/src/Common/H.LowCode.Components.Defaults/Components/Conditional.razor new file mode 100644 index 0000000000000000000000000000000000000000..1ec014d0888b5af537dc3ec97bc0a8bf577bfb29 --- /dev/null +++ b/src/Common/H.LowCode.Components.Defaults/Components/Conditional.razor @@ -0,0 +1,76 @@ +@namespace H.LowCode.Components.Defaults +@using Microsoft.AspNetCore.Components.Rendering + +@* + 条件渲染组件 - 平台层通用能力 + 根据 ConditionValue 匹配 Cases 中的条件,渲染对应的子内容 +*@ + +@if (MatchedContent != null) +{ + @MatchedContent +} +else if (DefaultContent != null) +{ + @DefaultContent +} + +@code { + /// + /// 条件值(用于匹配 Cases) + /// + [Parameter] + public object ConditionValue { get; set; } + + /// + /// 条件分支内容字典 + /// Key: 条件值(字符串形式) + /// Value: 对应的渲染内容 + /// + [Parameter] + public Dictionary Cases { get; set; } + + /// + /// 默认内容(当没有匹配的条件时显示) + /// + [Parameter] + public RenderFragment DefaultContent { get; set; } + + /// + /// 子内容(用于简单的显示/隐藏场景) + /// + [Parameter] + public RenderFragment ChildContent { get; set; } + + /// + /// 是否显示(用于简单的显示/隐藏场景) + /// + [Parameter] + public bool Visible { get; set; } = true; + + private RenderFragment MatchedContent + { + get + { + // 简单显示/隐藏模式 + if (Cases == null || Cases.Count == 0) + { + return Visible ? ChildContent : null; + } + + // 条件匹配模式 + if (ConditionValue == null) + { + return null; + } + + var key = ConditionValue.ToString(); + if (Cases.TryGetValue(key, out var content)) + { + return content; + } + + return null; + } + } +} diff --git a/src/Common/H.LowCode.Components.Defaults/Components/LcTable.razor b/src/Common/H.LowCode.Components.Defaults/Components/LcTable.razor index 24ad89a2deab9b5dc1b250a6625d83394cb8c1e5..f14e6cac8f80094e0504440e9a93b43a9ce6bbba 100644 --- a/src/Common/H.LowCode.Components.Defaults/Components/LcTable.razor +++ b/src/Common/H.LowCode.Components.Defaults/Components/LcTable.razor @@ -56,14 +56,17 @@ @code { + [CascadingParameter(Name = "pageCascading")] + public PageCascadingModel PageCascading { get; set; } + [Parameter] public ComponentDataSourceSchemaBase DataSource { get; set; } - [CascadingParameter(Name = "pageCascading")] - public PageCascadingModel PageCascading { get; set; } + [PersistentState] + public TablePropertySchema _tableSchema { get; set; } - private TablePropertySchema _tableSchema = new(); - private List> _data; + [PersistentState] + public List> _data { get; set; } IEnumerable> _selectedRows = []; ITable table; @@ -79,9 +82,28 @@ protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); + } + protected override async Task OnParametersSetAsync() + { + await base.OnParametersSetAsync(); + + // 确保所有必需的参数都已设置 + if (DataSource == null || PageCascading == null || string.IsNullOrEmpty(PageCascading.AppId)) + { + return; + } + + // 初始化 Schema Init(); - await LoadDataAsync(); + + // 检查持久化状态:如果 _data 为空,则需要加载 + // PersistentState 会在 SSR -> WebAssembly 切换时保持数据 + // 如果数据已存在(从 SSR 持久化过来),则跳过加载 + if (_data == null || _data.Count == 0) + { + await LoadDataAsync(); + } } protected override bool ShouldRender() @@ -89,12 +111,21 @@ //if (StateKey == DataSource.StateKey) // return false; - Init(); + // 参数变化时重新初始化 + if (DataSource != null) + { + Init(); + } return true; } private void Init() { + if (DataSource == null) + { + return; + } + _tableSchema = GetTableSchemaAsync(); StateKey = DataSource.StateKey; } @@ -113,7 +144,7 @@ private TablePropertySchema GetTableSchemaAsync() { var dataSource = DataSource?.DataSourceValue; - if (dataSource.IsNullOrWhiteSpace() || dataSource.Trim().Equals("[]")) + if (string.IsNullOrEmpty(dataSource) || dataSource.Trim().Equals("[]")) { var defaultTableSchema = new TablePropertySchema(); defaultTableSchema.Columns = new List() @@ -124,7 +155,7 @@ } var tableSchema = dataSource.FromJson(); - if(tableSchema.Columns.Any() == false) + if(tableSchema?.Columns != null && tableSchema.Columns.Any() == false) { tableSchema.Columns = new List() { @@ -132,8 +163,6 @@ }; } - Logger.LogWarning($"列表列头: {tableSchema.Columns.ToJson()}"); - return tableSchema; } @@ -141,9 +170,9 @@ { var request = new TableDataInput { - AppId = PageCascading?.AppId, - PageId = PageCascading?.PageId, - DataSourceId = DataSource?.DataSourceId, + AppId = PageCascading.AppId, + PageId = PageCascading.PageId, + DataSourceId = DataSource.DataSourceId, SkipCount = (_pageIndex - 1) * _pageSize, MaxResultCount = _pageSize, Filters = new Dictionary() diff --git a/src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs b/src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs index b34e3b03de93e96b820172811a31e516f20463d6..4627074b1fd89287f3a4582c31f808f1ead1700a 100644 --- a/src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs +++ b/src/Common/H.LowCode.MetaSchema.DesignEngine/ComponentPartsSchema.cs @@ -1,5 +1,7 @@ using H.Util.Ids; using System.Text.Json.Serialization; +using Volo.Abp.Validation; +using System.Linq; namespace H.LowCode.MetaSchema.DesignEngine; @@ -15,8 +17,8 @@ public class ComponentPartsSchema : ComponentSchemaBase /// 组件物料Id /// /// 一类组件唯一Id - [JsonPropertyName("compid")] - public required string ComponentId { get; set; } + [JsonPropertyName("partsId")] + public required string PartsId { get; set; } /// /// 组件类型:1-原子组件 2-组合组件 @@ -63,6 +65,20 @@ public class ComponentPartsSchema : ComponentSchemaBase [JsonPropertyName("stydefs")] public List StyleDefines { get; set; } = []; + /// + /// 条件分支配置(用于条件渲染组件) + /// Key: 条件值(字符串形式) + /// Value: 对应的子组件配置 + /// + [JsonPropertyName("cases")] + public Dictionary? Cases { get; set; } + + /// + /// 默认分支(当没有匹配的条件时渲染) + /// + [JsonPropertyName("default")] + public ComponentPartsSchema? DefaultCase { get; set; } + [JsonPropertyName("order")] public int Order { get; set; } @@ -83,6 +99,7 @@ public class ComponentPartsSchema : ComponentSchemaBase public ComponentDesignStateSchema DesignState { get; set; } = new(); [JsonIgnore] + [DisableValidation] public Action? Refresh { get; set; } public void RefreshState() @@ -99,7 +116,7 @@ public class ComponentPartsSchema : ComponentSchemaBase //Copy全新对象, Id 重新生成 newComponent.Id = ShortIdGenerator.Generate(); newComponent.ParentId = string.Empty; - newComponent.Name = $"{newComponent.ComponentId}_{Random.Shared.Next(100, 999)}"; + newComponent.Name = $"{newComponent.PartsId}_{Random.Shared.Next(100, 999)}"; newComponent.DesignState.IsSelected = false; //手动赋值无法序列化属性 @@ -147,37 +164,75 @@ public class ComponentPartsSchema : ComponentSchemaBase //基础属性合并 //this.Fragment = componentPartsDefine.Fragment; //this.Style = componentPartsDefine.Style; + this.IsHiddenLabel = componentPartsDefine.IsHiddenLabel; this.SupportEvents = componentPartsDefine.SupportEvents; //属性合并 - if (componentPartsDefine.AttributeDefineGroups != null) + MergeAttributeDefineGroups(componentPartsDefine.AttributeDefineGroups); + + //数据源合并 + this.IsSupportDataSource = componentPartsDefine.IsSupportDataSource; + if (componentPartsDefine?.DataSource?.DataSourceFragment != null) + this.DataSource.DataSourceFragment = componentPartsDefine.DataSource.DataSourceFragment; + } + + // 抽取的私有方法:合并 AttributeDefineGroups,存在则更新,不存在则新增 + private void MergeAttributeDefineGroups(IEnumerable? srcGroups) + { + if (srcGroups == null) + return; + + var currentGroups = this.AttributeDefineGroups?.ToList() ?? new List(); + + foreach (var srcGroup in srcGroups) { - foreach (var attrDefineGroup in componentPartsDefine.AttributeDefineGroups) + if (srcGroup == null || srcGroup.AttributeDefines == null) + continue; + + var targetGroup = currentGroups.FirstOrDefault(g => g.GroupName == srcGroup.GroupName); + + if (targetGroup == null) + { + // 新增整个分组(复制数组以避免引用同一实例) + var newGroup = new ComponentPartsAttributeDefineGroupSchema + { + GroupName = srcGroup.GroupName, + AttributeDefines = srcGroup.AttributeDefines.ToArray() + }; + + currentGroups.Add(newGroup); + } + else { - if(attrDefineGroup.AttributeDefines == null) - continue; - - foreach (var attrDefine in attrDefineGroup.AttributeDefines) + var targetAttrs = targetGroup.AttributeDefines?.ToList() ?? new List(); + + foreach (var srcAttr in srcGroup.AttributeDefines) { - var attr = this.AttributeDefineGroups.SelectMany(a => a.AttributeDefines) - .FirstOrDefault(a => a.AttributeName == attrDefine.AttributeName); + if (srcAttr == null) + continue; - if (attr != null) + var existingAttr = targetAttrs.FirstOrDefault(a => a.AttributeName == srcAttr.AttributeName); + if (existingAttr != null) { - attr.DisplayName = attrDefine.DisplayName; - attr.AttributeItemType = attrDefine.AttributeItemType; - attr.IsRequired = attrDefine.IsRequired; - attr.Description = attrDefine.Description; - attr.DefaultValue = attrDefine.DefaultValue; - attr.Options = attrDefine.Options; + existingAttr.DisplayName = srcAttr.DisplayName; + existingAttr.AttributeItemType = srcAttr.AttributeItemType; + //existingAttr.IsRequired = srcAttr.IsRequired; + existingAttr.Description = srcAttr.Description; + existingAttr.DefaultValue = srcAttr.DefaultValue; + existingAttr.Options = srcAttr.Options; + //existingAttr.IsValidationEnabled = srcAttr.IsValidationEnabled; + //existingAttr.ValidationRules = srcAttr.ValidationRules; + } + else + { + targetAttrs.Add(srcAttr); } } + + targetGroup.AttributeDefines = targetAttrs.ToArray(); } } - //数据源合并 - this.IsSupportDataSource = componentPartsDefine.IsSupportDataSource; - if (componentPartsDefine?.DataSource?.DataSourceFragment != null) - this.DataSource.DataSourceFragment = componentPartsDefine.DataSource.DataSourceFragment; + this.AttributeDefineGroups = currentGroups; } } \ No newline at end of file diff --git a/src/Common/H.LowCode.MetaSchema.DesignEngine/DataSourceSchemas/ComponentPartsDataSourceSchema.cs b/src/Common/H.LowCode.MetaSchema.DesignEngine/DataSourceSchemas/ComponentPartsDataSourceSchema.cs index 031a452ef2ea96ad57e0896867c36a44b91d3980..68ab9b7c44c5efd748d5b54bbf1d776d31a7d3c8 100644 --- a/src/Common/H.LowCode.MetaSchema.DesignEngine/DataSourceSchemas/ComponentPartsDataSourceSchema.cs +++ b/src/Common/H.LowCode.MetaSchema.DesignEngine/DataSourceSchemas/ComponentPartsDataSourceSchema.cs @@ -13,4 +13,10 @@ public class ComponentPartsDataSourceSchema : ComponentDataSourceSchemaBase /// [JsonPropertyName("dsfrag")] public ComponentPartsFragmentSchema? DataSourceFragment { get; set; } + + /// + /// 列表项模板(支持完整的组件配置,包括条件渲染) + /// + [JsonPropertyName("itemtpl")] + public ComponentPartsSchema? ItemTemplate { get; set; } } diff --git a/src/Common/H.LowCode.MetaSchema.DesignEngine/H.LowCode.MetaSchema.DesignEngine.csproj b/src/Common/H.LowCode.MetaSchema.DesignEngine/H.LowCode.MetaSchema.DesignEngine.csproj index a40d73f271cbc80e509d3d2eb81fc508a08ccf43..93b1d6f7317b930e13afa6089ed75a87b6c780f1 100644 --- a/src/Common/H.LowCode.MetaSchema.DesignEngine/H.LowCode.MetaSchema.DesignEngine.csproj +++ b/src/Common/H.LowCode.MetaSchema.DesignEngine/H.LowCode.MetaSchema.DesignEngine.csproj @@ -1,7 +1,11 @@  - + + + + + diff --git a/src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentFragmentEventSchema.cs b/src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentFragmentEventSchema.cs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentFragmentStyleSchema.cs b/src/Common/H.LowCode.MetaSchema.DesignEngine/PropertySchemas/ComponentFragmentStyleSchema.cs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs b/src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs index fd66932fd0f31b7384cac714dc3a2a646b93686b..a39521bb93312234dc6487f8258d9ed71cfb49b5 100644 --- a/src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs +++ b/src/Common/H.LowCode.MetaSchema.RenderEngine/ComponentSchema.cs @@ -22,11 +22,25 @@ public class ComponentSchema : ComponentSchemaBase public ComponentAttributeDefineGroupSchema[]? AttributeDefineGroups { get; set; } /// - /// 将组件自定义属性合并到 Fragment 中 + /// 子组件列表 /// [JsonPropertyName("childs")] public ComponentSchema[]? Childrens { get; set; } + /// + /// 条件分支配置(用于条件渲染组件) + /// Key: 条件值(字符串形式) + /// Value: 对应的子组件配置 + /// + [JsonPropertyName("cases")] + public Dictionary? Cases { get; set; } + + /// + /// 默认分支(当没有匹配的条件时渲染) + /// + [JsonPropertyName("default")] + public ComponentSchema? DefaultCase { get; set; } + public void MergeAttributeDefineToFragment() { if (this?.AttributeDefineGroups == null diff --git a/src/Common/H.LowCode.MetaSchema.RenderEngine/DataSourceSchemas/ComponentDataSourceSchema.cs b/src/Common/H.LowCode.MetaSchema.RenderEngine/DataSourceSchemas/ComponentDataSourceSchema.cs index c5b45be06d280c282ec6d3f6ec2e78a9ed93f5e4..2cb2ac799eccca04772efa083d7471cc729de4fc 100644 --- a/src/Common/H.LowCode.MetaSchema.RenderEngine/DataSourceSchemas/ComponentDataSourceSchema.cs +++ b/src/Common/H.LowCode.MetaSchema.RenderEngine/DataSourceSchemas/ComponentDataSourceSchema.cs @@ -13,4 +13,10 @@ public class ComponentDataSourceSchema : ComponentDataSourceSchemaBase /// [JsonPropertyName("dsfrag")] public ComponentFragmentSchema DataSourceFragment { get; set; } + + /// + /// 列表项模板(支持完整的组件配置,包括条件渲染) + /// + [JsonPropertyName("itemtpl")] + public ComponentSchema ItemTemplate { get; set; } } diff --git a/src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs b/src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs index 0b001be22b6fdbf504065cd69f68b1156173fc3c..ba87868198d8af7bae08ccc428b2da3586c68db4 100644 --- a/src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs +++ b/src/Common/H.LowCode.MetaSchema/DataSourceSchema.cs @@ -11,7 +11,7 @@ public class DataSourceSchema : MetaSchemaBase public required string Id { get; set; } [JsonPropertyName("n")] - public string? Name { get; set; } + public required string Name { get; set; } [JsonPropertyName("disn")] public string? DisplayName { get; set; } diff --git a/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ComponentDataSourceSchema.cs b/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ComponentDataSourceSchema.cs index 8265be6bdadbb6c9ee44607248a49c679d076eec..39f2ea4f54783e210632616123501cbabf2eafee 100644 --- a/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ComponentDataSourceSchema.cs +++ b/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ComponentDataSourceSchema.cs @@ -43,4 +43,10 @@ public abstract class ComponentDataSourceSchemaBase : StateHasChangeSchema /// [JsonPropertyName("sqlopds")] public SQLDataSourceSchema? SQLOptionDataSource { get; set; } + + /// + /// List 循环数据源配置 + /// + [JsonPropertyName("listds")] + public ListDataSourceSchema? ListDataSource { get; set; } } diff --git a/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ListDataSourceSchema.cs b/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ListDataSourceSchema.cs new file mode 100644 index 0000000000000000000000000000000000000000..176001721ebd08213515fb731c4977508d3b4d5a --- /dev/null +++ b/src/Common/H.LowCode.MetaSchema/DataSourceSchemas/ListDataSourceSchema.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace H.LowCode.MetaSchema; + +/// +/// List 循环数据源配置 +/// +public class ListDataSourceSchema +{ + /// + /// 固定数据源(用于设计时预览) + /// + [JsonPropertyName("fxdata")] + public IList>? FixedData { get; set; } + + /// + /// API 数据源配置 + /// + [JsonPropertyName("apids")] + public APIDataSourceSchema? APIDataSource { get; set; } + + /// + /// SQL 数据源配置 + /// + [JsonPropertyName("sqlds")] + public SQLDataSourceSchema? SQLDataSource { get; set; } + + /// + /// 数据响应路径(用于提取数组数据,如 "data.list") + /// + [JsonPropertyName("datapath")] + public string? DataPath { get; set; } + + /// + /// 排序字段 + /// + [JsonPropertyName("orderby")] + public string? OrderBy { get; set; } + + /// + /// 是否倒序 + /// + [JsonPropertyName("orderdesc")] + public bool OrderDesc { get; set; } +} diff --git a/src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceGroupTypeEnum.cs b/src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceGroupTypeEnum.cs index c924abbae63bd607f93f43f22a0c5a4d649e8881..6bc831c552616227a700ed8a49ed044b912c7cc8 100644 --- a/src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceGroupTypeEnum.cs +++ b/src/Common/H.LowCode.MetaSchema/Enums/ComponentDataSourceGroupTypeEnum.cs @@ -14,5 +14,6 @@ public enum ComponentDataSourceGroupTypeEnum General = 0, Option = 1, Table = 2, - Tree = 3 + Tree = 3, + List = 4 // 列表循环数据源 } diff --git a/src/Common/H.LowCode.MetaSchema/Enums/EventDataActionTypeEnum.cs b/src/Common/H.LowCode.MetaSchema/Enums/EventDataActionTypeEnum.cs index 0feda43cda3c14fa23a0beb9abff22836fa8b254..e41413602fee5121ead7c342e79576df7a5490e8 100644 --- a/src/Common/H.LowCode.MetaSchema/Enums/EventDataActionTypeEnum.cs +++ b/src/Common/H.LowCode.MetaSchema/Enums/EventDataActionTypeEnum.cs @@ -11,4 +11,9 @@ public enum EventDataActionTypeEnum CancelEdit = 40, // 取消编辑 AddRow = 50, // 添加行 RefreshData = 60, // 刷新数据 + + // List 数据操作 + MoveUp = 70, // 上移 + MoveDown = 80, // 下移 + CopyRow = 90, // 复制行 } \ No newline at end of file diff --git a/src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj b/src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj index 61f7f2b4bad7bd9cb02712469d73ee0c4e24c5bb..3027581dc8cf9b43d9d40b22c35c9d00c3f424ad 100644 --- a/src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj +++ b/src/Common/H.LowCode.MetaSchema/H.LowCode.MetaSchema.csproj @@ -7,8 +7,4 @@ - - - - diff --git a/src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs b/src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs index 1d46a205e666bfd8b3ea42873acfd0649c343bb6..51b81bc17a5b1d9a7bf3f1ad952159a3e57550e1 100644 --- a/src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs +++ b/src/Common/H.LowCode.MetaSchema/PropertySchemas/ComponentFragmentSchemaBase.cs @@ -19,6 +19,12 @@ public abstract class ComponentFragmentSchemaBase [JsonPropertyName("content")] public string? Content { get; set; } + /// + /// 事件配置(用于按钮等组件的事件绑定) + /// + [JsonPropertyName("evs")] + public IList? Events { get; set; } + public object? GetDefaultValue() { if (string.IsNullOrEmpty(ValueType)) diff --git a/src/Common/H.LowCode.MetaSchema/PropertySchemas/TableSchemas/TablePropertySchema.cs b/src/Common/H.LowCode.MetaSchema/PropertySchemas/TableSchemas/TablePropertySchema.cs index 88643890d335bc9241ced0f583cc88aac3882311..433584fd82763628e96cd108296b759a9ba75b5c 100644 --- a/src/Common/H.LowCode.MetaSchema/PropertySchemas/TableSchemas/TablePropertySchema.cs +++ b/src/Common/H.LowCode.MetaSchema/PropertySchemas/TableSchemas/TablePropertySchema.cs @@ -6,7 +6,7 @@ namespace H.LowCode.MetaSchema; public class TablePropertySchema { [JsonPropertyName("tcols")] - public IList Columns { get; set; } = []; + public IList? Columns { get; set; } = []; [JsonPropertyName("searchs")] public IList SearchItems { get; set; } = []; diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/PartsAppServices/IComponentPartsAppService.cs b/src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/PartsAppServices/IComponentPartsAppService.cs index 14bc5d5ebf1817afed6200be46cb14064c9e5d5e..d0c51f5fbf0f77432ce72619b4b857ed204924c5 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/PartsAppServices/IComponentPartsAppService.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.Application.Contracts/PartsAppServices/IComponentPartsAppService.cs @@ -11,9 +11,9 @@ public interface IComponentPartsAppService : IApplicationService Task> GetAllComponentsAsync(string libraryId); - Task GetByIdAsync(string libraryId, string componentId); + Task GetByIdAsync(string libraryId, string partsId); Task SaveAsync(ComponentPartsSchema componentParts); - Task DeleteAsync(string libraryId, string componentId); + Task DeleteAsync(string libraryId, string partsId); } diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs b/src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs index 505f73a14ac7c1b63cd7ce2e21ff1c4a3aceef12..5a87b6f1b77cb13640c202f8f0a2a5a4a037e6ff 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.Application/AppServices/PageAppService.cs @@ -67,7 +67,7 @@ public class PageAppService : ApplicationService, IPageAppService { //组件定义 Schema var componentPartsDefine = await _componentPartsAppService.GetByIdAsync(component.LibraryId, - component.ComponentId); + component.PartsId); //组件实例与组件定义合并,保证历史组件实例升级到最新组件特性 component.MergeComponentPartsDefine(componentPartsDefine); diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentPartsAppService.cs b/src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentPartsAppService.cs index 084910fea8c9bfbf638b6a8a5ff26824d7341ef0..5850ec8fb9490b150a5e50f9d22d89f258d5eada 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentPartsAppService.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.Application/PartsAppServices/ComponentPartsAppService.cs @@ -13,19 +13,14 @@ public class ComponentPartsAppService : ApplicationService, IComponentPartsAppSe { private IComponentPartsRepository _repository => LazyServiceProvider.GetRequiredService(); - public async Task DeleteAsync(string libraryId, string componentId) - { - return await _repository.DeleteAsync(libraryId, componentId); - } - public async Task> GetAllComponentsAsync(string libraryId) { return await _repository.GetAllComponentsAsync(libraryId); } - public async Task GetByIdAsync(string libraryId, string componentId) + public async Task GetByIdAsync(string libraryId, string partsId) { - return await _repository.GetByIdAsync(libraryId, componentId); + return await _repository.GetByIdAsync(libraryId, partsId); } public async Task> GetListAsync(string libraryId) @@ -37,4 +32,9 @@ public class ComponentPartsAppService : ApplicationService, IComponentPartsAppSe { return await _repository.SaveAsync(componentParts); } + + public async Task DeleteAsync(string libraryId, string partsId) + { + return await _repository.DeleteAsync(libraryId, partsId); + } } diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Domain/PartsRepositories/IComponentPartsRepository.cs b/src/DesignEngine/H.LowCode.DesignEngine.Domain/PartsRepositories/IComponentPartsRepository.cs index 0fd5aaa41a92a4dd1e29fefce0c87f92105a1730..6684920a8453dc561c203d893abf142dd47a529a 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Domain/PartsRepositories/IComponentPartsRepository.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.Domain/PartsRepositories/IComponentPartsRepository.cs @@ -14,9 +14,9 @@ public interface IComponentPartsRepository Task> GetAllComponentsAsync(string libraryId); - Task GetByIdAsync(string libraryId, string componentId); + Task GetByIdAsync(string libraryId, string partsId); Task SaveAsync(ComponentPartsSchema componentParts); - Task DeleteAsync(string libraryId, string componentId); + Task DeleteAsync(string libraryId, string partsId); } diff --git a/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs b/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs index e378c74194d01a1fe89f5f83f0b73392aafc3c38..07250edeac0c676b7131783d064331ee21afb3ba 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/DesignEngineDbContext.cs @@ -125,6 +125,8 @@ public class DesignEngineDbContext : DbContext //设置连接字符串 //optionsBuilder.UseSqlServer(""); + optionsBuilder.ReplaceService(); + //注册EFcore拦截器,对需要With(NoLock)查询linq进行拦截修改Sql语句 optionsBuilder.AddInterceptors(new QueryWithNoLockDbCommandInterceptor()); //表重复注册 diff --git a/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/MapModelCacheKeyFactory.cs b/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/DesignEngineModelCacheKeyFactory.cs similarity index 66% rename from src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/MapModelCacheKeyFactory.cs rename to src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/DesignEngineModelCacheKeyFactory.cs index 6615b606c7bc9813e508e29f8896b4c957fcdce7..ef4fd39735c2295878813a66a8fe80557d227d7b 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/MapModelCacheKeyFactory.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.EntityFrameworkCore/EntityFrameworkCore/Extensions/DesignEngineModelCacheKeyFactory.cs @@ -1,14 +1,9 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace H.LowCode.DesignEngine.EntityFrameworkCore; -internal class MapModelCacheKeyFactory : IModelCacheKeyFactory +internal class DesignEngineModelCacheKeyFactory : IModelCacheKeyFactory { public object Create(DbContext context, bool designTime) { diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.Development.json b/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.Development.json index 214f18e1ee92d9a81b597d7d9c23a8628d091ada..b637d40ec00fb8622cf5074eda17f968b00f9f06 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.Development.json +++ b/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.Development.json @@ -1,11 +1,4 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning", - "Microsoft.AspNetCore.Components.WebAssembly": "Warning" - } - }, "RemoteServices": { "Default": { "BaseUrl": "https://localhost:5181" diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json b/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json index ae41b9259ac0c9a01ca0dcfb8408f301f94e9dd5..f8e32efd7f6879320b0231787e0121fd41b45714 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json +++ b/src/DesignEngine/H.LowCode.DesignEngine.Host.Client/wwwroot/appsettings.json @@ -15,5 +15,26 @@ "Telemetry": { "IsEnabled": false } + }, + "Serilog": { + "Using": [ "Serilog.Sinks.Console" ], + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.EntityFrameworkCore": "Information" + } + }, + "WriteTo": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Error", + "outputTemplate": "{Timestamp:HH:mm:ss} [{Level}] {Message} {NewLine}{Exception}\n", + "theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Grayscale, Serilog.Sinks.Console" + } + } + ] } } diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json b/src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json index 1f7c0ff44ffce3a5bc71ccce8dbc46facddcdea1..e02335629841a51ebbdd059c7c7fd4c22f3c5763 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json +++ b/src/DesignEngine/H.LowCode.DesignEngine.Host/appsettings.json @@ -36,5 +36,44 @@ "Telemetry": { "IsEnabled": false } + }, + "Serilog": { + "Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Async", "Serilog.Sinks.Console" ], + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.EntityFrameworkCore": "Information" + } + }, + "WriteTo": [ + { + "Name": "Async", + "Args": { + "configure": [ + { + "Name": "File", + "Args": { + "path": "../../logs/log_.txt", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] [{SourceContext}] [{EventId}] {Message}{NewLine}{Exception}\n", + "rollOnFileSizeLimit": true, + "fileSizeLimitBytes": 10485760, //10M + "retainedFileCountLimit": 50, + "rollingInterval": "Day" + } + } + ] + } + }, + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Error", + "outputTemplate": "{Timestamp:HH:mm:ss} [{Level}] {Message} {NewLine}{Exception}\n", + "theme": "Serilog.Sinks.SystemConsole.Themes.SystemConsoleTheme::Grayscale, Serilog.Sinks.Console" + } + } + ] } } diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Model/PartsModels/ComponentPartsListModel.cs b/src/DesignEngine/H.LowCode.DesignEngine.Model/PartsModels/ComponentPartsListModel.cs index 585fb895926b85771f4c3e393fd835201f1637db..8499e11e57dcd47779b6cabc836577dbe7d5f0a7 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Model/PartsModels/ComponentPartsListModel.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.Model/PartsModels/ComponentPartsListModel.cs @@ -10,7 +10,7 @@ public class ComponentPartsListModel /// public string LibraryId { get; set; } - [JsonPropertyName("compid")] + [JsonPropertyName("partsId")] public string ComponentId { get; set; } [JsonPropertyName("lb")] diff --git a/src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs b/src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs index 96a5aa01bcf01efc57cb1b5f0d503131fa6a53bf..48346f86d9f4a825c355b6cfd3369ba0d6c9b622 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine.Repository.JsonFile/PartsRepositories/ComponentPartsRepository.cs @@ -46,7 +46,7 @@ public class ComponentPartsRepository : PartsFileRepositoryBase, IComponentParts ComponentPartsListModel model = new() { LibraryId = componentPartsSchema.LibraryId, - ComponentId = componentPartsSchema.ComponentId, + ComponentId = componentPartsSchema.PartsId, ComponentType = componentPartsSchema.ComponentType, IsContainer = componentPartsSchema.IsContainer, IsSupportDataSource = componentPartsSchema.IsSupportDataSource, @@ -97,9 +97,9 @@ public class ComponentPartsRepository : PartsFileRepositoryBase, IComponentParts return await Task.FromResult(list); } - public async Task GetByIdAsync(string libraryId, string componentId) + public async Task GetByIdAsync(string libraryId, string partsId) { - string fileName = string.Format(componentPartsFileName_Format, _metaBaseDir, libraryId, componentId); + string fileName = string.Format(componentPartsFileName_Format, _metaBaseDir, libraryId, partsId); var componentPartsSchemaJson = ReadAllText(fileName) ?? throw new FileNotFoundException(fileName); var componentParts = componentPartsSchemaJson.FromJson(); @@ -118,7 +118,7 @@ public class ComponentPartsRepository : PartsFileRepositoryBase, IComponentParts if(componentParts.Fragment != null) componentParts.Fragment.TypeName = null; - string fileName = string.Format(componentPartsFileName_Format, _metaBaseDir, componentParts.LibraryId, componentParts.ComponentId); + string fileName = string.Format(componentPartsFileName_Format, _metaBaseDir, componentParts.LibraryId, componentParts.PartsId); string fileDirectory = Path.GetDirectoryName(fileName); if (!Directory.Exists(fileDirectory)) @@ -128,9 +128,9 @@ public class ComponentPartsRepository : PartsFileRepositoryBase, IComponentParts return await Task.FromResult(true); } - public async Task DeleteAsync(string libraryId, string componentId) + public async Task DeleteAsync(string libraryId, string partsId) { - string fileName = string.Format(componentPartsFileName_Format, _metaBaseDir, libraryId, componentId); + string fileName = string.Format(componentPartsFileName_Format, _metaBaseDir, libraryId, partsId); if (!File.Exists(fileName)) return false; diff --git a/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/ComponentPanel.razor b/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/ComponentPanel.razor index fac12c9550c44fcc2f45fb14985889a9b329af07..01b60e7ac0845d7ced3e62911adfc137281bf77a 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/ComponentPanel.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/ComponentPanel.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @inject IComponentLibraryAppService ComponentLibraryAppService @inject IComponentPartsAppService ComponentPartsAppService @@ -10,27 +10,30 @@ -
- @* @if (_componentLibraries != null) +
+ + @if (ComponentsByLibrary != null && ComponentsByLibrary.Count > 0) { - @foreach (var componentLibrary in _componentLibraries) - { -
-
@componentLibrary.LibraryName
- - @foreach (var component in LoadComponentParts(componentLibrary.LibraryId)) - { - - } -
- } - } *@ - @if (_componentPartsList != null) + + @foreach (var libraryGroup in ComponentsByLibrary) + { + +
+ @if (libraryGroup.Value != null) + { + @foreach (var component in libraryGroup.Value) + { + + } + } +
+
+ } +
+ } + else { - @foreach (var component in _componentPartsList) - { - - } +
暂无组件
}
@@ -66,23 +69,33 @@ @code { + /// + /// 按组件库分组的组件集合 + /// Key: 组件库名称, Value: 该库的组件列表 + /// [PersistentState] - public IList? _componentPartsList { get; set; } + public Dictionary> ComponentsByLibrary { get; set; } = []; protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); - _componentPartsList = (await LoadComponentPartsAsync()) ?? []; - } + // 先尝试获取所有组件库 + var libraries = await ComponentLibraryAppService.GetListAsync(); - private async Task> LoadComponentLibraries() - { - return await ComponentLibraryAppService.GetListAsync(); - } + if (libraries != null && libraries.Count > 0) + { + // 为每个库加载组件,并按库分组 + ComponentsByLibrary = new Dictionary>(); - private async Task> LoadComponentPartsAsync() - { - return await ComponentPartsAppService.GetAllComponentsAsync("antdesign"); + foreach (var lib in libraries) + { + var components = await ComponentPartsAppService.GetAllComponentsAsync(lib.LibraryId); + if (components != null && components.Count > 0) + { + ComponentsByLibrary[lib.LibraryId] = new List(components); + } + } + } } } \ No newline at end of file diff --git a/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor index 0d7a9ceb361f6199f0ee899c39b5e004b4320d34..4a42fcc9622748b3c6d87d04518379cb11da299e 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @inject DragDropStateService DragDropStateService @@ -34,8 +34,8 @@ component.DesignState.IsDroppedFromComponentPanel = true; if (isOnClick) { - //发送事件,通知订阅此事件的其他组件更新状态 - BlazorEventDispatcher.Publish("designengine.dragitem.onclick", component); + // 在组件的渲染线程中发布事件,避免 Publish 在非 UI 线程执行导致后续 InvokeAsync 抛异常 + InvokeAsync(() => BlazorEventDispatcher.Publish("designengine.dragitem.onclick", component)); } else { diff --git a/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css b/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css index 4bc55a4ea9339268774f086f35292b1e9cf10b93..e877f8a1213c0652d674dd7c1164138e8cf04e3b 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css +++ b/src/DesignEngine/H.LowCode.DesignEngine/ComponentPanel/DragItem.razor.css @@ -1,18 +1,35 @@ /* ================== DragItem.razor ==================== */ .dragitem { float: left; - width: 6.8rem; - height: 2.2rem; - margin: 4px; - cursor: pointer; + width: calc(50% - 10px); + min-width: 90px; + height: 36px; + margin: 4px 8px 4px 0; + cursor: grab; display: flex; justify-content: center; align-items: center; color: #333; - background-color: #f5f7fa; + font-size: 13px; + background-color: #fafafa; + border: 1px solid #e8e8e8; + border-radius: 4px; + transition: all 0.3s ease; + box-sizing: border-box; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .dragitem:hover { - border: #409eff dashed 1px; + border-color: #409eff; color: #409eff; + background-color: #f0f7ff; + box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15); + transform: translateY(-1px); + } + + .dragitem:active { + cursor: grabbing; + transform: scale(0.98); } diff --git a/src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor b/src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor index af1f2282cf83ab90e9f4248ee0834db04ef1698c..63a13be21a265a0562ffbec825fb6b0cab54c704 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/DesignPanel/DesignPanel.razor @@ -1,6 +1,6 @@ @namespace H.LowCode.DesignEngine @using System.Reflection -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @inject DragDropStateService DragDropStateService @@ -39,7 +39,7 @@ rootComponent = new ComponentPartsSchema() { Id = "root", - ComponentId = "root" + PartsId = "root" }; rootComponent.Name = "root"; rootComponent.Refresh = StateHasChanged; diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableContainer.razor similarity index 96% rename from src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor rename to src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableContainer.razor index 8682430e966977a81fe1dffa1c98fbf2b51b5354..3b74c3b0366c88b2c6f7c2b74fa2825d7b4022df 100644 --- a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableContainer.razor @@ -1,5 +1,6 @@ -@namespace H.LowCode.DesignEngineBase -@inherits DesignEngineLowCodeComponentBase +@namespace H.LowCode.DesignEngine +@using System.Threading.Tasks +@inherits LowCodeComponentBase @inject DragDropStateService DragDropStateService @@ -197,13 +198,14 @@ /// /// /// - private void DragItem_Move(ComponentPartsSchema newContainerComponent, ComponentPartsSchema currentDragComponent, ComponentPartsSchema dragOverComponent) + private async Task DragItem_Move(ComponentPartsSchema newContainerComponent, ComponentPartsSchema currentDragComponent, ComponentPartsSchema dragOverComponent) { //上一个 DraggableContainer 移除 var oldContainerComponent = DragDropStateService.FindComponentById(PageCascading.AppId, PageCascading.PageId, currentDragComponent.ParentId); oldContainerComponent.Childrens.Remove(currentDragComponent); - oldContainerComponent.RefreshState(); //刷新上一个 DraggableContainer,使 Remove 立即生效 + await InvokeAsync(() => oldContainerComponent.RefreshState()); //刷新上一个 DraggableContainer,使 Remove 立即生效 + //当前 DraggableContainer 新增 currentDragComponent.ParentId = newContainerComponent.Id; DragItem_Add(newContainerComponent, currentDragComponent, dragOverComponent); diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor.css b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableContainer.razor.css similarity index 100% rename from src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableContainer.razor.css rename to src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableContainer.razor.css diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableItem.razor similarity index 99% rename from src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor rename to src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableItem.razor index 96afa63a21fb8756255d07302d3ac650700366ec..d21729cfa0d31fa2388468459a19f2f0f3d35916 100644 --- a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableItem.razor @@ -1,5 +1,5 @@ -@namespace H.LowCode.DesignEngineBase -@inherits DesignEngineLowCodeComponentBase +@namespace H.LowCode.DesignEngine +@inherits LowCodeComponentBase @implements IAsyncDisposable @inject DragDropStateService DragDropStateService @@ -44,7 +44,7 @@
} - +
diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableItem.razor.css similarity index 100% rename from src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/DraggableItem.razor.css rename to src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DraggableItem.razor.css diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/ComponentItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DynamicComponentItem.razor similarity index 90% rename from src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/ComponentItem.razor rename to src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DynamicComponentItem.razor index d1ee8051b7f87ff8e3c751428031c0b9e631a1c8..9707d43299a1a3e9011cf394a2cf9aabc95ef936 100644 --- a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/ComponentItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DynamicComponentItem.razor @@ -1,5 +1,5 @@ -@namespace H.LowCode.DesignEngineBase -@inherits DesignEngineDynamicComponentBase +@namespace H.LowCode.DesignEngine +@inherits DynamicComponentBase @if (Component != null && _renderFragment != null) { @@ -52,7 +52,7 @@ throw new NullReferenceException($"{nameof(Component)} or {nameof(Component.Fragment)} is null"); if (string.IsNullOrEmpty(Component.Name)) - Component.Name = $"{Component.ComponentId}_{Random.Shared.Next(100, 999)}"; + Component.Name = $"{Component.PartsId}_{Random.Shared.Next(100, 999)}"; if (string.IsNullOrEmpty(Component.Fragment.TypeName)) Component.Fragment.TypeName = Component.Fragment.DefaultTypeName; diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/ComponentItem.razor.css b/src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DynamicComponentItem.razor.css similarity index 100% rename from src/DesignEngine/H.LowCode.DesignEngineBase/DraggableComponents/ComponentItem.razor.css rename to src/DesignEngine/H.LowCode.DesignEngine/DraggableComponents/DynamicComponentItem.razor.css diff --git a/src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor b/src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor index c07f4341f29e2835ce74d8949f3702e3dfdb228d..784659f8ee03c4f6704ce855db99d4bfe0537d03 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/Pages/DesignPage.razor @@ -1,6 +1,6 @@ @page "/designer/{AppId}/{PageId}" @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodePageComponentBase +@inherits LowCodePageComponentBase @layout DesignEngineLayout @inject IPageAppService PageAppService @@ -45,9 +45,6 @@ @code { - [Parameter] - public string AppId { get; set; } - [Parameter] public string PageId { get; set; } diff --git a/src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs b/src/DesignEngine/H.LowCode.DesignEngine/Services/DragDropStateService.cs similarity index 98% rename from src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs rename to src/DesignEngine/H.LowCode.DesignEngine/Services/DragDropStateService.cs index 6f41d59c0f00b88d9bda0e367be820e03499a4b5..c208908de26f3b0581fb0b63361913fe316ba56e 100644 --- a/src/DesignEngine/H.LowCode.DesignEngineBase/Services/DragDropStateService.cs +++ b/src/DesignEngine/H.LowCode.DesignEngine/Services/DragDropStateService.cs @@ -1,11 +1,11 @@ using H.LowCode.MetaSchema.DesignEngine; -namespace H.LowCode.DesignEngineBase; +namespace H.LowCode.DesignEngine; /// /// 拖拽状态服务 /// -public class DragDropStateService +internal class DragDropStateService { #region 拖拽对象状态管理 private IDictionary schemaStates = new Dictionary(); @@ -205,7 +205,7 @@ public class DragDropStateService #endregion } -public class DragDropStateSchema +internal class DragDropStateSchema { /// /// 根 ComponentPartsSchema diff --git a/src/DesignEngine/H.LowCode.DesignEngine/Services/DynamicComponentBase.cs b/src/DesignEngine/H.LowCode.DesignEngine/Services/DynamicComponentBase.cs new file mode 100644 index 0000000000000000000000000000000000000000..14088a93a86a39d67e06de49d4b80e52c372949f --- /dev/null +++ b/src/DesignEngine/H.LowCode.DesignEngine/Services/DynamicComponentBase.cs @@ -0,0 +1,349 @@ +using H.LowCode.ComponentBase; +using H.LowCode.MetaSchema; +using H.LowCode.MetaSchema.DesignEngine; +using H.Util.Ids; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Rendering; + +namespace H.LowCode.DesignEngine; + +public abstract class DynamicComponentBase : LowCodeDynamicComponentBase +{ + protected virtual RenderFragment RenderComponent(ComponentPartsSchema component) + => builder => + { + if (component == null || component.Fragment == null) + throw new NullReferenceException($"{nameof(component)} or {nameof(component.Fragment)} is null"); + + int index = 0; + RenderComponentRecursive(component.Id, component.IsSupportDataSource, + component, component.DataSource, component.Fragment, builder, index); + }; + + private void RenderComponentRecursive( + string componentId, bool isSupportDataSource, + ComponentPartsSchema component, + ComponentPartsDataSourceSchema dataSource, + ComponentPartsFragmentSchema componentFragment, + RenderTreeBuilder builder, int index) + { + //TypeName 为空时,使用 DefaultTypeName + if (string.IsNullOrEmpty(componentFragment.TypeName)) + componentFragment.TypeName = componentFragment.DefaultTypeName; + + if (string.IsNullOrEmpty(componentFragment.TypeName)) + throw new NullReferenceException($"componentId={componentId}, {nameof(componentFragment.TypeName)}"); + + Type componentType = Type.GetType(componentFragment.TypeName, true); + if (componentType == null) + throw new NullReferenceException($"componentId={componentId}, type={componentFragment.TypeName}"); + + builder.OpenComponent(index++, componentType); + + //渲染属性 + RenderComponentAttributes(builder, index, componentId, componentType, + componentFragment.Attributes); + + //渲染 ChildContent + if (isSupportDataSource) + { + RenderDataSource(componentId, component, dataSource, builder, index); + } + else if (componentFragment.HasChildFragment) + { + RenderChildFragments(componentId, component, componentFragment, builder, index); + } + else if (componentFragment.Content.IsNullOrWhiteSpace() == false) + { + RenderContent(componentId, component, componentFragment, builder, index); + } + + builder.CloseComponent(); + } + + #region 渲染数据源 + private void RenderDataSource(string componentId, + ComponentPartsSchema component, + ComponentPartsDataSourceSchema dataSource, + RenderTreeBuilder builder, int index) + { + if (dataSource == null) + return; + + if (dataSource.DataSourceGroupType == ComponentDataSourceGroupTypeEnum.Option) + { + switch (dataSource.DataSourceType) + { + case ComponentDataSourceTypeEnum.Fiexd: + RenderOptionDataSource(componentId, dataSource, builder, index); + break; + case ComponentDataSourceTypeEnum.SQL: + break; + case ComponentDataSourceTypeEnum.API: + break; + default: + break; + } + } + else if (dataSource.DataSourceGroupType == ComponentDataSourceGroupTypeEnum.Table) + { + builder.AddAttribute(index++, "DataSource", component.DataSource); + } + else if (dataSource.DataSourceGroupType == ComponentDataSourceGroupTypeEnum.List) + { + RenderListDataSource(componentId, component, dataSource, builder, index); + } + } + + private void RenderOptionDataSource(string componentId, + ComponentPartsDataSourceSchema dataSource, + RenderTreeBuilder builder, int index) + { + if (dataSource.FiexdOptionDataSource == null + || dataSource.FiexdOptionDataSource.Count == 0) + return; + + builder.AddAttribute(index++, "ChildContent", (RenderFragment)(childBuilder => + { + if (string.IsNullOrEmpty(dataSource.DataSourceFragment.TypeName)) + throw new NullReferenceException($"componentId={componentId}, {nameof(dataSource.DataSourceFragment.TypeName)}"); + + Type childComponentType = Type.GetType(dataSource.DataSourceFragment.TypeName, true); + if (childComponentType == null) + throw new NullReferenceException($"componentId={componentId}, type={dataSource.DataSourceFragment.TypeName}"); + + foreach (var option in dataSource.FiexdOptionDataSource) + { + childBuilder.OpenComponent(index++, childComponentType); + foreach (var fragAttr in dataSource.DataSourceFragment.Attributes) + { + if(string.IsNullOrEmpty(fragAttr.AttributeName)) + throw new NullReferenceException($"componentId={componentId}, {nameof(fragAttr.AttributeName)} is null"); + + childBuilder.AddAttribute(index++, fragAttr.AttributeName, option.Value); + } + + childBuilder.AddAttribute(index++, "ChildContent", (RenderFragment)((cb) => + { + cb.AddContent(index++, option.Label); + })); + + childBuilder.CloseComponent(); + } + })); + } + #endregion + + #region 渲染子节点 + private void RenderChildFragments(string componentId, + ComponentPartsSchema component, + ComponentPartsFragmentSchema componentFragment, + RenderTreeBuilder builder, int index) + { + if (componentFragment.HasChildFragment == false) + return; + + builder.AddAttribute(index++, "ChildContent", (RenderFragment)(childBuilder => + { + foreach (var childFragment in componentFragment.ChildFragments) + { + RenderComponentRecursive(componentId, false, + component, null, childFragment, childBuilder, index); + } + })); + } + #endregion + + #region 渲染 List 循环数据源 + private void RenderListDataSource(string componentId, + ComponentPartsSchema component, + ComponentPartsDataSourceSchema dataSource, + RenderTreeBuilder builder, int index) + { + if (dataSource.ListDataSource == null) + { + // 如果没有配置数据源,渲染空列表 + builder.AddAttribute(index++, "DataSource", new List()); + return; + } + + // 获取固定数据源(设计时预览) + var listData = GetListDataSource(dataSource); + if (listData == null || listData.Count == 0) + { + // 使用示例数据 + listData = new List + { + new Dictionary { { "id", "1" }, { "title", "示例问题 1" } }, + new Dictionary { { "id", "2" }, { "title", "示例问题 2" } } + }; + } + + // 渲染 ItemTemplate + if (dataSource.DataSourceFragment != null) + { + builder.AddAttribute(index++, "ChildContent", (RenderFragment)((item) => (childBuilder) => + { + if (string.IsNullOrEmpty(dataSource.DataSourceFragment.TypeName)) + return; + + Type itemComponentType = Type.GetType(dataSource.DataSourceFragment.TypeName, true); + if (itemComponentType == null) + return; + + childBuilder.OpenComponent(index++, itemComponentType); + + // 渲染属性 + if (dataSource.DataSourceFragment.Attributes != null) + { + foreach (var attr in dataSource.DataSourceFragment.Attributes) + { + if (string.IsNullOrEmpty(attr.AttributeName)) + continue; + + var attrValue = ResolveAttributeValue(attr, item); + + if (!string.IsNullOrEmpty(attr.AttributeClrType)) + { + var attrType = Type.GetType(attr.AttributeClrType); + if (attrType != null) + { + var realValue = attrValue?.ToString().ConvertToRealType(attrType) ?? attrValue; + childBuilder.AddAttribute(index++, attr.AttributeName, realValue); + } + } + else + { + childBuilder.AddAttribute(index++, attr.AttributeName, attrValue); + } + } + } + + // 渲染子组件 + if (dataSource.DataSourceFragment.HasChildFragment) + { + RenderChildFragments(componentId, component, dataSource.DataSourceFragment, childBuilder, index); + } + + childBuilder.CloseComponent(); + })); + } + + builder.AddAttribute(index++, "DataSource", listData); + } + + private IList GetListDataSource(ComponentPartsDataSourceSchema dataSource) + { + var listDs = dataSource.ListDataSource; + if (listDs == null) + return new List(); + + if (listDs.FixedData != null && listDs.FixedData.Count > 0) + { + return listDs.FixedData.Cast().ToList(); + } + + return new List(); + } + + private object ResolveAttributeValue(ComponentAttributeFragmentSchema attr, object dataItem) + { + if (attr.AttributeValue == null) + return null; + + var valueStr = attr.AttributeValue.ToString(); + if (string.IsNullOrEmpty(valueStr)) + return null; + + // 支持绑定表达式 $(item.fieldName) + if (valueStr.StartsWith("$(item.") && valueStr.EndsWith(")")) + { + var fieldName = valueStr.Substring(7, valueStr.Length - 8); + + if (dataItem is Dictionary dict) + { + return dict.ContainsKey(fieldName) ? dict[fieldName] : null; + } + else + { + var propInfo = dataItem.GetType().GetProperty(fieldName); + return propInfo?.GetValue(dataItem); + } + } + + return attr.AttributeValue; + } + #endregion + + #region 渲染 Content + private void RenderContent(string componentId, + ComponentPartsSchema component, + ComponentPartsFragmentSchema componentFragment, + RenderTreeBuilder builder, int index) + { + if (componentFragment.Content.IsNullOrWhiteSpace()) + return; + + if (string.Equals(componentFragment.Content, $"$({nameof(DraggableContainer)})", + StringComparison.OrdinalIgnoreCase)) + { + //TODO: 此处 containerComponentId 不能保证唯一性, 待优化 + var containerComponentId = $"container-{component.Id}-{componentFragment.DefaultTypeName.GetHashCode()}"; + var (containerComponent, needAdd) = RenderContainerComponent(component, containerComponentId); + if (needAdd == false) + return; + + builder.AddAttribute(index++, "ChildContent", (RenderFragment)(childBuilder => + { + childBuilder.OpenComponent(index++); + childBuilder.AddAttribute(index++, "ContainerComponent", containerComponent); + childBuilder.CloseComponent(); + })); + } + else + { + builder.AddAttribute(index++, "ChildContent", (RenderFragment)(childBuilder => + { + childBuilder.AddMarkupContent(index++, componentFragment.Content); + })); + } + } + #endregion + + #region 渲染组件内的 DraggableContainer + private (ComponentPartsSchema, bool) RenderContainerComponent(ComponentPartsSchema component, string key, Action action = null) + { + var exist = component.Childrens?.Any(t => t.Id == key); + if (exist.HasValue && exist.Value) + return (null, false); + + var innerContainerComponent = RenderChildContainerComponent(component, key); + + if (action != null) action(innerContainerComponent); + + component.Childrens.Add(innerContainerComponent); + + return (innerContainerComponent, true); + } + + private ComponentPartsSchema RenderChildContainerComponent(ComponentPartsSchema component, string key) + { + var innerContainerComponent = new ComponentPartsSchema + { + Id = key, + PartsId = ShortIdGenerator.Generate(), + Refresh = component.Refresh, + + Fragment = new(), + Style = new() { DefaultStyle = "height:100%; width:100%;" }, + IsHiddenLabel = true, + + IsContainer = true, + IsInnerContainer = true, + ParentId = component.Id + }; + + return innerContainerComponent; + } + #endregion +} diff --git a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor index 75fcfbe51c4acb57382f1553b7d61f6b5edd5045..1d582012f978b0c7223675dc8903534499075d5d 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PageSetting.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @inject IDataSourceAppService DataSourceAppService @if (Page != null) diff --git a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySetting.razor b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySetting.razor index b8e11cdd846506630dafbd35d5293e6e370ac107..ac1e47101aa868c45ee0b313f11269beed28a067 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySetting.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySetting.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @using H.LowCode.MetaSchema @using H.LowCode.MetaSchema.DesignEngine diff --git a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/BasicPropertyItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/BasicPropertyItem.razor index 0c4bc2995edfbaaab24d964747696cbc4541f9b3..ee2f592d9049b79072d079d7017f347369f03406 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/BasicPropertyItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/BasicPropertyItem.razor @@ -1,15 +1,15 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @if (Component.IsContainer) { - 组件标识:@Component.ComponentId + 组件标识:@Component.PartsId } else {
- +
diff --git a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/ComponentPropertyItems/TablePropertyItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/ComponentPropertyItems/TablePropertyItem.razor index 49104148d4e4774aae89de2e2ca8eb8da0c4786b..f56bc89f1c5f155f5486b51f3c219caac5f86cff 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/ComponentPropertyItems/TablePropertyItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/ComponentPropertyItems/TablePropertyItem.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase
diff --git a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/DataSourcePropertyItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/DataSourcePropertyItem.razor index da463d9e6e4b58909e24dc74d365c8c0fe7fa464..92dcfb536e4f5374572571acdcf73806a66d0a71 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/DataSourcePropertyItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/DataSourcePropertyItem.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase @if (Component.IsSupportDataSource){
数据源
@@ -33,6 +33,12 @@ 配置数据源 } + else if (Component.DataSource.DataSourceGroupType == ComponentDataSourceGroupTypeEnum.List) + { + + } else{
@@ -50,6 +56,11 @@ + + + + @code { [CascadingParameter(Name = "pageCascading")] public PageCascadingModel PageCascading { get; set; } @@ -60,6 +71,7 @@ private bool _optionDataSourceVisible = false; private bool _tableDataSourceVisible = false; private bool _treeDataSourceVisible = false; + private bool _listDataSourceVisible = false; protected override async Task OnInitializedAsync() { @@ -81,6 +93,11 @@ _treeDataSourceVisible = true; } + private void ShowListDataSourceModal() + { + _listDataSourceVisible = true; + } + private async Task OnOptionDataSourceConfirmAsync(MouseEventArgs e) { await Task.CompletedTask; @@ -134,6 +151,11 @@ return await Task.FromResult(true); } + private async Task SaveListDataSourceAsync() + { + return await Task.FromResult(true); + } + private void OnDataSourcePropertyChange(string value) { Component.RefreshState(); diff --git a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/EventPropertyItem.razor b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/EventPropertyItem.razor index f7402cc9033b93223d2f8820505a9b95adfb261b..87248652d8ca690c6ad5974c4d5dcd0fb7823cd0 100644 --- a/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/EventPropertyItem.razor +++ b/src/DesignEngine/H.LowCode.DesignEngine/SettingPanel/PropertySettingItems/EventPropertyItem.razor @@ -1,5 +1,5 @@ @namespace H.LowCode.DesignEngine -@inherits DesignEngineLowCodeComponentBase +@inherits LowCodeComponentBase
事件
+
+ + @if (DataSource?.FixedData != null && DataSource.FixedData.Count > 0) + { +
+ @for (int i = 0; i < DataSource.FixedData.Count; i++) + { + var index = i; + var dataItem = DataSource.FixedData[index]; + + + + + + + + + + + + + + + + +
+ +