This commit is contained in:
coco
2026-07-03 16:05:30 +08:00
commit df489d5640
1101 changed files with 779140 additions and 0 deletions
@@ -0,0 +1,146 @@
# 任务包与地形配置
<cite>
**本文档引用文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [任务包配置功能](#任务包配置功能)
3. [地形参数设置功能](#地形参数设置功能)
4. [任务包数据持久化机制](#任务包数据持久化机制)
5. [地形参数文件处理流程](#地形参数文件处理流程)
6. [用户界面操作指南](#用户界面操作指南)
7. [开发者实现解析](#开发者实现解析)
8. [结论](#结论)
## 引言
本文档全面阐述Geomative Studio软件中的任务包配置(DialCfgTaskPacket)与地形参数设置(DialCfgTerrain)两大核心功能。文档旨在为用户提供清晰的图形化界面操作指南,同时为开发者深入解析底层数据处理与持久化机制。通过详细说明调度参数配置、环境参数输入、数据验证规则及配置保存流程,确保用户能够高效、准确地完成地质勘探任务的前期配置工作。
## 任务包配置功能
任务包配置功能允许用户将多个测量任务组织成一个有序的执行序列。用户可以通过图形化界面选择并添加任务到任务包中,系统会自动管理任务的执行顺序。该功能的核心是调度参数的配置,包括循环次数和采集间隔,这些参数共同决定了任务包的执行时序。
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
## 地形参数设置功能
地形参数设置功能用于输入测量区域的高程和地质条件信息。用户可以通过界面直接输入或从外部文件导入地形数据点,每个数据点包含水平(X)和垂直(Y)坐标。系统支持两种地形数据标志:水平距离和垂直距离,用户可根据实际测量需求进行选择。此外,用户还需指定第一个电极对应的地形数据点编号,以建立电极位置与地形数据的映射关系。
**Section sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
## 任务包数据持久化机制
任务包的配置数据通过CTaskDataOper类实现内存与数据库间的持久化。当用户在DialCfgTaskPacket界面完成配置并点击“保存”时,系统会调用CTaskDataOper::InsertTaskPacketInfo方法,将任务包信息写入数据库。
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant 界面 as "DialCfgTaskPacket"
participant 操作类 as "CTaskDataOper"
participant 数据库 as "数据库"
用户->>界面 : 点击“保存”
界面->>界面 : 验证输入参数
界面->>操作类 : 调用InsertTaskPacketInfo()
操作类->>数据库 : 开始事务
操作类->>数据库 : 删除旧的tdTaskPacket记录
操作类->>数据库 : 插入新的任务包属性
操作类->>数据库 : 删除旧的tdTaskPacketInfo记录
操作类->>数据库 : 插入新的任务列表
操作类->>数据库 : 提交事务
操作类-->>界面 : 返回结果
界面-->>用户 : 显示“保存成功”消息
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L669-L715)
## 地形参数文件处理流程
地形参数的配置最终会保存到一个.dat格式的文件中。该流程涉及文件的读取、解析和写入操作。系统首先读取.dat文件的头部信息以确定装置类型,然后根据装置类型决定是否需要添加地形数据。在保存时,系统会从文件末尾开始查找零结束符的位置,然后在该位置写入新的地形数据,确保不破坏原有的测量脚本。
```mermaid
flowchart TD
Start([开始]) --> CheckFile["检查是否已导入dat文件"]
CheckFile --> |否| ShowError1["提示:请先导入dat文件"]
CheckFile --> |是| CheckFlag["检查地形数据标志"]
CheckFlag --> |未选择| ShowError2["提示:请先选择地形数据标志"]
CheckFlag --> |已选择| CheckData["检查地形数据点"]
CheckData --> |无数据| ShowError3["提示:请输入地形数据"]
CheckData --> |有数据| CheckElectrode["验证第一个电极编号"]
CheckElectrode --> |无效| ShowError4["提示:编号必须在有效范围内"]
CheckElectrode --> |有效| OpenFile["打开dat文件"]
OpenFile --> ReadHeader["读取文件头部"]
ReadHeader --> ParseHeader["解析装置类型"]
ParseHeader --> CheckType["判断是否需要地形数据"]
CheckType --> |不需要| ShowError5["提示:该装置无需地形数据"]
CheckType --> |需要| FindEnd["查找文件末尾零结束符"]
FindEnd --> |未找到| ShowError6["提示:未找到结束符"]
FindEnd --> |找到| WriteData["写入地形数据"]
WriteData --> CloseFile["关闭文件"]
CloseFile --> ShowSuccess["提示:保存成功"]
ShowError1 --> End([结束])
ShowError2 --> End
ShowError3 --> End
ShowError4 --> End
ShowError5 --> End
ShowError6 --> End
ShowSuccess --> End
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
## 用户界面操作指南
### 任务包配置操作步骤
1. **打开配置界面**:在软件主界面中,导航至任务管理模块,选择“任务包配置”功能。
2. **选择任务**:从下拉菜单中选择一个待添加的任务。
3. **添加任务**:点击“添加”按钮,将选中的任务加入任务列表。系统会自动检查任务是否重复。
4. **配置调度参数**
* **循环次数**:输入任务包需要重复执行的总次数,有效范围为1-60000。
* **采集间隔**:输入每次循环之间的等待时间(秒),有效范围为1-60000。
* **PLC ID**:输入可编程逻辑控制器的标识符。
5. **删除任务**:在任务列表中选中某项,点击“删除”按钮可将其移除。
6. **保存配置**:确认所有参数无误后,点击“确定”按钮保存配置。系统会进行输入验证,若通过则提示“保存成功”。
### 地形参数设置操作步骤
1. **打开配置界面**:在软件主界面中,导航至地形设置模块,选择“地形参数设置”功能。
2. **导入数据文件**:点击“导入文件”按钮,选择一个.dat格式的测量脚本文件。
3. **输入地形数据**
* 在列表中点击“添加”按钮。
* 在X和Y输入框中分别输入地形点的水平和垂直坐标。
* 点击“添加”确认,数据点将被加入列表。
4. **修改或删除数据**:选中列表中的数据点,可通过“修改”按钮更新坐标,或通过“删除”按钮移除。
5. **选择地形标志**:从下拉框中选择“水平距离”或“垂直距离”。
6. **设置电极映射**:在“第一个电极对应的地形数据点编号”输入框中,输入一个正整数,该编号必须在已输入的地形数据点范围内。
7. **保存数据**:点击“保存数据”按钮,系统会将地形信息写入之前导入的.dat文件。
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L47-L300)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L450-L693)
## 开发者实现解析
### CTaskDataOper类核心方法
* **`QueryTaskPacketAttr`**: 该方法从数据库的`tdTaskPacket`表中查询当前的循环次数、采集间隔和PLC ID,并将结果填充到传入的引用参数中。它在DialCfgTaskPacket的`OnInitDialog`中被调用,用于初始化界面显示。
* **`InsertTaskPacketInfo`**: 这是任务包持久化的关键方法。它接收一个任务信息向量和一个属性结构体。方法内部使用数据库事务,首先清空`tdTaskPacket``tdTaskPacketInfo`两个表,然后重新插入新的配置数据,确保数据的一致性。
### 数据结构与映射关系
地形参数与测量脚本的空间映射关系至关重要。测量脚本(.dat文件)定义了电极的排列和测量序列,而地形数据则提供了这些电极所在位置的高程信息。通过“第一个电极对应的地形数据点编号”这一参数,系统能够将脚本中的第一个电极与地形数据列表中的某个点对齐,从而推算出所有电极的精确位置。这种映射直接影响后续数据采集的精度,尤其是在地形起伏较大的区域,准确的高程数据是进行精确电阻率反演的基础。
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L669-L715)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L147-L157)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
## 结论
任务包配置与地形参数设置是Geomative Studio软件中两个紧密关联且至关重要的功能模块。任务包配置通过循环次数和采集间隔等参数,实现了对复杂测量任务的自动化调度,极大地提升了野外作业的效率。地形参数设置则通过精确的高程数据输入,为后续的数据采集和反演分析提供了关键的环境信息,确保了测量结果的准确性。两者的结合,使得软件能够适应多样化的地质勘探场景,为用户提供了一套完整、可靠的测量解决方案。
@@ -0,0 +1,231 @@
# 任务包配置
<cite>
**本文档引用的文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [Constant.h](file://h/Constant.h)
- [DataMngStruct.h](file://h/DataMngStruct.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档全面说明Geomative Studio中的任务包配置功能(DialCfgTaskPacket),涵盖调度参数配置、图形界面操作流程以及底层数据持久化机制。文档详细阐述了循环时间、采集间隔和PLC ID等关键参数的配置规则,包括输入验证范围和默认值设定。同时为用户提供任务列表管理的操作指南,并为开发者解析CTaskDataOper类中InsertTaskPacketInfo方法的实现逻辑。
## 项目结构
任务包配置功能主要分布在Views和Operator两个模块中,通过数据库持久化任务配置信息。系统采用MFC框架构建图形用户界面,通过ADO接口与数据库交互。
```mermaid
graph TB
subgraph "用户界面层"
DialCfgTaskPacket["DialCfgTaskPacket (任务包配置对话框)"]
end
subgraph "业务逻辑层"
TaskDataOper["CTaskDataOper (任务数据操作类)"]
end
subgraph "数据访问层"
Database["数据库 (Access/SQL Server)"]
end
DialCfgTaskPacket --> TaskDataOper
TaskDataOper --> Database
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
## 核心组件
任务包配置功能的核心组件包括DialCfgTaskPacket对话框类和CTaskDataOper数据操作类。DialCfgTaskPacket负责用户界面交互和输入验证,CTaskDataOper负责数据持久化和数据库操作。两个组件通过STTaskPacketAttr结构体和STTdBrowseInfo向量进行数据传递,实现了界面与业务逻辑的分离。
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 架构概述
任务包配置功能采用典型的三层架构设计,包括表示层、业务逻辑层和数据访问层。用户通过图形界面输入配置参数,系统进行验证后,将任务包信息持久化到数据库中。
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant 界面 as "DialCfgTaskPacket"
participant 业务逻辑 as "CTaskDataOper"
participant 数据库 as "数据库"
用户->>界面 : 打开任务包配置对话框
界面->>业务逻辑 : 查询可选任务列表
业务逻辑->>数据库 : 执行SQL查询
数据库-->>业务逻辑 : 返回任务列表
业务逻辑-->>界面 : 返回任务列表数据
界面->>界面 : 显示任务列表和配置参数
用户->>界面 : 输入循环时间、采集间隔、PLC ID
用户->>界面 : 添加/删除任务
用户->>界面 : 点击保存
界面->>界面 : 验证输入参数
界面->>业务逻辑 : 调用InsertTaskPacketInfo
业务逻辑->>数据库 : 开始事务
业务逻辑->>数据库 : 删除旧的任务包配置
业务逻辑->>数据库 : 插入新的任务包属性
业务逻辑->>数据库 : 插入任务包包含的任务
业务逻辑->>数据库 : 提交事务
数据库-->>业务逻辑 : 返回操作结果
业务逻辑-->>界面 : 返回保存结果
界面->>用户 : 显示保存成功/失败消息
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 详细组件分析
### 任务包配置对话框分析
DialCfgTaskPacket类实现了任务包配置的图形用户界面,提供任务选择、参数输入和任务列表管理功能。
```mermaid
classDiagram
class CDialCfgTaskPacket {
+CListCtrl m_listTaskPacket
+CComboBox m_cmbTaskName
+OnInitDialog() bool
+OnButtonAdd() void
+OnButtonDel() void
+OnOK() void
+InitialTaskList() void
+IsRepeatTask(int) bool
}
CDialCfgTaskPacket --> CTaskDataOper : "使用"
CDialCfgTaskPacket --> STTaskPacketAttr : "使用"
CDialCfgTaskPacket --> STTdBrowseInfo : "使用"
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L18-L301)
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L18-L301)
### 任务数据操作类分析
CTaskDataOper类负责任务相关数据的持久化操作,包括任务包配置的保存和查询。
```mermaid
classDiagram
class CTaskDataOper {
+InsertTaskPacketInfo(vector<STTdBrowseInfo>, STTaskPacketAttr) bool
+QueryTaskPacketAttr(int&, int&, CString&) bool
+QueryTdBrowseInfo(vector<STTdBrowseInfo>&, int, int) bool
+QueryTaskPacketInfo(vector<STTdBrowseInfo>&) bool
}
class STTaskPacketAttr {
+int iLoopTimes
+int iInterval
+CString strPlcID
}
class STTdBrowseInfo {
+int iTaskID
+CString strTaskName
}
CTaskDataOper --> STTaskPacketAttr
CTaskDataOper --> STTdBrowseInfo
```
**图示来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
- [DataMngStruct.h](file://h/DataMngStruct.h#L1-L23)
**本节来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
### 调度参数配置流程分析
任务包配置涉及循环时间、采集间隔和PLC ID三个核心调度参数的配置,系统实施严格的输入验证规则。
```mermaid
flowchart TD
Start([开始配置]) --> ValidateLoopTime["验证循环时间"]
ValidateLoopTime --> LoopTimeValid{"1-60000之间?"}
LoopTimeValid --> |否| ShowLoopTimeError["显示错误消息: 循环次数的值必须在1-60000之间"]
LoopTimeValid --> |是| ValidateInterval["验证采集间隔"]
ValidateInterval --> IntervalValid{"1-60000之间?"}
IntervalValid --> |否| ShowIntervalError["显示错误消息: 时间间隔的值必须在1-60000之间"]
IntervalValid --> |是| ValidatePLCID["验证PLC ID"]
ValidatePLCID --> PLCIDValid{"已输入?"}
PLCIDValid --> |否| ShowPLCIError["显示错误消息: 请输入PLC ID"]
PLCIDValid --> |是| SaveConfig["保存配置"]
SaveConfig --> BeginTransaction["开始数据库事务"]
BeginTransaction --> DeleteOldConfig["删除旧的任务包配置"]
DeleteOldConfig --> InsertAttr["插入任务包属性"]
InsertAttr --> InsertTasks["插入任务包包含的任务"]
InsertTasks --> CommitTransaction["提交事务"]
CommitTransaction --> Success{"成功?"}
Success --> |是| ShowSuccess["显示保存成功"]
Success --> |否| ShowFail["显示保存失败"]
ShowSuccess --> End([配置完成])
ShowFail --> End
ShowLoopTimeError --> End
ShowIntervalError --> End
ShowPLCIError --> End
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
## 依赖分析
任务包配置功能依赖于多个系统组件和外部库,形成复杂的依赖关系网络。
```mermaid
graph TD
DialCfgTaskPacket --> TaskDataOper
TaskDataOper --> ADO["ADO数据库接口"]
TaskDataOper --> GUCodeCreator["GUCodeCreator"]
TaskDataOper --> FileOperTools["FileOperTools"]
TaskDataOper --> AutoLock["AutoLock"]
ADO --> Database
GUCodeCreator --> UUID["UUID生成"]
FileOperTools --> FileSystem["文件系统"]
AutoLock --> Thread["多线程同步"]
style DialCfgTaskPacket fill:#f9f,stroke:#333
style TaskDataOper fill:#bbf,stroke:#333
style Database fill:#f96,stroke:#333
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
**本节来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
## 性能考虑
任务包配置功能在设计时考虑了性能优化,特别是在数据库操作方面采用了事务处理机制,确保数据一致性的同时提高操作效率。系统在保存任务包配置时,先删除旧配置再插入新配置,避免了复杂的更新逻辑。对于大量任务的处理,建议分批操作以减少内存占用和数据库压力。
## 故障排除指南
当任务包配置功能出现问题时,可按照以下步骤进行排查:
1. **界面无法打开**:检查DialCfgTaskPacket对话框的资源定义是否正确,确认IDD常量定义无误。
2. **任务列表为空**:验证数据库连接是否正常,确认td表中存在可配置的任务。
3. **保存失败**:检查数据库事务是否被正确提交,确认tdTaskPacket和tdTaskPacketInfo表的结构是否符合预期。
4. **参数验证错误**:确认循环时间和采集间隔在1-60000的有效范围内,确保PLC ID已正确输入。
5. **重复任务无法添加**:系统已实现重复检测机制,相同任务ID的任务不能重复添加。
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L47-L108)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 结论
任务包配置功能为Geomative Studio提供了灵活的任务调度能力,通过DialCfgTaskPacket和CTaskDataOper组件的协同工作,实现了用户友好的界面操作和可靠的数据持久化。系统对循环时间、采集间隔和PLC ID等关键参数实施了严格的验证规则,确保配置的正确性。开发者可通过理解InsertTaskPacketInfo方法的实现逻辑,进一步扩展和定制任务包配置功能,满足特定的自动化测量需求。
@@ -0,0 +1,145 @@
# 地形配置
<cite>
**本文档引用文件**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
- [SP2DTd.cpp](file://cpp/ProblemZone/SP2DTd.cpp)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp)
- [Res3DDatFileRecord.cpp](file://cpp/Tools/Res3DDatFileRecord.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [地形参数输入界面](#地形参数输入界面)
3. [数据格式与验证](#数据格式与验证)
4. [地形数据存储机制](#地形数据存储机制)
5. [地形参数与测量脚本的映射关系](#地形参数与测量脚本的映射关系)
6. [实际应用案例](#实际应用案例)
7. [结论](#结论)
## 简介
地形参数设置功能(DialCfgTerrain)是Geomative Studio软件中的一个关键模块,用于配置测量任务中的环境参数。该功能允许用户输入地形高程、地质条件和表面特征等信息,这些信息对于后续的数据采集精度和解释结果具有重要影响。通过图形化界面,用户可以方便地进行参数输入、验证和保存,确保测量方案的科学性和准确性。
**Section sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L1-L72)
## 地形参数输入界面
地形参数输入界面提供了直观的操作方式,用户可以通过该界面完成地形数据的配置。界面主要包括以下几个部分:
- **地形数据标志**:用户可以选择水平距离或垂直距离作为地形数据的标志。
- **地形数据明细**:用户可以在此列表中添加、修改和删除地形数据点,每个数据点包含ID、X坐标和Y坐标。
- **第一个电极对应的地形数据点编号**:用户需要指定第一个电极对应的地形数据点编号,以便系统正确映射地形数据与电极位置。
```mermaid
graph TD
A[地形参数输入界面] --> B[地形数据标志]
A --> C[地形数据明细]
A --> D[第一个电极对应的地形数据点编号]
B --> E[水平距离]
B --> F[垂直距离]
C --> G[添加数据点]
C --> H[修改数据点]
C --> I[删除数据点]
D --> J[输入编号]
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L77-L81)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L25-L29)
## 数据格式与验证
为了确保地形数据的准确性和一致性,系统对输入的数据进行了严格的格式验证。具体要求如下:
- **X坐标和Y坐标**:必须为浮点数,且绝对值小于100000。
- **地形数据点编号**:必须为正整数,且在1到地形数据点总数之间。
- **地形数据标志**:必须选择水平距离或垂直距离之一。
```mermaid
flowchart TD
Start([开始]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ReturnError["返回错误信息"]
InputValid --> |是| CheckDataCount["检查数据点数量"]
CheckDataCount --> DataCountValid{"数据点数量 > 0?"}
DataCountValid --> |否| ReturnError
DataCountValid --> |是| CheckFirstElectrode["检查第一个电极编号"]
CheckFirstElectrode --> FirstElectrodeValid{"编号在范围内?"}
FirstElectrodeValid --> |否| ReturnError
FirstElectrodeValid --> |是| SaveData["保存数据"]
SaveData --> End([结束])
ReturnError --> End
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L472-L537)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L62)
## 地形数据存储机制
地形数据在系统中以特定的格式存储,并通过CTaskDataOper类进行管理和处理。具体存储机制如下:
- **数据结构**:地形数据以二维数组的形式存储,每个数据点包含X坐标和Y坐标。
- **文件格式**:地形数据保存在.dat文件中,文件末尾包含多个零作为结束符。
- **数据库存储**:地形数据的相关信息(如地形数据标志、数据点数量等)存储在数据库的`t2dtg`表中。
```mermaid
classDiagram
class CTaskDataOper {
+int m_iExplainStartIndex
+CString m_strDatFilePath
+bool CheckValidBeforSave()
+void OnButtonSaveData()
+int GetDevArrayFromText(const CString& strInfo)
+int GetWriteIndexFromEndTxt(CString strInfo, int &iEndZeroCnt)
+void InitUIByLanguage(int iLanguage)
}
class DialCfgTerrain {
+CEdit m_edit1stPtIndex
+CComboBox m_cmbTerrainDataFlag
+CListCtrl m_ctrlTerrainData
+CListCtrl m_ctrlRemarkHeader
+CListCtrl m_ctrlRemarkEnd
+CListCtrl m_ctrlRemarkDetail
}
CTaskDataOper --> DialCfgTerrain : "使用"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L44-L817)
- [TaskDataOper.h](file://h/TaskDataOper.h#L42-L72)
## 地形参数与测量脚本的映射关系
地形参数与测量脚本之间存在紧密的映射关系,这种关系确保了测量数据的准确性和可靠性。具体映射过程如下:
- **数据读取**:系统从.dat文件中读取地形数据,并解析出地形数据标志和数据点数量。
- **数据写入**:将解析后的地形数据写入到测量脚本中,确保每个测点的地形信息与实际位置一致。
- **数据验证**:在写入过程中,系统会验证地形数据的完整性和正确性,防止数据丢失或错误。
```mermaid
sequenceDiagram
participant User as "用户"
participant Interface as "图形界面"
participant Controller as "控制器"
participant Database as "数据库"
User->>Interface : 输入地形数据
Interface->>Controller : 提交数据
Controller->>Controller : 验证数据格式
Controller->>Database : 保存地形数据
Database-->>Controller : 确认保存成功
Controller-->>Interface : 显示成功消息
Interface-->>User : 通知用户
```
**Diagram sources**
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp#L4672-L4823)
- [SP2DTd.cpp](file://cpp/ProblemZone/SP2DTd.cpp#L3248-L3252)
## 实际应用案例
### 案例一:复杂地形测量
在一个复杂的山区环境中,用户需要进行高精度的地质测量。通过地形参数设置功能,用户可以精确输入每个测点的地形高程和表面特征,确保测量数据的准确性。系统根据这些参数自动调整测量脚本,优化测量路径,提高数据采集效率。
### 案例二:城市地下管线探测
在城市地下管线探测项目中,地形参数设置功能帮助用户快速配置不同区域的地形条件。通过导入已有的地形数据文件,用户可以快速完成参数设置,减少现场工作量。系统根据地形数据生成最优的测量方案,确保探测结果的可靠性。
## 结论
地形参数设置功能(DialCfgTerrain)是Geomative Studio软件中不可或缺的一部分,它通过图形化界面和严格的数据验证机制,确保了地形数据的准确性和一致性。该功能不仅提高了测量任务的效率,还显著提升了数据采集的精度和解释结果的可靠性。通过合理的地形参数配置,用户可以更好地指导测量方案的设计,实现更高质量的地质勘探。
@@ -0,0 +1,183 @@
# 任务配置与调度
<cite>
**本文档引用的文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h)
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp)
- [DialTimerTask.h](file://h/DialTimerTask.h)
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [任务包配置 (DialCfgTaskPacket)](#任务包配置-dialcfgtaskpacket)
3. [地形参数设置 (DialCfgTerrain)](#地形参数设置-dialcfgterrain)
4. [定时任务 (DialTimerTask)](#定时任务-dialtimertask)
5. [循环任务管理 (DialLoopTaskQuery, DialManageLoopTask)](#循环任务管理-diallooptaskquery-dialmanagelooptask)
6. [任务树形结构与用户交互](#任务树形结构与用户交互)
7. [任务调度算法与状态机](#任务调度算法与状态机)
8. [任务序列化与反序列化机制](#任务序列化与反序列化机制)
9. [设备通信协议映射](#设备通信协议映射)
10. [操作指南](#操作指南)
## 引言
本系统提供了一套完整的任务配置与调度解决方案,涵盖了从任务创建、参数配置、地形数据管理到任务调度执行的全生命周期管理。系统通过任务包、定时任务和循环任务三种核心模式,实现了灵活、可靠的任务自动化。任务包允许用户将多个独立任务组合成一个有序序列,并进行循环执行;定时任务支持在指定时间点自动触发测量任务;循环任务则提供了更复杂的周期性执行策略。所有任务数据均通过统一的数据结构进行组织,并与设备通信协议紧密映射,确保了配置信息能够准确无误地传输到测量设备并执行。
## 任务包配置 (DialCfgTaskPacket)
该模块实现了任务包的创建、编辑和管理功能。用户可以从现有任务列表中选择任务,将其添加到任务包中,并设置循环次数、执行间隔和PLC ID等全局属性。任务包本质上是一个有序的任务序列,其执行遵循“循环次数”次,每次循环内按顺序执行所有任务,任务间间隔为“时间间隔”秒。
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L55)
- [TaskDataOper.h](file://h/TaskDataOper.h#L324-L335)
## 地形参数设置 (DialCfgTerrain)
该模块负责为测量任务配置地形数据。用户可以通过手动输入或导入.dat文件的方式,添加一系列包含X、Y坐标的地形点。系统支持两种地形数据标志:水平距离和垂直距离。配置完成后,地形数据将被写入到与任务关联的原始.dat文件末尾,供设备在测量时使用。
**Section sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L1-L73)
## 定时任务 (DialTimerTask)
该模块实现了基于时间的定时任务调度功能。用户可以为任意任务设置一个未来的执行时间点。系统会将这些定时任务存储在数据库中,并在到达指定时间时自动触发任务执行。为了区分由定时器自动创建的任务和用户手动创建的任务,系统使用了任务ID的最高位作为标志位(0x80000000)。
**Section sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L1-L238)
- [DialTimerTask.h](file://h/DialTimerTask.h#L1-L61)
- [TaskDataOper.h](file://h/TaskDataOper.h#L275-L288)
## 循环任务管理 (DialLoopTaskQuery, DialManageLoopTask)
该模块提供了对循环任务的查询和管理功能。`DialLoopTaskQuery`用于从服务器查询当前存在的循环任务列表,用户可以选择一个或多个任务进行后续操作。`DialManageLoopTask`则是一个更高级的管理界面,它通过网络请求从服务器同步所有循环任务,并展示其详细信息,包括循环类型(次数循环或定时循环)、开始/结束时间以及包含的子任务列表。用户可以在此界面删除循环任务。
```mermaid
graph TD
A[用户界面] --> B[DialManageLoopTask]
B --> C{网络请求}
C --> |EN_REQ_DOWNLOAD_LOOP_TABLE| D[服务器]
D --> |返回循环任务表| C
C --> E[解析并显示任务列表]
E --> F[用户选择任务]
F --> G{用户操作}
G --> |删除| H[发送EN_CANCEL_LOOP_TASK_TRUST请求]
G --> |查看详情| I[发送EN_REQ_DOWNLOAD_LOOP_SUB_TABLE请求]
H --> D
I --> D
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L230-L251)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L520-L582)
**Section sources**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h#L1-L34)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h#L1-L70)
## 任务树形结构与用户交互
系统中的任务数据以树形结构进行组织,便于用户进行浏览和管理。任务树的根节点通常是项目或测区,其下包含不同类型的测量任务(如1D、2D、3D任务)。用户可以通过任务管理器界面直观地查看和操作这些任务。对于任务包和循环任务,它们在树形结构中表现为一个父节点,其子节点为包含的具体任务。用户交互逻辑主要通过对话框实现,例如`DialCfgTaskPacket`对话框允许用户通过“添加”、“删除”按钮来编辑任务包中的任务序列。
## 任务调度算法与状态机
系统的任务调度由多个组件协同完成。`TaskDataOper`类是核心的数据操作引擎,它负责与数据库交互,查询和管理所有任务的元数据。对于定时任务,系统在启动时会查询所有未来有效的定时任务,并在后台进行监控。当系统时间到达任务设定的执行时间时,调度器会触发任务执行流程。循环任务的调度逻辑则更为复杂,它由服务器端控制,客户端主要负责查询和管理。任务状态机的设计体现在任务的生命周期上,一个任务可以处于“待执行”、“执行中”、“已完成”或“已取消”等状态,这些状态通过数据库中的字段进行记录和同步。
## 任务序列化与反序列化机制
任务数据的序列化与反序列化主要通过`STQueryTaskBasicInfo`等结构体实现。这些结构体定义了任务的所有关键属性,如任务ID、名称、类型、脚本信息、电极配置等。当需要将任务信息从数据库读取到内存时,`TaskDataOper`类的`QueryTdBasicInfo`等方法会执行反序列化过程,将数据库记录填充到结构体实例中。反之,当需要保存任务配置时,系统会将结构体中的数据序列化为SQL语句或网络协议数据包。对于任务包,其序列化过程涉及将`STTdBrowseInfo`结构体的向量(vector)与`STTaskPacketAttr`结构体一起持久化到数据库。
**Section sources**
- [TaskDataOper.h](file://h/TaskDataOper.h#L126-L204)
- [TaskDataOper.h](file://h/TaskDataOper.h#L336-L335)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L356-L364)
## 设备通信协议映射
任务配置数据最终需要通过网络协议传输给测量设备(如GD10)。`CtrlProtocolDef.h`头文件定义了与设备通信的协议结构。例如,`STMeasuTaskParam`结构体直接映射了发送给设备的任务参数,其中包含了测试类型、发射周期、堆栈数、采样间隔等关键信息。当一个任务被调度执行时,系统会从数据库中查询该任务的详细信息,然后将其填充到`STMeasuTaskParam`等协议结构体中,最后通过TCP/IP网络发送给设备。这种映射关系确保了在软件界面上配置的参数能够准确地转化为设备可理解的指令。
```mermaid
classDiagram
class STQueryTaskBasicInfo {
+int iTaskID
+char szTaskName[60]
+int iTestType
+int iAR
+int iSptType
+float fXElecDistance
+float fYElecDistance
+UINT32 uiStartLayer
+UINT32 uiEndLayer
+UINT32 uiTimerTime
}
class STMeasuTaskParam {
+BYTE ucTestType
+BYTE ucTxPeriod
+BYTE ucSptType
+BYTE ucCableLayout
+BYTE ucStacking
+int iSAInterval
+float fElecSpace
+char ucTaskID[40]
}
class TaskDataOper {
+QueryTdBasicInfo(int, STQueryTaskBasicInfo*)
+QueryTimerTaskValiad(vector~STTimerTask~&, const SYSTEMTIME&)
}
class DialTimerTask {
+OnButtonAdd()
+OnButtonSave()
+OnInitDialog()
}
STQueryTaskBasicInfo --> TaskDataOper : "查询"
TaskDataOper --> STMeasuTaskParam : "映射"
DialTimerTask --> TaskDataOper : "调用"
```
**Diagram sources**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L111-L123)
- [TaskDataOper.h](file://h/TaskDataOper.h#L126-L204)
## 操作指南
### 创建任务包
1. 打开“任务包配置”对话框。
2. 在下拉列表中选择一个任务,点击“添加”按钮将其加入任务包列表。
3. 重复步骤2,按顺序添加所有需要的任务。
4. 在“循环次数”框中输入希望重复执行整个任务包的次数(1-60000)。
5. 在“时间间隔”框中输入每个任务执行后的等待时间(秒,1-60000)。
6. 输入PLC ID。
7. 点击“确定”保存配置。
### 配置地形数据
1. 打开“地形参数设置”对话框。
2. 点击“导入文件”按钮,选择一个.dat格式的原始数据文件。
3. 在列表中输入或修改地形点的X、Y坐标,点击“添加”或“修改”按钮。
4. 选择“地形数据标志”(水平或垂直距离)。
5. 在“第一个电极对应的地形数据点编号”中输入起始点编号。
6. 点击“保存数据”按钮,将地形信息写入原始.dat文件。
### 设置定时任务
1. 打开“定时任务”对话框。
2. 选择一个任务、设置执行日期和时间。
3. 输入PLC ID。
4. 点击“添加”按钮,该任务将出现在定时任务列表中。
5. 点击“保存”完成所有定时任务的设置。
### 管理循环任务
1. 打开“循环任务管理”对话框。
2. 系统会自动从服务器加载所有循环任务。
3. 在列表中选择一个循环任务,其包含的子任务会显示在下方。
4. 如需删除,选中任务后点击“删除”按钮。
@@ -0,0 +1,310 @@
# 定时任务管理
<cite>
**本文档引用文件**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp)
- [DialTimerTask.h](file://h/DialTimerTask.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp)
</cite>
## 目录
1. [定时任务管理概述](#定时任务管理概述)
2. [DialTimerTask对话框UI组件与交互逻辑](#dialtimertask对话框ui组件与交互逻辑)
3. [CTaskDataOper类技术实现细节](#ctaskdataoper类技术实现细节)
4. [定时器触发机制与任务状态机](#定时器触发机制与任务状态机)
5. [任务与设备通信协议集成](#任务与设备通信协议集成)
6. [任务执行失败处理机制](#任务执行失败处理机制)
## 定时任务管理概述
定时任务管理功能实现了任务的创建、时间规划、状态监控和执行触发的全流程控制。系统通过数据库表`task_timer`存储定时任务信息,结合系统时间进行任务触发判断。定时任务的核心流程包括:用户通过DialTimerTask对话框配置任务参数,系统将任务信息存储到数据库,定时器服务根据当前系统时间与任务计划时间的比较来触发任务执行。任务执行过程中,系统会更新任务状态,记录执行日志,并在失败时执行重试策略。
**Section sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L1-L238)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4426-L4455)
## DialTimerTask对话框UI组件与交互逻辑
DialTimerTask对话框提供了完整的定时任务配置界面,其UI组件布局和用户交互逻辑设计如下:
对话框主要包含以下UI组件:
- **IDC_DATETIMEPICKER_DATE**: 日期选择器,用于选择任务执行日期
- **IDC_DATETIMEPICKER_TIME**: 时间选择器,用于选择任务执行时间
- **IDC_COMBO_TASK_NAME**: 下拉组合框,用于选择要执行的任务名称
- **IDC_EDIT_PLC_ID**: 编辑框,用于输入PLC设备ID
- **IDC_LIST_TIMER_TASK**: 列表控件,显示已配置的定时任务列表,包含ID、任务名称、执行时间和PLC ID四列
- **IDC_BUTTON_ADD**: 添加按钮,用于将当前配置添加到任务列表
- **IDC_BUTTON_DEL**: 删除按钮,用于从任务列表中删除选中的任务
- **IDC_BUTTON_SAVE**: 保存按钮,用于保存所有配置的定时任务
用户交互逻辑如下:
1. 用户首先在下拉框中选择一个任务,然后输入PLC ID
2. 通过日期和时间选择器设置任务执行时间
3. 点击"添加"按钮,系统会验证输入的有效性(确保选择了任务、输入了PLC ID、时间不早于当前时间),然后将任务添加到列表中
4. 任务名称会自动生成为"原任务名_YYYYMMDDHHMM"格式,确保唯一性
5. 用户可以多次添加任务,形成任务队列
6. 点击"删除"按钮可移除选中的任务
7. 最后点击"保存"按钮,系统会先删除标记为删除的任务,然后保存新的定时任务到数据库
```mermaid
flowchart TD
Start([开始配置定时任务]) --> SelectTask["选择任务"]
SelectTask --> InputPLCID["输入PLC ID"]
InputPLCID --> SetDateTime["设置日期和时间"]
SetDateTime --> ValidateInput["验证输入有效性"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ShowError["显示错误信息"]
InputValid --> |是| AddToList["添加到任务列表"]
AddToList --> Continue{"继续添加?"}
Continue --> |是| SelectTask
Continue --> |否| SaveTasks["保存所有任务"]
SaveTasks --> End([完成定时任务配置])
ShowError --> End
```
**Diagram sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L79-L145)
- [DialTimerTask.h](file://h/DialTimerTask.h#L49-L51)
**Section sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L1-L238)
- [DialTimerTask.h](file://h/DialTimerTask.h#L47-L60)
## CTaskDataOper类技术实现细节
CTaskDataOper类提供了定时任务管理的核心数据操作方法,主要包括QueryTimerTaskValiad和AddTimerTask等关键方法。
### QueryTimerTaskValiad方法
`QueryTimerTaskValiad`方法用于查询有效的定时任务,其技术实现细节如下:
- 方法接收一个`std::vector<STTimerTask>`类型的引用参数`vtTimerTd`用于返回查询结果,以及一个`SYSTEMTIME`类型的`sysCurTime`参数表示当前系统时间
- 方法首先清空结果容器,然后构建SQL查询语句,从`task_timer`表中查询执行时间大于当前时间的所有任务
- SQL查询条件为:`RunDate > 当前日期` 或 (`RunDate = 当前日期``RunTime > 当前时间`)
- 查询结果按执行日期和时间排序,确保最先执行的任务排在前面
- 方法将查询到的任务信息填充到`STTimerTask`结构体中,并添加到结果向量中
### AddTimerTask方法
`AddTimerTask`方法用于添加新的定时任务,其技术实现细节如下:
- 方法接收任务ID、任务名称、执行时间和PLC ID作为参数
- 方法首先检查任务是否已存在,如果存在则更新,否则插入新记录
- 使用事务处理确保数据一致性,在插入过程中如果发生错误会回滚事务
- 任务ID采用特殊编码方式:通过将任务ID与0x80000000进行按位或操作来标记为定时任务,恢复时通过与0x7FFFFFFF进行按位与操作来获取原始ID
- 方法返回布尔值表示操作是否成功
```mermaid
classDiagram
class CTaskDataOper {
+QueryTimerTaskValiad(vtTimerTd, sysCurTime) void
+AddTimerTask(dwTdID, strTaskName, strRunTime, strPlcID) bool
+DeleteTimerTask(vtDleTimerTask) bool
-m_pRecTdData Recordset*
-m_iTdType int
-m_bIsOpenTdData bool
}
class STTimerTask {
+uiTaskID DWORD
+strTaskName CString
+strRunTime CString
+strPlcID CString
}
CTaskDataOper --> STTimerTask : "包含"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4426-L4440)
- [DialTimerTask.h](file://h/DialTimerTask.h#L49-L51)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L205-L2734)
- [DialTimerTask.h](file://h/DialTimerTask.h#L47-L60)
## 定时器触发机制与任务状态机
定时任务的触发机制基于系统时间的比较和任务状态的转换,形成了一个完整的工作流程。
### 定时器触发机制
定时器触发机制的核心是`CompareTdTimer`函数,其实现逻辑如下:
- 函数接收当前系统时间和任务计划时间作为参数
- 将两个时间格式化为"YYYY-MM-DD HH:MM"格式的字符串
- 使用`strcmp`函数比较两个时间字符串
- 如果系统时间大于任务时间,说明任务已超时,记录超时日志
- 返回比较结果,用于判断是否应该执行任务
任务执行流程如下:
1. 系统定期调用`QueryTimerTaskValiad`方法获取所有待执行的任务
2. 对每个任务调用`CompareTdTimer`进行时间比较
3. 对于需要执行的任务,启动任务执行线程
4. 在执行前更新任务的测试日期和时间字段
5. 按照预设流程执行任务测量
### 任务状态机转换逻辑
定时任务执行过程中的状态机转换逻辑如下:
- **EN_TIMER_PROC_PLC_POWERON**: PLC开机状态,发送开机指令并等待响应
- **EN_TIMER_PROC_ROLLCALL**: 设备点名状态,对设备进行点名操作
- **EN_TIMER_PROC_CFG_TASK**: 任务配置状态,向设备发送任务参数
- **EN_TIMER_PROC_MEASU_DATA**: 数据测量状态,执行实际测量操作
- **EN_TIMER_PROC_MEASU_SUSPEND**: 测量暂停状态,用户暂停测量
- **EN_TIMER_PROC_MEASU_CONTINUE**: 测量继续状态,用户继续测量
- **EN_TIMER_PROC_MEASU_FIN**: 测量完成状态,任务正常结束
- **EN_TIMER_PROC_MEASU_TRMI**: 测量终止状态,任务异常终止
状态转换遵循严格的顺序,每个状态完成后自动进入下一个状态。系统还支持暂停和继续功能,允许用户在测量过程中暂停并稍后继续。
```mermaid
stateDiagram-v2
[*] --> PLC开机
PLC开机 --> 设备点名 : 开机成功
设备点名 --> 任务配置 : 点名成功
任务配置 --> 数据测量 : 配置成功
数据测量 --> 测量完成 : 全部测点完成
数据测量 --> 测量暂停 : 用户暂停
测量暂停 --> 数据测量 : 用户继续
数据测量 --> 测量终止 : 发生严重错误
测量暂停 --> 测量终止 : 用户取消
note right of 数据测量
包含重试机制:
- 网络超时重试
- 数据错误重试
- 最多重试90000次
end note
```
**Diagram sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L815-L838)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L626-L781)
**Section sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L1-L1002)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4426-L4440)
## 任务与设备通信协议集成
定时任务与设备通信协议的集成通过一系列标准化的通信流程实现,确保任务能够正确地在远程设备上执行。
### 通信协议集成方式
系统通过以下方式实现定时任务与设备通信协议的集成:
1. **PLC控制协议**: 使用专门的PLC控制命令与设备通信,包括开机、关机、状态查询等操作
2. **任务参数传输**: 将任务参数序列化后通过网络发送到设备端,参数包括测量周期、阵列类型、电缆布局等
3. **测量数据接收**: 设备完成测量后,将数据打包发送回主机,主机解析并存储到数据库
4. **状态同步**: 实时同步设备状态,包括告警状态、测量进度等
通信流程如下:
1. 建立与PLC设备的连接
2. 发送开机指令并等待响应
3. 执行设备点名,确认设备在线
4. 发送任务配置参数
5. 启动测量流程
6. 接收并处理测量数据
7. 关闭连接
### 通信数据结构
关键通信数据结构包括:
- **STMeasuTaskParam**: 测量任务参数结构体,包含测量周期、测试类型、阵列类型等信息
- **STSigSndDataInfo**: 信号发送数据信息,包含测点编号、电极位置等
- **STMeasuBasicDataRes**: 测量基本数据响应,包含电流、电压、电阻率等测量结果
- **STRemPlcDataInfo**: 远程PLC数据信息,包含PLC状态和控制结果
系统在发送数据前会将主机字节序转换为网络字节序(使用`htonl``tcp_htonf`等函数),接收数据时再转换回主机字节序(使用`ntohl``tcp_ntohf`等函数),确保跨平台兼容性。
```mermaid
sequenceDiagram
participant 主机 as "主机系统"
participant 网络 as "网络通信"
participant 设备 as "远程设备"
主机->>网络 : 发送PLC开机指令
网络->>设备 : 接收开机指令
设备-->>网络 : 返回开机响应
网络-->>主机 : 接收开机响应
主机->>网络 : 发送设备点名指令
网络->>设备 : 接收点名指令
设备-->>网络 : 返回点名响应
网络-->>主机 : 接收点名响应
主机->>网络 : 发送任务配置参数
网络->>设备 : 接收配置参数
设备-->>网络 : 返回配置响应
网络-->>主机 : 接收配置响应
主机->>网络 : 发送测量指令
网络->>设备 : 执行测量
设备-->>网络 : 返回测量数据
网络-->>主机 : 接收测量数据
主机->>主机 : 处理并存储数据
```
**Diagram sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L685-L794)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L2713-L2734)
**Section sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L485-L598)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L2713-L2734)
## 任务执行失败处理机制
系统实现了完善的任务执行失败处理机制,包括重试策略和日志记录,确保任务的可靠执行。
### 重试策略
系统采用智能重试策略处理任务执行失败:
- **重试条件**: 当遇到网络超时、数据错误、数据乱序等情况时触发重试
- **重试次数**: 最多重试90000次,通过`MAX_TIMER_REPEAT_SND_CNT`常量定义
- **重试间隔**: 单个测点的最大超时时间为60秒,给予网络充分的恢复时间
- **重试逻辑**: 在`NotifyResFunc`回调函数中处理重试逻辑,根据操作结果决定是否重试
重试流程如下:
1. 发送测量请求
2. 等待响应(最长60秒)
3. 如果超时或收到错误响应,增加重试计数
4. 如果重试计数未达到上限,重新发送请求
5. 如果重试计数达到上限,终止任务并记录错误
### 日志记录机制
系统实现了全面的日志记录机制:
- **操作日志**: 记录任务的每个关键操作,包括开始执行、状态转换、完成等
- **错误日志**: 详细记录各种错误情况,包括网络错误、数据库错误、设备告警等
- **性能日志**: 记录任务执行的时间信息,用于性能分析
- **调试日志**: 在开发和调试阶段提供详细的执行信息
日志记录的关键点包括:
- 在任务开始执行时记录"准备执行定时任务"日志
- 在时间比较发现超时时记录"定时任务超时"日志
- 在重试时记录"正在重试测量"日志
- 在遇到严重告警时记录告警信息
- 在数据库操作失败时记录详细的错误描述
日志通过`CFileOperTools::GetInstance()->WriteComLog()`方法写入日志文件,确保所有重要事件都有迹可循。
```mermaid
flowchart TD
Start([开始任务执行]) --> SendRequest["发送测量请求"]
SendRequest --> WaitForResponse["等待响应(60秒)"]
WaitForResponse --> ResponseReceived{"收到响应?"}
ResponseReceived --> |否| Timeout["超时"]
ResponseReceived --> |是| CheckData["检查数据有效性"]
CheckData --> DataValid{"数据有效?"}
DataValid --> |否| DataError["数据错误"]
DataValid --> |是| ProcessData["处理测量数据"]
ProcessData --> UpdateDB["更新数据库"]
UpdateDB --> Success["任务成功完成"]
Timeout --> Retry{"重试次数 < 90000?"}
DataError --> Retry
Retry --> |是| IncrementRetry["增加重试计数"]
IncrementRetry --> SendRequest
Retry --> |否| Fail["任务执行失败"]
Success --> End([结束])
Fail --> End
```
**Diagram sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L326-L364)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L832-L834)
**Section sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L308-L380)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L815-L838)
@@ -0,0 +1,283 @@
# 循环任务上传
<cite>
**本文档引用的文件**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp)
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h)
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp)
- [CDragListCtrl.h](file://cpp/ctrl/CDragListCtrl.h)
</cite>
## 目录
1. [简介](#简介)
2. [核心组件](#核心组件)
3. [网络通信架构](#网络通信架构)
4. [数据封装与上传流程](#数据封装与上传流程)
5. [拖拽排序功能实现](#拖拽排序功能实现)
6. [设备ID与PLC ID的作用](#设备id与plc-id的作用)
7. [消息响应处理](#消息响应处理)
## 简介
本文档全面文档化循环任务上传功能的技术实现,重点聚焦于`DialUploadLoopTask`类的设计。该功能允许用户创建并上传循环测量任务到GD10设备,支持通过拖拽方式对子任务进行排序,并通过网络通信协议将任务信息发送到目标设备。系统通过继承`CNetRequestDialog`类构建了完整的网络请求-响应架构,实现了从用户界面交互到数据传输的完整流程。
## 核心组件
`DialUploadLoopTask`类是循环任务上传功能的核心实现,继承自`CNetRequestDialog`,负责管理用户界面、数据封装和网络通信。该类通过`CDragListCtrl`控件实现任务列表的拖拽排序功能,使用`STTaskListItem`结构体存储任务信息,并通过`PostNetRequest`方法发起网络请求与GD10设备通信。
**本节来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L10-L65)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L22-L30)
## 网络通信架构
### 继承关系与架构设计
`DialUploadLoopTask`类继承自`CNetRequestDialog`,后者提供了基础的网络通信能力。这种设计模式实现了网络通信功能的复用和封装,形成了清晰的职责分离:`CNetRequestDialog`处理底层网络通信机制,而`DialUploadLoopTask`专注于业务逻辑和用户界面。
```mermaid
classDiagram
class CNetRequestDialog {
+CNetRequestDialog(UINT nIDTemplate, CWnd* pParent)
+~CNetRequestDialog()
+PostNetRequest(BYTE cmd, HWND hwnd, char* pData, WORD dataLen)
-PreNetResponse(WPARAM wParam, LPARAM lParam)
-DoDataExchange(CDataExchange* pDX)
}
class DialUploadLoopTask {
+DialUploadLoopTask(CWnd* pParent)
+~DialUploadLoopTask()
+SetDeviceID(DWORD dwDeviceID)
+SetPLCID(DWORD dwPLCID)
+OnInitDialog()
+OnBnClickedUploadLoop()
+OnBnClickedExitUpload()
+OnCbnSelchangeTimerTypeCombo()
+DragMoveItem(WPARAM wParam, LPARAM lParam)
-PreNetResponse(WPARAM wParam, LPARAM lParam)
-DoDataExchange(CDataExchange* pDX)
-m_CListCtrlTask CDragListCtrl
-m_TaskList CList<STTaskListItem>
-m_dwDeviceSN DWORD
-m_dwPLCID DWORD
}
DialUploadLoopTask --|> CNetRequestDialog : 继承
```
**图表来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L10)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h#L8)
**本节来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L10)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h#L8)
## 数据封装与上传流程
### 任务信息结构体
循环任务上传的数据封装基于`STLoopTaskInfo`结构体,该结构体包含了任务的所有必要信息:
```mermaid
classDiagram
class STLoopTaskInfo {
+char ucTaskID[MAX_NAME_LEN]
+char ucTaskName[MAX_NAME_LEN]
+UINT32 uiGD10Id
+UINT32 uiPlcId
+UINT8 ucContrlType
+UINT8 ucTimerType
+UINT64 uiLoopNum
+UINT8 ucLoopType
+UINT8 ucTimerAgsNum
+UINT8 ucTimerTimeAgs
+UINT32 uiStartTime
+UINT32 uiEndTime
+UINT32 uiStartMin
+UINT32 uiTaskSpace
+UINT32 uiSubTaskNum
}
```
### 上传流程实现
上传流程在`OnBnClickedUploadLoop`方法中实现,主要包括以下步骤:
1. **参数验证**:检查子任务数量、任务名称、循环次数等输入参数的有效性
2. **数据填充**:从界面控件获取数据并填充到`STLoopTaskInfo`结构体中
3. **字节序转换**:使用`htonl``htons`函数将主机字节序转换为网络字节序
4. **任务列表序列化**:将`STTaskListItem`列表中的任务ID按顺序序列化到发送缓冲区
5. **网络请求发起**:调用`PostNetRequest`方法发送数据
```mermaid
flowchart TD
Start([开始上传]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"参数有效?"}
InputValid --> |否| ShowError["显示错误信息"]
InputValid --> |是| FillData["填充STLoopTaskInfo结构体"]
FillData --> ConvertByteOrder["转换为网络字节序"]
ConvertByteOrder --> SerializeTasks["序列化任务列表"]
SerializeTasks --> SuspendThread["暂停网络线程"]
SuspendThread --> SendRequest["调用PostNetRequest发送请求"]
SendRequest --> ResumeThread["恢复网络线程"]
ResumeThread --> End([上传完成])
ShowError --> End
```
**图表来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L180-L377)
**本节来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L180-L377)
## 拖拽排序功能实现
### CDragListCtrl控件应用
`CDragListCtrl`控件是实现任务拖拽排序的关键组件,它继承自`CListCtrl`并扩展了拖拽功能。该控件通过Windows消息机制处理拖拽操作,实现了直观的任务重新排序体验。
```mermaid
classDiagram
class CListCtrl {
+GetItemCount()
+GetItemText(int nItem, int nSubItem)
+SetItemText(int nItem, int nSubItem, LPCTSTR lpszText)
+InsertItem(int nItem, LPCTSTR lpszItem)
}
class CDragListCtrl {
+OnLvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
+OnMouseMove(UINT nFlags, CPoint point)
+OnLButtonUp(UINT nFlags, CPoint point)
-m_nSelItem int
-m_pDragImageList CImageList*
-m_bDragging BOOL
}
CDragListCtrl --|> CListCtrl : 继承
```
### 拖拽事件处理流程
拖拽排序功能通过以下三个关键事件处理:
1. **开始拖拽**`OnLvnBegindrag`):当用户开始拖拽时创建拖拽图像并进入拖拽模式
2. **鼠标移动**`OnMouseMove`):在拖拽过程中更新拖拽图像位置
3. **释放鼠标**`OnLButtonUp`):完成拖拽操作,更新列表项位置
```mermaid
sequenceDiagram
participant User as 用户
participant CDragListCtrl as CDragListCtrl控件
participant DialUploadLoopTask as DialUploadLoopTask对话框
User->>CDragListCtrl : 开始拖拽操作
CDragListCtrl->>CDragListCtrl : OnLvnBegindrag事件
CDragListCtrl->>CDragListCtrl : 创建拖拽图像
CDragListCtrl->>CDragListCtrl : 进入拖拽模式
loop 拖拽过程中
User->>CDragListCtrl : 移动鼠标
CDragListCtrl->>CDragListCtrl : OnMouseMove事件
CDragListCtrl->>CDragListCtrl : 更新拖拽图像位置
end
User->>CDragListCtrl : 释放鼠标按钮
CDragListCtrl->>CDragListCtrl : OnLButtonUp事件
CDragListCtrl->>CDragListCtrl : 结束拖拽操作
CDragListCtrl->>DialUploadLoopTask : 发送WM_MOVEITEM消息
DialUploadLoopTask->>DialUploadLoopTask : DragMoveItem处理
DialUploadLoopTask->>DialUploadLoopTask : 重新排列列表项
```
**图表来源**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L93-L178)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L57-L58)
**本节来源**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L93-L178)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L481-L532)
## 设备ID与PLC ID的作用
### 设备标识符管理
`DialUploadLoopTask`类通过两个关键成员变量管理设备标识:
- `m_dwDeviceSN`:存储GD10设备的序列号(Device ID
- `m_dwPLCID`:存储PLC控制器的ID
这两个标识符在任务上传过程中起着至关重要的作用,确保任务被正确路由到目标设备。
### 标识符的设置与使用
设备ID和PLC ID通过专门的setter方法进行设置:
```mermaid
classDiagram
class DialUploadLoopTask {
+SetDeviceID(DWORD dwDeviceID)
+SetPLCID(DWORD dwPLCID)
-m_dwDeviceSN DWORD
-m_dwPLCID DWORD
}
class UsageFlow {
direction LR
A[用户选择设备] --> B[调用SetDeviceID]
B --> C[保存m_dwDeviceSN]
D[用户选择PLC] --> E[调用SetPLCID]
E --> F[保存m_dwPLCID]
C --> G[上传时填充STLoopTaskInfo]
F --> G
G --> H[发送到GD10设备]
}
```
在上传过程中,这些ID被提取自界面控件(去除"SN"和"PLC"前缀),转换为整数后填充到`STLoopTaskInfo`结构体的`uiGD10Id``uiPlcId`字段中,确保设备能够正确识别和处理上传的任务。
**图表来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L22-L30)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L232-L238)
**本节来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L22-L30)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L232-L238)
## 消息响应处理
### 预处理与响应机制
`DialUploadLoopTask`类实现了`CNetRequestDialog`定义的`PreNetResponse`纯虚函数,用于处理来自GD10设备的响应消息。这种设计模式遵循了模板方法模式,基类`CNetRequestDialog`定义了算法骨架,子类实现具体步骤。
```mermaid
sequenceDiagram
participant GD10 as GD10设备
participant Network as 网络模块
participant CNetRequestDialog as CNetRequestDialog
participant DialUploadLoopTask as DialUploadLoopTask
GD10->>Network : 发送响应数据包
Network->>CNetRequestDialog : OnNetResponse消息
CNetRequestDialog->>CNetRequestDialog : 调用PreNetResponse
CNetRequestDialog->>DialUploadLoopTask : 虚函数调用
DialUploadLoopTask->>DialUploadLoopTask : 处理具体响应
DialUploadLoopTask->>DialUploadLoopTask : 显示结果或错误信息
```
### 响应处理逻辑
`PreNetResponse`方法根据响应命令类型和状态码进行相应的处理:
```mermaid
flowchart TD
Start([收到响应]) --> CheckCommand["检查命令类型 EN_REQ_LOOP_TASK_TRUST"]
CheckCommand --> IsMatch{"命令匹配?"}
IsMatch --> |否| Exit[忽略响应]
IsMatch --> |是| CheckStatus["检查状态码"]
CheckStatus --> Success{"状态码=0?"}
Success --> |是| ShowSuccess["显示成功消息"]
Success --> |否| CheckConflict["检查是否为时间冲突"]
CheckConflict --> IsConflict{"状态码=2?"}
IsConflict --> |是| ShowConflict["显示时间冲突消息"]
IsConflict --> |否| ShowUnknownError["显示未知错误"]
ShowSuccess --> CloseDialog["关闭对话框"]
ShowConflict --> Exit
ShowUnknownError --> Exit
CloseDialog --> Exit
```
成功的响应会显示"循环任务创建完成"的消息并关闭对话框,而错误响应则会根据具体错误码显示相应的错误信息,如"此时段已创建其他任务"。
**图表来源**
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp#L37-L41)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L387-L447)
**本节来源**
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp#L37-L41)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L387-L447)
@@ -0,0 +1,265 @@
# 循环任务查询
<cite>
**本文档引用的文件**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [核心组件](#核心组件)
3. [架构概述](#架构概述)
4. [详细组件分析](#详细组件分析)
5. [依赖分析](#依赖分析)
6. [性能考虑](#性能考虑)
7. [故障排除指南](#故障排除指南)
8. [结论](#结论)
## 引言
本文档系统化地描述了Geomative Studio软件中循环任务查询功能的实现机制。重点分析了DialLoopTaskQuery对话框作为CDialog派生类的生命周期管理,包括其初始化流程、数据交换机制以及消息映射处理。文档详细阐述了CListCtrl控件在任务列表展示中的应用,以及STLoopTaskTable结构体在内存中的数据组织方式。同时,深入探讨了查询功能与数据库的交互逻辑,特别是如何通过CTaskDataOper组件访问tdTaskPacket和tdTaskPacketInfo表来获取循环任务数据。
## 核心组件
循环任务查询功能的核心组件是DialLoopTaskQuery对话框类,该类继承自MFC的CDialog类,负责提供用户界面以查询和选择循环任务。该对话框通过m_LoopTablelist成员变量管理内存中的循环任务数据,并使用m_ListLoopDisplay控件在界面上展示任务列表。当用户选择任务并点击查询按钮时,系统会将选中的任务ID存储在m_szArrayLoopTaskID数组中,并关闭对话框以返回主程序进行后续处理。
**本节来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
## 架构概述
循环任务查询功能的架构基于MFC对话框框架,采用经典的模型-视图-控制器(MVC)模式。DialLoopTaskQuery类作为视图和控制器,负责用户交互和界面展示;STLoopTaskTable结构体作为数据模型,定义了循环任务的数据结构;CTaskDataOper类作为数据访问层,负责与数据库进行交互。整个架构通过消息映射机制实现用户操作的响应,通过DoDataExchange实现控件与成员变量的数据绑定。
```mermaid
graph TB
subgraph "用户界面层"
DialLoopTaskQuery["DialLoopTaskQuery<br/>对话框类"]
end
subgraph "数据访问层"
TaskDataOper["CTaskDataOper<br/>数据操作类"]
end
subgraph "数据存储层"
Database["数据库<br/>tdTaskPacket表"]
end
DialLoopTaskQuery --> TaskDataOper
TaskDataOper --> Database
Database --> TaskDataOper
TaskDataOper --> DialLoopTaskQuery
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L1450)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L700-L706)
## 详细组件分析
### DialLoopTaskQuery类分析
DialLoopTaskQuery类是循环任务查询功能的核心实现,作为CDialog的派生类,它遵循MFC对话框的标准生命周期。
#### 类生命周期管理
DialLoopTaskQuery类的生命周期由MFC框架管理,遵循标准的构造、初始化、运行和析构流程。类的构造函数负责初始化成员变量,析构函数则负责清理资源。
```mermaid
classDiagram
class DialLoopTaskQuery {
+CStatic m_StaticLoopNum
+CListCtrl m_ListLoopDisplay
+CList<STLoopTaskTable> m_LoopTablelist
+CStringArray m_szArrayLoopTaskID
+DialLoopTaskQuery(CWnd* pParent)
+~DialLoopTaskQuery()
+OnInitDialog() bool
+DoDataExchange(CDataExchange* pDX)
+OnBnClickedQuerySubLoop()
+OnBnClickedCancel()
}
DialLoopTaskQuery --|> CDialog : "继承"
```
**图表来源**
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
#### OnInitDialog初始化流程
OnInitDialog方法是对话框初始化的核心,负责设置界面控件的初始状态和加载数据。该方法首先调用基类的OnInitDialog进行基本初始化,然后配置CListCtrl控件的扩展样式,设置列标题,并根据m_LoopTablelist中的数据填充列表控件。
```mermaid
flowchart TD
Start([OnInitDialog入口]) --> SetExtendedStyle["设置CListCtrl扩展样式<br/>LVS_EX_FULLROWSELECT等"]
SetExtendedStyle --> SetStaticText["设置静态文本控件<br/>m_StaticLoopNum初始值为0"]
SetStaticText --> AddColumns["添加列表控件列<br/>任务名称、任务ID等"]
AddColumns --> CheckData["检查m_LoopTablelist<br/>是否有数据"]
CheckData --> |是| LoopData["遍历m_LoopTablelist<br/>填充列表控件"]
CheckData --> |否| SetTaskNum["设置任务数量为0"]
LoopData --> FormatTime["格式化时间显示<br/>使用Tm2LocalStr函数"]
FormatTime --> InsertItem["插入列表项<br/>SetItemText设置各列值"]
InsertItem --> UpdateTaskNum["更新任务数量显示"]
UpdateTaskNum --> End([返回TRUE])
SetTaskNum --> End
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L82-L144)
#### DoDataExchange数据交换机制
DoDataExchange方法实现了对话框控件与类成员变量之间的数据交换,这是MFC数据绑定的核心机制。该方法使用DDX_Control宏将界面控件与类的成员变量关联起来,确保界面状态与程序数据的一致性。
```mermaid
sequenceDiagram
participant Framework as "MFC框架"
participant Dialog as "DialLoopTaskQuery"
Framework->>Dialog : OnInitDialog()
Dialog->>Dialog : CDialog : : OnInitDialog()
Dialog->>Dialog : DoDataExchange(pDX)
Dialog->>Dialog : DDX_Control(pDX, IDC_STATIC_LOOP_Q_NUM, m_StaticLoopNum)
Dialog->>Dialog : DDX_Control(pDX, IDC_LIST_QUERY, m_ListLoopDisplay)
Dialog->>Framework : 控件与成员变量绑定完成
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L29-L34)
#### 消息映射处理
消息映射机制使DialLoopTaskQuery类能够响应用户的操作。通过BEGIN_MESSAGE_MAP宏定义,将特定的Windows消息映射到相应的处理函数。当用户点击"查询"或"取消"按钮时,框架会自动调用对应的处理函数。
```mermaid
flowchart LR
A["用户点击查询按钮"] --> B["WM_COMMAND消息"]
B --> C["MFC框架查找消息映射"]
C --> D["找到ON_BN_CLICKED(IDOK_QUERY_SUB_LOOP)"]
D --> E["调用OnBnClickedQuerySubLoop函数"]
E --> F["处理查询逻辑"]
F --> G["关闭对话框"]
H["用户点击取消按钮"] --> I["WM_COMMAND消息"]
I --> J["MFC框架查找消息映射"]
J --> K["找到ON_BN_CLICKED(IDCANCEL)"]
K --> L["调用OnBnClickedCancel函数"]
L --> M["清理资源"]
M --> N["关闭对话框"]
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L37-L40)
### CListCtrl控件应用分析
m_ListLoopDisplay是CListCtrl类型的控件,用于在界面上展示循环任务列表。该控件通过插入列和设置项文本的方式组织和显示数据。
#### 任务列表展示机制
CListCtrl控件通过多列列表的形式展示任务信息,每行代表一个循环任务,每列代表任务的一个属性。控件的初始化和数据填充在OnInitDialog方法中完成。
```mermaid
erDiagram
TASK ||--o{ COLUMN : "包含"
TASK {
string 任务名称
string 任务ID
string 任务类型
string 开始时间
string 结束时间
}
COLUMN {
string 列标题
int 列宽度
int 对齐方式
}
DISPLAY : "m_ListLoopDisplay"
DISPLAY --> TASK : "显示"
DISPLAY --> COLUMN : "管理"
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L90-L137)
### STLoopTaskTable结构体分析
STLoopTaskTable结构体定义了循环任务在内存中的数据组织方式,是连接界面展示和数据库存储的关键数据模型。
#### 内存数据组织
STLoopTaskTable结构体包含了循环任务的所有必要信息,通过CList模板类进行管理,形成一个任务列表。
```mermaid
classDiagram
class STLoopTaskTable {
+char ucTaskID[40]
+char ucTaskName[40]
+BYTE ucLoopType
+UINT32 uiStartTime
+UINT32 uiEndTime
}
class CList {
+AddHead()
+AddTail()
+RemoveAll()
+GetHeadPosition()
+GetNext()
}
CList<STLoopTaskTable> --|> CList : "模板实例化"
CList<STLoopTaskTable> --> STLoopTaskTable : "存储"
```
**图表来源**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L700-L706)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h#L28)
### 数据库交互逻辑分析
循环任务查询功能通过CTaskDataOper组件与数据库进行交互,获取循环任务的相关数据。
#### 查询功能与数据库交互
查询功能通过CTaskDataOper类的QueryTaskPacketInfo方法访问数据库,获取tdTaskPacketInfo表中的任务信息,并将其转换为STTdBrowseInfo结构体数组。
```mermaid
sequenceDiagram
participant Dialog as "DialLoopTaskQuery"
participant DataOper as "CTaskDataOper"
participant Database as "数据库"
Dialog->>DataOper : QueryTaskPacketInfo(vtTdBrowseInfo)
DataOper->>Database : SELECT * FROM tdTaskPacketInfo
Database-->>DataOper : 返回任务数据
DataOper->>DataOper : 转换为STTdBrowseInfo数组
DataOper-->>Dialog : 填充vtTdBrowseInfo
Dialog->>Dialog : 将数据加载到m_LoopTablelist
```
**图表来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1112-L1139)
- [TaskDataOper.h](file://h/TaskDataOper.h#L308-L306)
## 依赖分析
循环任务查询功能依赖于多个核心组件和外部资源。主要依赖包括MFC框架提供的对话框和控件类、CTaskDataOper数据操作类、全局应用程序对象theApp以及数据库连接。这些依赖关系确保了功能的完整性和稳定性。
```mermaid
graph TD
DialLoopTaskQuery --> CDialog
DialLoopTaskQuery --> CListCtrl
DialLoopTaskQuery --> CStatic
DialLoopTaskQuery --> CTaskDataOper
DialLoopTaskQuery --> theApp
CTaskDataOper --> ADODB
CTaskDataOper --> Database
theApp --> NetworkOper
theApp --> Connection
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L10-L13)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L25-L38)
## 性能考虑
循环任务查询功能在性能方面主要考虑数据加载效率和界面响应速度。由于任务列表数据通常不会太大,因此采用一次性加载所有数据的方式。通过合理设置CListCtrl控件的扩展样式,如LVS_EX_GRIDLINES和LVS_EX_FULLROWSELECT,提升了用户体验。在数据交换过程中,使用_bstr_t类型转换确保了字符串处理的效率。
## 故障排除指南
当循环任务查询功能出现问题时,可以按照以下步骤进行排查:
1. 检查数据库连接是否正常
2. 验证tdTaskPacket和tdTaskPacketInfo表是否存在且有数据
3. 确认m_LoopTablelist是否正确填充了数据
4. 检查OnInitDialog方法中的列设置是否正确
5. 验证消息映射是否正确配置
**本节来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L55-L58)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L79-L81)
## 结论
循环任务查询功能通过DialLoopTaskQuery对话框实现了用户友好的任务选择界面。该功能充分利用了MFC框架的特性,通过标准的对话框生命周期管理、数据交换机制和消息映射,实现了稳定可靠的用户交互。内存中的STLoopTaskTable结构体和CList容器有效组织了任务数据,而CTaskDataOper组件则确保了与数据库的高效交互。整体设计遵循了良好的软件工程原则,具有良好的可维护性和扩展性。
@@ -0,0 +1,292 @@
# 循环任务管理
<cite>
**本文档引用的文件**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp)
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [循环任务查询](#循环任务查询)
3. [循环任务管理](#循环任务管理)
4. [循环任务上传](#循环任务上传)
5. [数据结构与协议](#数据结构与协议)
6. [生命周期与同步机制](#生命周期与同步机制)
7. [异常处理与数据完整性](#异常处理与数据完整性)
8. [与PLC状态监控的集成](#与plc状态监控的集成)
9. [结论](#结论)
## 引言
循环任务管理功能是Geomative Studio系统中的核心模块之一,负责实现定时任务的创建、查询、管理和批量上传。该功能通过三个主要界面组件实现:`DialLoopTaskQuery`(任务查询)、`DialManageLoopTask`(任务管理)和`DialUploadLoopTask`(任务上传)。这些组件共同构成了一个完整的循环任务生命周期管理系统,支持用户对设备端的定时测量任务进行精细化控制。
系统通过网络协议与设备端通信,实现任务信息的双向同步。任务数据结构设计考虑了时间控制、执行策略、子任务调度等多个维度,确保任务能够在指定时间窗口内按预定规则执行。同时,系统集成了PLC状态监控功能,确保任务执行环境的稳定性。
**本文档来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L1-L532)
## 循环任务查询
`DialLoopTaskQuery`组件提供了循环任务的查询功能,允许用户从设备端获取已存在的循环任务列表。该组件通过`CListCtrl`控件展示任务信息,包括任务名称、任务ID、任务类型、开始时间和结束时间等关键字段。
在初始化过程中,组件通过`OnInitDialog`方法设置列表控件的列标题和显示样式。由于该组件仅用于查询和选择任务,其核心逻辑集中在`OnBnClickedQuerySubLoop`事件处理函数中。当用户选择一个或多个任务并点击确认按钮时,系统会将选中的任务ID存储在`m_szArrayLoopTaskID`数组中,并关闭对话框,将选择结果返回给调用方。
该组件的设计体现了单一职责原则,专注于任务查询功能,不涉及任务的创建或修改操作。通过与`STLoopTaskTable`数据结构的绑定,实现了任务信息的结构化展示。
**本文档来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L82-L144)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h#L29)
## 循环任务管理
`DialManageLoopTask`组件提供了循环任务的管理功能,包括任务的删除和详细信息查看。该组件继承自`CNetRequestDialog`,具备网络请求处理能力,能够与设备端进行双向通信。
组件的核心功能包括:
- **任务列表初始化**:通过`InitLoopTaskList`方法向设备端发送`EN_REQ_DOWNLOAD_LOOP_TABLE`命令,获取指定时间范围内的循环任务列表。
- **任务删除**:用户选择一个或多个任务后,点击删除按钮,系统会向设备端发送`EN_CANCEL_LOOP_TASK_TRUST`命令,请求删除选中的循环任务。
- **子任务查看**:当用户点击某个循环任务时,系统会发送`EN_REQ_DOWNLOAD_LOOP_SUB_TABLE`命令,获取该循环任务包含的子任务列表。
该组件使用`std::map<CString, STLoopTaskTable>`数据结构`m_mapSaveLoopList`来缓存从设备端获取的任务列表,提高了数据访问效率。同时,通过`CRITICAL_SECTION`临界区对象`m_cs`确保多线程环境下的数据安全。
**本文档来源**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L230-L621)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h#L63)
## 循环任务上传
`DialUploadLoopTask`组件提供了新建循环任务的功能,允许用户配置任务参数并上传到设备端。该组件提供了丰富的用户界面元素,包括组合框、日期时间选择器和编辑框,用于收集任务配置信息。
任务创建流程包括以下关键步骤:
1. **参数收集**:从用户界面收集任务名称、循环类型(次数循环或定时循环)、循环次数、开始时间、结束时间、每日开始时间和任务间隔等参数。
2. **数据验证**:对用户输入进行验证,确保循环次数在1-60000范围内,结束时间不早于开始时间。
3. **数据结构填充**:将验证后的参数填充到`STLoopTaskInfo`数据结构中,并进行网络字节序转换。
4. **任务上传**:通过`PostNetRequest`方法发送`EN_REQ_LOOP_TASK_TRUST`命令,将任务信息上传到设备端。
该组件还支持子任务的拖拽排序功能,通过`DragMoveItem`消息处理函数实现。用户可以通过拖拽调整子任务的执行顺序,系统会按照调整后的顺序生成任务ID列表并上传。
**本文档来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L180-L378)
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L42)
## 数据结构与协议
循环任务管理功能依赖于一系列精心设计的数据结构和通信协议。核心数据结构包括:
### STLoopTaskTable
该结构体用于表示循环任务的基本信息,包括:
- `ucTaskID`:任务ID
- `ucTaskName`:任务名称
- `ucLoopType`:循环类型(0:一次, 1:按天, 2:按月, 3:按周)
- `uiStartTime`:开始测试时间
- `uiEndTime`:结束测试时间
### STLoopTaskInfo
该结构体用于表示循环任务的详细配置信息,包含:
- `ucTaskID`:循环任务名
- `ucTaskName`:循环备用任务名
- `uiPlcId`PLC设备ID
- `uiGD10Id`GD10设备ID
- `ucContrlType`:控制类型(0:次数循环, 1:定时循环)
- `uiLoopNum`:循环次数
- `uiStartTime`:开始测试时间
- `uiEndTime`:结束测试时间
- `uiStartMin`:每天或每周相对0点开始的分钟数
- `uiTaskSpace`:任务间间隔(秒)
- `uiSubTaskNum`:子任务数
### 通信协议
系统定义了专门的网络命令用于循环任务管理:
- `EN_REQ_LOOP_TASK_TRUST` (0x58):请求创建循环任务
- `EN_CANCEL_LOOP_TASK_TRUST` (0x59):请求取消循环任务
- `EN_REQ_DOWNLOAD_TASK_ARG` (0x73):请求下载任务参数
- `EN_REQ_DOWNLOAD_LOOP_TABLE` (0x77):请求下载循环任务表
- `EN_REQ_DOWNLOAD_LOOP_SUB_TABLE` (0x78):请求下载循环子任务表
这些数据结构和协议共同构成了循环任务管理功能的基础,确保了任务信息在客户端和设备端之间的一致性和完整性。
```mermaid
classDiagram
class STLoopTaskTable {
+char ucTaskID[40]
+char ucTaskName[40]
+BYTE ucLoopType
+UINT32 uiStartTime
+UINT32 uiEndTime
}
class STLoopTaskInfo {
+char ucTaskID[40]
+char ucTaskName[60]
+UINT32 uiPlcId
+UINT32 uiGD10Id
+BYTE ucContrlType
+BYTE ucTimerType
+UINT16 uiLoopNum
+UINT16 uiRemainLoopNum
+BYTE ucLoopType
+BYTE ucTimerAgsNum
+BYTE ucTimerTimeAgs
+UINT32 uiStartTime
+UINT32 uiEndTime
+UINT32 uiStartMin
+UINT32 uiTaskSpace
+UINT32 uiSubTaskNum
}
class STTaskListItem {
+char szTaskID[40]
+char szTDName[60]
+BYTE byTestStatus
+EN_TASK_LOCAL_STATUSE eSynStatus
}
class EN_TASK_LOCAL_STATUSE {
<<enumeration>>
EN_TASK_NO_UPLOAD = 0
EN_TASK_NO_DOWNLOAD
EN_TASK_YES_SYN
}
class EN_TASK_SERVER_STATUSE {
<<enumeration>>
EN_TASK_STATE_NO_TRUST = 0
EN_TASK_STATE_TESTING
EN_TASK_STATE_STOP_TEST = 20
EN_TASK_STATE_TEST_FAILED = 30
EN_TASK_STATE_FINISH = 40
}
STLoopTaskInfo --> STTaskListItem : "包含"
STTaskListItem --> EN_TASK_LOCAL_STATUSE : "引用"
STLoopTaskInfo --> EN_TASK_SERVER_STATUSE : "引用"
```
**图表来源**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L705-L729)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L698)
## 生命周期与同步机制
循环任务的生命周期管理涉及创建、查询、执行和删除四个阶段,每个阶段都有相应的同步机制确保数据一致性。
### 创建阶段
当用户通过`DialUploadLoopTask`创建新任务时,系统会生成唯一的任务ID,格式为"LOOPYYYYMMDDHHMMSS_任务名"。这个ID结合了时间戳和任务名,确保全局唯一性。创建请求通过`EN_REQ_LOOP_TASK_TRUST`命令发送到设备端,设备端验证参数合法性后返回响应。
### 查询阶段
`DialManageLoopTask`组件通过分页机制查询任务列表。初始查询时间范围为当前时间前30天到当前时间后1小时,如果查询结果跨越多天,则按5天为单位分批加载,避免单次请求数据量过大。
### 执行阶段
任务执行由设备端的PLC控制器负责调度。系统通过`STLoopTaskInfo`中的`uiStartMin``uiTaskSpace`参数精确控制任务的启动时间和间隔。任务执行状态通过`EN_TASK_SERVER_STATUSE`枚举值反映,包括测试中、测试停止、测试失败和完成等状态。
### 删除阶段
任务删除操作是不可逆的。当用户请求删除任务时,系统会向设备端发送`EN_CANCEL_LOOP_TASK_TRUST`命令,设备端验证后删除任务并释放相关资源。删除操作会同时清除任务的所有子任务和测量数据。
整个生命周期中,系统通过网络请求-响应模式确保操作的原子性。每个关键操作都有对应的日志记录,便于故障排查和审计。
```mermaid
sequenceDiagram
participant 用户 as 用户界面
participant 客户端 as 客户端应用
participant 设备端 as 设备端
用户->>客户端 : 创建循环任务
客户端->>设备端 : 发送EN_REQ_LOOP_TASK_TRUST
设备端-->>客户端 : 返回创建结果
客户端->>用户 : 显示创建结果
用户->>客户端 : 查询循环任务
客户端->>设备端 : 发送EN_REQ_DOWNLOAD_LOOP_TABLE
设备端-->>客户端 : 返回任务列表
客户端->>用户 : 显示任务列表
用户->>客户端 : 删除循环任务
客户端->>设备端 : 发送EN_CANCEL_LOOP_TASK_TRUST
设备端-->>客户端 : 返回删除结果
客户端->>用户 : 显示删除结果
设备端->>设备端 : 按计划执行任务
设备端->>客户端 : 推送任务状态更新
客户端->>用户 : 更新界面显示
```
**图表来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L376)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L250)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L172)
## 异常处理与数据完整性
系统在循环任务管理过程中实施了多层次的异常处理和数据完整性保障措施。
### 输入验证
在任务创建过程中,系统对所有用户输入进行严格验证:
- 任务名称不能为空
- 循环次数必须在1-60000范围内
- 结束时间不能早于开始时间
- 任务ID必须符合命名规范
### 网络通信保障
系统通过以下机制确保网络通信的可靠性:
- **请求重试**:关键操作支持重试机制,避免因网络抖动导致操作失败
- **超时控制**:设置合理的请求超时时间,防止长时间等待
- **错误码处理**:根据设备端返回的错误码进行针对性处理,如`FAILED_CREATE_LOOP_DURING_THIS_PERIOD`表示该时间段已存在其他任务
### 数据一致性
为确保数据一致性,系统采用以下策略:
- **事务性操作**:关键操作(如任务删除)设计为原子操作,要么全部成功,要么全部失败
- **状态同步**:通过`EN_TASK_LOCAL_STATUSE``EN_TASK_SERVER_STATUSE`两个状态枚举,分别维护本地和服务器端的任务状态,确保状态同步
- **日志记录**:所有关键操作都记录到日志文件中,便于问题追踪和审计
### 内存管理
系统在内存管理方面也做了精心设计:
- 使用`std::map``CList`等容器管理任务列表,提供高效的查找和遍历能力
- 通过`CRITICAL_SECTION`保护共享数据,避免多线程竞争
- 及时释放不再使用的资源,防止内存泄漏
这些措施共同确保了循环任务管理功能的稳定性和可靠性。
**本文档来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L186-L271)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L264-L268)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L409-L418)
## 与PLC状态监控的集成
循环任务管理功能与PLC状态监控系统深度集成,确保任务执行环境的稳定性和可靠性。
### 状态依赖
循环任务的执行依赖于PLC的运行状态。系统通过`OperPLC`模块获取PLC的实时状态,只有在PLC处于正常工作状态时才允许启动新的测量任务。这种依赖关系避免了在设备异常情况下执行任务导致的数据错误或设备损坏。
### 状态同步
系统实现了PLC状态与循环任务状态的双向同步:
- 当PLC状态发生变化时,系统会更新相关任务的状态
- 当循环任务状态发生变化时,系统会向PLC发送相应的控制指令
### 故障处理
在PLC出现故障时,系统会采取以下措施:
- 暂停正在执行的循环任务
- 记录故障信息和时间戳
- 向用户发出告警通知
- 在PLC恢复正常后,根据配置决定是否恢复任务执行
### 参数传递
循环任务的配置参数会通过特定的通信协议传递给PLC,包括:
- 任务ID和名称
- 执行时间计划
- 测量参数和阈值
- 异常处理策略
这种集成设计确保了上位机软件与下位机控制器之间的协调工作,提高了整个系统的自动化水平和可靠性。
**本文档来源**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L130-L133)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L133-L136)
## 结论
循环任务管理功能通过`DialLoopTaskQuery``DialManageLoopTask``DialUploadLoopTask`三个核心组件,实现了完整的任务生命周期管理。系统采用分层架构设计,将用户界面、业务逻辑和数据访问分离,提高了代码的可维护性和可扩展性。
数据结构设计充分考虑了实际应用场景,`STLoopTaskInfo`等结构体包含了任务执行所需的所有参数。通信协议设计简洁高效,通过少量的命令码实现了复杂的功能需求。
异常处理机制完善,从输入验证到网络通信再到数据一致性,每个环节都有相应的保障措施。与PLC状态监控的深度集成,确保了任务执行的可靠性和安全性。
该功能模块的设计体现了工业控制系统对稳定性、可靠性和安全性的高要求,为地质勘探设备的自动化测量提供了坚实的基础。
@@ -0,0 +1,292 @@
# 循环任务管理界面
<cite>
**本文档引用的文件**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DataMngStruct.h](file://h/DataMngStruct.h)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档深入解析循环任务管理界面的UI架构与交互逻辑,基于DialManageLoopTask类的实现。该对话框是Geomative Studio软件中用于管理定时循环任务的核心组件,提供了任务创建、编辑、删除等核心操作功能。文档重点分析了界面与底层数据模型的绑定机制,用户操作事件(如按钮点击)的处理流程,以及如何通过消息映射与CTaskDataOper服务层进行通信。同时,文档化了界面状态管理策略,包括任务列表的动态刷新机制和用户输入验证逻辑。
## 项目结构
循环任务管理功能主要分布在Views和Operator两个模块中。Views模块包含用户界面相关的实现,而Operator模块则负责数据操作和业务逻辑处理。核心文件DialManageLoopTask.cpp位于cpp/Views目录下,实现了循环任务管理对话框的完整功能。
```mermaid
graph TB
subgraph "Views"
A[DialManageLoopTask.cpp]
B[DialLoopTaskQuery.cpp]
C[DialUploadLoopTask.cpp]
end
subgraph "Operator"
D[TaskDataOper.cpp]
end
subgraph "Socket"
E[NetRequestDialog.h]
end
A --> D
A --> E
B --> D
C --> D
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 核心组件
循环任务管理界面的核心组件是CDialManageLoopTask类,它继承自CNetRequestDialog,实现了循环任务的管理功能。该组件集成了任务列表显示、子任务管理、任务删除等核心操作。通过与CTaskDataOper服务层的通信,实现了与底层数据模型的绑定。组件使用了消息映射机制来处理用户操作事件,如按钮点击和列表项选择。
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 架构概述
循环任务管理界面采用典型的MVCModel-View-Controller)架构模式。视图层由CDialManageLoopTask类实现,负责用户界面的展示和用户交互。控制层通过消息映射处理用户操作,调用服务层进行数据操作。模型层由CTaskDataOper类提供,负责与数据库的交互和业务逻辑处理。
```mermaid
classDiagram
class CDialManageLoopTask {
+CListCtrl m_LoopTaskList
+CListCtrl m_subtaskList
+CEdit m_editLoopTaskName
+CEdit m_editPLCID
+CEdit m_editGDID
+OnInitDialog()
+OnBnClickedBtnDeleteLoopTask()
+OnBnClickedOk()
+OnNMClickListLoopTaskList()
+InitLoopTaskList()
+PreNetResponse()
}
class CTaskDataOper {
+Create1DTask()
+Create2DTask()
+Create3DTask()
+InsertTaskPacketInfo()
+InsertPlcStatusData()
+QueryARByTdID()
+QuerySptByAR()
}
class CNetRequestDialog {
+PostNetRequest()
+PreNetResponse()
+DoDataExchange()
}
CDialManageLoopTask --> CTaskDataOper : "uses"
CDialManageLoopTask --> CNetRequestDialog : "inherits"
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
## 详细组件分析
### CDialManageLoopTask类分析
CDialManageLoopTask类是循环任务管理界面的核心实现,负责管理用户界面和用户交互。该类通过继承CNetRequestDialog获得了网络请求处理能力,能够与服务器进行通信获取和更新任务数据。
#### 用户界面初始化
在OnInitDialog方法中,组件初始化了两个列表控件:m_LoopTaskList用于显示循环任务列表,m_subtaskList用于显示选中任务的子任务列表。根据当前语言设置,组件会动态设置界面文本,支持中文和英文两种语言。
```mermaid
flowchart TD
Start([OnInitDialog]) --> SetLanguage["设置界面语言"]
SetLanguage --> CreateList["创建任务列表控件"]
CreateList --> SetColumn["设置列表列"]
SetColumn --> InitData["初始化循环任务列表"]
InitData --> Return["返回TRUE"]
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L60-L136)
#### 任务删除功能
OnBnClickedBtnDeleteLoopTask方法处理删除按钮的点击事件。当用户选择一个或多个任务并点击删除按钮时,该方法会收集选中任务的ID,通过PostNetRequest发送删除请求到服务器,并在收到成功响应后从界面列表中移除相应任务。
```mermaid
sequenceDiagram
participant User as "用户"
participant UI as "CDialManageLoopTask"
participant Network as "CNetRequestDialog"
participant Server as "服务器"
User->>UI : 点击删除按钮
UI->>UI : 获取选中任务
UI->>Network : PostNetRequest(EN_CANCEL_LOOP_TASK_TRUST)
Network->>Server : 发送删除请求
Server-->>Network : 返回响应
Network->>UI : PreNetResponse
UI->>UI : 更新界面列表
UI-->>User : 显示操作结果
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L138-L193)
#### 任务选择与详情显示
OnNMClickListLoopTaskList方法处理任务列表项的点击事件。当用户点击某个任务时,该方法会更新右侧的详细信息显示,并通过PostNetRequest请求该任务的子任务列表数据。
```mermaid
flowchart TD
Click["点击任务列表项"] --> GetTaskID["获取任务ID"]
GetTaskID --> UpdateUI["更新界面显示"]
UpdateUI --> RequestSubTask["PostNetRequest(EN_REQ_DOWNLOAD_LOOP_SUB_TABLE)"]
RequestSubTask --> WaitResponse["等待服务器响应"]
WaitResponse --> ShowSubTask["显示子任务列表"]
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L202-L228)
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
### CTaskDataOper服务层分析
CTaskDataOper类是数据操作的核心服务层,负责与数据库的交互和业务逻辑处理。该类提供了创建不同类型任务、查询任务信息、插入任务包信息等方法。
#### 任务创建功能
Create1DTask、Create2DTask和Create3DTask方法分别用于创建一维、二维和三维任务。这些方法通过ADO数据库操作,将任务信息插入到相应的数据库表中。
```mermaid
classDiagram
class CTaskDataOper {
+Create1DTask(ST1DTaskParam)
+Create2DTask(ST2DTaskParam)
+Create3DTask(ST3DTaskParam)
+InsertTaskPacketInfo()
+InsertPlcStatusData()
+QueryARByTdID()
+QuerySptByAR()
}
class ST1DTaskParam {
+strTDName
+iSptID
+strTestPlace
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
}
class ST2DTaskParam {
+strTDName
+iSptID
+strTestPlace
+iStartElec
+iEndElec
+iEAmount
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
+iCableLayout
+iSkipCable
+iRollCnt
+fEspace
+fHoleSpace
+ucTestGRFlag
}
class ST3DTaskParam {
+strTDName
+iSptID
+strTestPlace
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
+iCableLayout
+iSkipCable
+ucTestGRFlag
}
CTaskDataOper --> ST1DTaskParam : "uses"
CTaskDataOper --> ST2DTaskParam : "uses"
CTaskDataOper --> ST3DTaskParam : "uses"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L667)
#### 任务包信息管理
InsertTaskPacketInfo方法用于插入任务包信息,包括循环次数、间隔时间和PLC ID等。该方法通过事务处理确保数据的一致性。
```mermaid
flowchart TD
Start["开始插入任务包信息"] --> BeginTrans["开始数据库事务"]
BeginTrans --> DeleteOld["删除旧的任务包信息"]
DeleteOld --> InsertMain["插入主任务包信息"]
InsertMain --> DeleteOldInfo["删除旧的任务包详情"]
DeleteOldInfo --> InsertDetails["插入任务包详情"]
InsertDetails --> Commit["提交事务"]
Commit --> End["完成"]
Commit --> Rollback["回滚事务"]
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L669-L715)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L4455)
## 依赖分析
循环任务管理界面依赖于多个核心组件和服务。主要依赖关系包括:
```mermaid
graph TD
A[CDialManageLoopTask] --> B[CTaskDataOper]
A --> C[CNetRequestDialog]
A --> D[CFileOperTools]
B --> E[theApp.m_pConnection]
B --> F[theApp.m_NetWorkOper]
C --> G[theApp.m_NetWorkOper]
A --> H[g_iUILanguage]
A --> I[theApp]
style A fill:#f9f,stroke:#333
style B fill:#bbf,stroke:#333
style C fill:#f96,stroke:#333
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L4455)
## 性能考虑
循环任务管理界面在设计时考虑了多个性能因素。首先,任务列表的加载采用了分页机制,每次只加载指定时间范围内的任务,避免一次性加载过多数据导致界面卡顿。其次,网络请求采用了异步处理模式,通过消息映射机制在后台线程中处理网络通信,避免阻塞UI线程。此外,界面更新采用了增量更新策略,只更新发生变化的部分,减少不必要的重绘操作。
## 故障排除指南
在使用循环任务管理界面时,可能会遇到以下常见问题:
1. **任务列表无法加载**:检查网络连接是否正常,确保服务器正在运行。
2. **删除任务失败**:确认任务是否正在执行中,正在执行的任务无法删除。
3. **界面显示异常**:尝试重启应用程序,清除可能的界面状态错误。
4. **语言显示错误**:检查g_iUILanguage全局变量的设置是否正确。
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L4455)
## 结论
循环任务管理界面通过CDialManageLoopTask类的实现,提供了一个功能完整、交互友好的任务管理解决方案。该界面成功地将UI展示、用户交互和数据操作分离,遵循了良好的软件设计原则。通过与CTaskDataOper服务层的紧密协作,实现了对循环任务的全生命周期管理。未来可以考虑增加任务批量操作、更丰富的筛选条件和导出功能,进一步提升用户体验。