# 项目创建与管理 **本文档引用的文件** - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp) - [ProManager.cpp](file://cpp/Managers/ProManager.cpp) - [Project.cpp](file://cpp/ProblemZone/Project.cpp) - [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp) - [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp) - [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp) - [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp) - [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp) - [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp) ## 目录 1. [项目创建流程](#项目创建流程) 2. [项目类型对话框实现机制](#项目类型对话框实现机制) 3. [项目参数设置与测区定义](#项目参数设置与测区定义) 4. [项目数据模型与内存组织](#项目数据模型与内存组织) 5. [XML缓存与数据库同步](#xml缓存与数据库同步) 6. [项目类型扩展技术路径](#项目类型扩展技术路径) ## 项目创建流程 Geomative Studio的项目创建流程始于应用程序初始化阶段,在`GeoMative.cpp`中通过`InitInstance()`方法完成。系统首先建立与数据库的连接,然后初始化项目管理器(`CProManager`)、设备管理器(`CDevManager`)等核心组件。项目创建的核心入口是`CProManager::CreateProjectInDB()`方法,该方法通过显示`COpCreateProjectDlg`对话框收集用户输入的项目基本信息。 项目创建过程遵循严格的验证机制,首先检查项目名称是否已存在,若存在则提示用户"工程名称已经存在!"。项目信息包括工程编号(CN)、名称、描述、位置、日期、持续时间、监督员、管理员、负责人、品质保证员和标准等字段。系统支持自动生成唯一标识码(GUID)作为工程编号,确保项目标识的唯一性。 项目创建成功后,系统会自动为新项目创建默认测区(DefaultTestZone),并初始化相应的数据库记录。整个创建过程采用事务处理机制,确保数据的一致性和完整性。项目创建完成后,相关信息会被同步到缓存目录(CACHE/projects/)下的XML文件中,实现本地缓存与数据库的双重存储。 **Section sources** - [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L159-L442) - [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L341) - [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L79-L115) ## 项目类型对话框实现机制 系统为不同维度的测量项目提供了专门的对话框实现,包括`DialNew1DTask`、`DialNew2DTask`和`DialNew3DTask`三个类,分别处理一维、二维和三维测量任务的创建。这些对话框类继承自MFC的`CDialog`基类,通过资源文件定义用户界面布局,并在运行时动态填充数据。 ### 一维项目对话框(DialNew1DTask) `DialNew1DTask`对话框为用户提供了一维测量任务的配置界面。在`OnInitDialog()`方法中,系统初始化测试类型下拉框(电阻率、激电、自电),并从数据库查询可用的测量装置类型(AR)。用户选择装置类型后,系统会自动加载关联的测试脚本。发射周期选项支持从"自动"到64秒的多种选择,满足不同测量需求。 ```mermaid classDiagram class CDialNew1DTask { +m_strTaskName string +m_strTestPlace string +m_strSptName string +m_iTestType int +m_iAR int +m_iSptID int +m_iStacking int +m_iTxWave int +m_iTxPeriod int +OnInitDialog() bool +OnSelchangeCombo1dArray() void +OnSelchangeCombo1dTestType() void +OnOK() void } class CTaskDataOper { +QueryMediumInfo() void +QuerySptByAR() void +Create1DTask() int } CDialNew1DTask --> CTaskDataOper : "uses" ``` **Diagram sources ** - [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L200) ### 二维项目对话框(DialNew2DTask) `DialNew2DTask`对话框提供了更复杂的二维测量配置功能。除了基本的测试参数外,还包含电缆布线方式、电极间距、孔间距等专业设置。系统根据选择的测试类型动态调整可用的电缆布线选项,例如电阻率测量和激电测量有不同的布线要求。对于交叉孔(Cross Hole)类型的测量,系统会显示孔间距设置字段。 ```mermaid classDiagram class CDialNew2DTask { +m_iCableLayout int +m_iStatrLayer int +m_iEndLayer int +m_iStartElec int +m_iEndElec int +m_fEelcSpace float +m_iSkipCable int +m_iRollCnt int +OnInitDialog() bool +OnSelchangeCombo2dArray() void +OnSelchangeCombo2dScript() void +OnSelchangeCombo2dTestType() void +OnOK() void } class CTaskDataOper { +QueryCmInfo() void +Query2DSptInfo() bool +QuerySptElecTpMount() bool +Create2DTask() int } CDialNew2DTask --> CTaskDataOper : "uses" ``` **Diagram sources ** - [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L202-L400) ### 三维项目对话框(DialNew3DTask) `DialNew3DTask`对话框专为三维测量任务设计,提供了网格信息、步长设置等高级功能。用户选择测试脚本后,系统会自动解析并显示网格尺寸信息(X和Y方向的电极数量)。三维测量支持复杂的电极步长和距离设置,允许用户定义非均匀网格布局。 ```mermaid classDiagram class CDialNew3DTask { +m_rcGridSize CRect +m_fXElecStep float +m_fYElecStep float +m_fXElecDistance float +m_fYElecDistance float +m_byLineDirection byte +OnInitDialog() bool +OnSelchangeCombo3dArray() void +OnSelchangeCombo3dScript() void +OnSelchangeCombo3dTestType() void +OnOK() void } class CTaskDataOper { +QuerySptRectByARandSCname() void +Create3DTask() int } CDialNew3DTask --> CTaskDataOper : "uses" ``` **Diagram sources ** - [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L402-L600) **Section sources** - [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381) - [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665) - [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570) ## 项目参数设置与测区定义 项目参数设置是测量任务创建过程中的关键环节,系统通过一系列验证规则确保输入数据的有效性。每个对话框的`OnOK()`方法都包含完整的参数验证逻辑,对必填字段进行空值检查,对数值范围进行边界验证。 ### 参数验证规则 系统实施严格的参数验证机制: - **任务名称**:不能为空,长度限制50个字符 - **迭代次数**:必须在1-255范围内 - **电极间距**:必须大于零 - **采样间隔**:必须在0-30000毫秒范围内 - **孔间距**:必须大于电极间距(仅交叉孔测量) 当用户输入不符合要求时,系统会弹出相应的错误提示,如"任务名不能为空"、"迭代次数的取值范围为1到255"等,并阻止任务创建过程继续执行。 ### 测区定义机制 测区(Testing Zone)是项目的基本组成单元,系统通过`COpCreateTzDlg`对话框管理测区的创建。每个项目创建时都会自动包含一个默认测区。测区定义包含名称、位置、描述和创建日期等基本信息。系统在`ProManager.cpp`中通过`InsertDefaultTzToProject()`方法实现默认测区的自动创建。 测区与测量任务之间存在层级关系,一个项目可以包含多个测区,每个测区可以包含多个测量任务。这种层次结构通过数据库中的外键关系(PRID、TZID)来维护,确保数据的完整性和一致性。 ```mermaid flowchart TD Start([开始创建任务]) --> ValidateInput["验证输入参数"] ValidateInput --> InputValid{"参数有效?"} InputValid --> |否| ReturnError["显示错误信息"] InputValid --> |是| CheckDependencies["检查依赖项"] CheckDependencies --> DependenciesValid{"依赖项有效?"} DependenciesValid --> |否| HandleDependencyError["处理依赖错误"] DependenciesValid --> |是| CreateTaskRecord["创建任务数据库记录"] CreateTaskRecord --> CreateChannelRecord["创建通道记录"] CreateChannelRecord --> ImportScriptData["导入脚本数据"] ImportScriptData --> InsertGroundResistance["插入接地电阻信息"] InsertGroundResistance --> CommitTransaction["提交事务"] CommitTransaction --> End([任务创建完成]) ReturnError --> End HandleDependencyError --> End ``` **Diagram sources ** - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L200) - [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L91) **Section sources** - [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L365) - [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L414-L664) - [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L411-L568) - [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L91) ## 项目数据模型与内存组织 系统的项目数据模型基于面向对象设计,核心类包括`CProject`、`CTestingZone`和`CTask`等。这些类通过`CProManager`进行统一管理,并在内存中形成层次化的数据结构。 ### 核心数据结构 `CProject`类封装了项目的所有属性,包括工程编号(CN)、名称、描述、位置、日期、持续时间、监督员、管理员、负责人、品质保证员和标准等。这些属性在构造函数中从数据库查询并初始化: ```mermaid classDiagram class CProject { +m_szCN string +m_szPRname string +m_szDesc string +m_szLocation string +m_szPRdate string +m_szDuration string +m_szPS string +m_szCS string +m_szPM string +m_szQAS string +m_szStandard string +m_dwID DWORD +CProject(DWORD, _ConnectionPtr&) constructor +~CProject() destructor +ShowDetailInfo(CListCtrl&) bool } class CTestingZone { +m_szCN string +m_szTZname string +m_szDesc string +m_szLocation string +m_szCdate string +m_dwID DWORD +m_dwPRID DWORD +CTestingZone(DWORD, _ConnectionPtr&) constructor +~CTestingZone() destructor } class CTask { +m_strTDName string +m_strTDCN string +m_strTestPlace string +m_iTZID int +m_iSCID int +m_strSCCN string +m_strSptName string +m_ucStype byte +m_ucTtype byte +m_iEamount int +m_iTPmount int +m_ucCHamount byte +m_iN int +m_ucTRwave byte +m_ucTRfrequency byte +m_iSAfrequency int +m_strCdate string +m_strCtime string +m_tCreateTime time_t +CTask(DWORD, _ConnectionPtr&) constructor +~CTask() destructor } CProject --> CTestingZone : "1..*" CTestingZone --> CTask : "1..*" ``` **Diagram sources ** - [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L81) - [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L153-L182) ### 内存管理机制 系统采用智能缓存机制管理项目数据,通过`m_dmsLinkList`链表存储已加载的项目、测区和任务对象。`CProManager::GetDMS()`方法实现了对象的延迟加载和缓存重用: 1. 当请求特定数据对象时,首先在缓存链表中查找 2. 如果找到则直接返回缓存对象 3. 如果未找到则从数据库加载并创建新对象,然后加入缓存链表 这种机制避免了重复的数据库查询,提高了系统性能。同时,系统在应用程序退出时通过析构函数清理所有缓存对象,防止内存泄漏。 **Section sources** - [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L81) - [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L153-L182) ## XML缓存与数据库同步 系统采用XML文件作为本地缓存机制,与中央数据库保持同步。这种双重存储策略既保证了数据的持久性,又提高了本地访问性能。 ### 缓存文件结构 项目相关的XML缓存文件存储在`CACHE/`目录下,主要包含: - `project.xml`:项目基本信息 - `testzone.xml`:测区配置信息 - 任务特定的XML文件:测量任务参数 `project.xml`文件采用标准的XML格式,包含项目名称、编号、描述、位置、创建日期等元数据: ```xml 示例项目 PRJ-2023-001 项目描述 测量地点 2023-01-01 00:00:00 2023-01-01 00:00:00 30 监督员姓名 管理员姓名 负责人姓名 品质保证员姓名 标准名称 1 ``` ### 同步策略 系统在项目创建和修改时执行同步操作: 1. 首先在数据库中创建记录 2. 然后生成对应的XML缓存文件 3. 最后将文件传输到设备(如果连接) 同步过程采用事务控制,确保数据库和缓存的一致性。如果文件传输失败,系统会回滚数据库操作,保持数据完整性。`CreateProjectInDev()`方法负责处理项目到设备的同步,包括创建目录结构、生成XML文件和文件传输等步骤。 ```mermaid sequenceDiagram participant User as "用户" participant Dialog as "创建对话框" participant TaskDataOper as "TaskDataOper" participant Database as "数据库" participant FileSystem as "文件系统" User->>Dialog : 提交任务参数 Dialog->>TaskDataOper : 调用CreateXDTTask() TaskDataOper->>Database : 开始事务 Database-->>TaskDataOper : 事务开始 TaskDataOper->>Database : 插入任务记录 Database-->>TaskDataOper : 记录ID TaskDataOper->>Database : 插入通道记录 TaskDataOper->>Database : 导入脚本数据 TaskDataOper->>Database : 插入接地电阻 TaskDataOper->>FileSystem : 生成XML缓存 FileSystem-->>TaskDataOper : 文件创建成功 TaskDataOper->>Database : 提交事务 Database-->>TaskDataOper : 事务提交 TaskDataOper-->>Dialog : 返回任务ID Dialog-->>User : 创建成功 ``` **Diagram sources ** - [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L383-L447) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L148-L197) **Section sources** - [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L383-L447) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L148-L197) ## 项目类型扩展技术路径 系统设计具有良好的可扩展性,开发者可以通过以下路径扩展项目类型和功能。 ### 新增项目模板 要添加新的项目模板,需要执行以下步骤: 1. 在数据库的`medium`表中添加新的测量装置类型 2. 在相应的脚本表(`script1d`、`script2d`、`script3d`)中添加配套的测量脚本 3. 修改`QueryMediumInfo()`方法的查询逻辑,确保新模板能被正确检索 ### 自定义参数字段 扩展自定义参数字段需要: 1. 修改数据库表结构,添加新的字段列 2. 更新`STXDTTaskParam`结构体,添加对应的成员变量 3. 在对话框资源文件中添加新的UI控件 4. 在`DoDataExchange()`方法中绑定新控件 5. 在`OnOK()`方法中添加参数验证逻辑 ### 项目验证规则 自定义验证规则的实现方式: 1. 在对话框类中添加新的验证方法 2. 在`OnOK()`方法中调用验证方法 3. 使用`AfxMessageBox()`或`MessageBoxEx()`显示验证错误信息 4. 返回前阻止基类的`OnOK()`调用 ### 扩展示例 以下是一个添加温度补偿参数的扩展示例: ```mermaid classDiagram class CDialNew2DTask { +m_fTemperature float +m_iCompensationMethod int +AddTemperatureControls() void +ValidateTemperature() bool } class ST2DTaskParam { +fTemperature float +iCompensationMethod int } CDialNew2DTask --> ST2DTaskParam : "包含" ``` 开发者可以基于现有架构,通过类似的模式添加各种专业测量参数和验证规则,满足特定应用场景的需求。 **Section sources** - [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L365) - [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L414-L664) - [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L411-L568) - [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L200)