Pārlūkot izejas kodu

提交分页查询功能

波比 11 mēneši atpakaļ
vecāks
revīzija
f35c8280a4

+ 6 - 0
Tech/controllers/default.go

@@ -15,3 +15,9 @@ func (c *MainController) Get() {
 	c.TplName = "index.tpl"
 
 }
+func (c *MainController) Options() {
+	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
+	c.Ctx.Output.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
+	c.Ctx.Output.Header("Access-Control-Allow-Headers", "Content-Type,Authorization")
+	c.Ctx.ResponseWriter.WriteHeader(200)
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 23
Tech/controllers/test.json


+ 458 - 11
Tech/controllers/电调.go

@@ -7,22 +7,153 @@ import (
 	"encoding/json"
 	"fmt"
 	"io"
+	"math/rand"
 	"net/http"
+	"os"
+	"time"
 
 	"github.com/beego/beego/v2/client/orm"
 	beego "github.com/beego/beego/v2/server/web"
 )
 
+func init() {
+	// 启动后台协程定期更新电调模型数据
+	go func() {
+		// 初始化延迟1秒执行,避免系统启动时的资源竞争
+		time.Sleep(1 * time.Second)
+
+		// 定时每5秒获取一次数据
+		ticker := time.NewTicker(5 * time.Second)
+		defer ticker.Stop()
+
+		for {
+			select {
+			case <-ticker.C:
+				updateElectricalData()
+			}
+		}
+	}()
+}
+
+// updateElectricalData 从电调服务获取数据并更新模型
+func updateElectricalData() {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Printf("更新电调数据时发生错误: %v\n", r)
+		}
+	}()
+
+	// 获取 ElectricModelManager 单例实例
+	manager := models.GetInstance()
+
+	// 获取模型列表副本,避免长时间持有锁
+	manager.Mutex.RLock()
+	modelsCopy := make(map[string]models.EViewMapModel)
+	for k, v := range manager.Models {
+		modelsCopy[k] = v
+	}
+	manager.Mutex.RUnlock()
+
+	// 如果 Models 为空,不进行任何处理
+	if len(modelsCopy) == 0 {
+		return
+	}
+
+	// 遍历已有模型并分别更新
+	for _, viewMapModel := range modelsCopy {
+		if len(viewMapModel.Models) > 0 && time.Since(viewMapModel.LastBatchUpdate) >= 5*time.Second {
+			// 获取第一个模型作为参考来构建请求参数
+			firstModel := viewMapModel.Models[0]
+
+			// 从配置获取电调服务地址
+			electricalIP, err := beego.AppConfig.String("ElectricalIP")
+			if err != nil {
+				fmt.Printf("读取电调服务IP配置失败: %v\n", err)
+				continue
+			}
+
+			electricalPort, err := beego.AppConfig.Int("ElectricalPort")
+			if err != nil {
+				fmt.Printf("读取电调服务端口配置失败: %v\n", err)
+				continue
+			}
+
+			// 构造电调服务地址
+			electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/AllEqpmtList", electricalIP, electricalPort)
+
+			// 准备请求数据
+			type RequestData struct {
+				LineID    int `json:"lineID"`
+				StationID int `json:"StationID"`
+				ViewID    int `json:"ViewID"`
+			}
+			reqData := RequestData{
+				LineID:    firstModel.LineID,
+				StationID: firstModel.StationID,
+				ViewID:    firstModel.ViewID,
+			}
+
+			// 将请求数据转换为JSON
+			reqBody, err := json.Marshal(reqData)
+			if err != nil {
+				fmt.Printf("构造请求数据失败: %v\n", err)
+				continue
+			}
+
+			// 发送POST请求获取数据
+			resp, err := http.Post(electricalAddr, "application/json", bytes.NewBuffer(reqBody))
+			if err != nil {
+				fmt.Printf("调用电调服务获取所有设备列表接口失败: %v\n", err)
+				continue
+			}
+
+			// 读取响应体
+			bodyBytes, err := io.ReadAll(resp.Body)
+			resp.Body.Close()
+			if err != nil {
+				fmt.Printf("读取电调服务响应失败: %v\n", err)
+				continue
+			}
+
+			// 检查响应状态
+			if resp.StatusCode != http.StatusOK {
+				fmt.Printf("电调服务返回异常状态码: %d,响应内容: %s\n", resp.StatusCode, string(bodyBytes))
+				continue
+			}
+
+			// 解析JSON响应
+			var result map[string]interface{}
+			if err := json.Unmarshal(bodyBytes, &result); err != nil {
+				fmt.Printf("解析电调服务响应失败: %v\n", err)
+				continue
+			}
+
+			// 检查是否有data字段
+			if data, exists := result["data"]; exists {
+				// 解析data中的设备列表并更新到模型管理器
+				var equipments []models.DiandiaoModel
+				if equipBytes, err := json.Marshal(data); err == nil {
+					if err := json.Unmarshal(equipBytes, &equipments); err == nil {
+						// 更新总包设备数据 (在更新时加锁)
+						manager.UpdateBatchData(equipments)
+						fmt.Printf("成功更新线路%d车站%d视图%d的电调模型数据\n", firstModel.LineID, firstModel.StationID, firstModel.ViewID)
+					} else {
+						fmt.Printf("解析设备列表失败: %v\n", err)
+					}
+				}
+			}
+		}
+	}
+}
+
 type EDispatchController struct {
 	beego.Controller
 }
 
 // /courserun/eqpmtstatus 更新电调设备状态
 func (c *EDispatchController) Eqpmtstatus() {
-	var req struct {
-		UserName string `json:"userName"`
-		Password string `json:"password"`
-	}
+	var req models.DiandiaoModel
+
 	requestBody := c.Ctx.Input.RequestBody
 	println("Request Body:", string(requestBody))
 	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
@@ -35,6 +166,12 @@ func (c *EDispatchController) Eqpmtstatus() {
 		return
 	}
 
+	// 获取 ElectricModelManager 单例实例
+	manager := models.GetInstance()
+
+	// 更新单个设备数据
+	manager.UpdateSingleDevice(req)
+
 	c.Data["json"] = map[string]interface{}{
 		"code": 200,
 		"msg":  "更新电调设备状态",
@@ -42,11 +179,18 @@ func (c *EDispatchController) Eqpmtstatus() {
 	c.ServeJSON()
 }
 
+// /courserun/add_ctrl_log 添加电调控制日志
 // /courserun/add_ctrl_log 添加电调控制日志
 func (c *EDispatchController) Addctrllog() {
 	var req struct {
-		UserName string `json:"userName"`
-		Password string `json:"password"`
+		CtrlType int    `json:"CtrlType"`
+		CtrlFrom int    `json:"CtrlFrom"`
+		CtrlUser string `json:"CtrlUser"`
+		Param1   string `json:"Param1"`
+		Param2   string `json:"Param2"`
+		Param3   string `json:"Param3"`
+		Param4   string `json:"Param4"`
+		Param5   string `json:"Param5"`
 	}
 	requestBody := c.Ctx.Input.RequestBody
 	println("Request Body:", string(requestBody))
@@ -59,6 +203,95 @@ func (c *EDispatchController) Addctrllog() {
 		c.ServeJSON()
 		return
 	}
+
+	// 获取数据库连接
+	o := orm.NewOrm()
+
+	// 查找当前正在运行的课程
+	var runningCourse models.CourseRunLog
+	err := o.QueryTable(new(models.CourseRunLog)).
+		Filter("CourseTime", 0).
+		OrderBy("-RunLogID").
+		One(&runningCourse)
+
+	if err != nil {
+		c.Ctx.Output.SetStatus(400)
+		c.Data["json"] = map[string]interface{}{
+			"code": 400,
+			"msg":  "查找当前运行课程失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 查找当前运行课程中最大的RunOperID
+	var maxOperLog models.CourseOperLog
+	var runOperID int
+	err = o.QueryTable(new(models.CourseOperLog)).
+		Filter("RunLogID", runningCourse.RunLogID).
+		OrderBy("-RunOperID").
+		One(&maxOperLog)
+
+	if err != nil && err != orm.ErrNoRows {
+		c.Ctx.Output.SetStatus(500)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "查询操作日志失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	if err == orm.ErrNoRows {
+		// 如果没有找到记录,则从1开始
+		runOperID = 1
+	} else {
+		// 找到记录,则取最大值加1
+		runOperID = maxOperLog.RunOperID + 1
+	}
+
+	runDateTime, err := time.ParseInLocation("2006-01-02 15:04:05", runningCourse.RunDateTime, time.Local)
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code":      500,
+			"msg":       "解析课程开始时间失败: " + err.Error(),
+			"runStatus": 0,
+			"data":      nil,
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 计算从课程开始到现在的秒数,减去暂停累计时间
+	operTime := int(time.Since(runDateTime).Seconds()) - runningCourse.PauseTotalTime
+
+	// 创建操作日志记录
+	operLog := models.CourseOperLog{
+		RunLogID:    runningCourse.RunLogID,
+		RunCourseID: runningCourse.RunCourseID,
+		RunOperID:   runOperID,
+		OperName:    req.CtrlUser,
+		OperTime:    operTime,
+		OperScore:   0, // 默认分数为0
+		OperParam1:  req.Param1,
+		OperParam2:  req.Param2,
+		OperParam3:  req.Param3,
+		OperParam4:  req.Param4,
+		OperParam5:  req.Param5,
+	}
+
+	// 插入操作日志记录到数据库
+	_, err = o.Insert(&operLog)
+	if err != nil {
+		c.Ctx.Output.SetStatus(500)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "插入操作日志失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
 	c.Data["json"] = map[string]interface{}{
 		"code": 200,
 		"msg":  "添加操作日志成功",
@@ -146,9 +379,159 @@ func (c *EDispatchController) SubSysStatus() {
 
 	c.ServeJSON()
 }
+func (c *EDispatchController) UpdateTestStatus() {
+
+}
 
 // /serverCtrl/alleqpmtlist 获取所有设备列表
 func (c *EDispatchController) AllEqpmtList() {
+	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
+	// 定义与testStatus.json文件匹配的结构体
+	type jsonData struct {
+		DataID   string `json:"dataId"`
+		DataName string `json:"dataName"`
+		Value    string `json:"value"`
+		ID       string `json:"id"`
+	}
+
+	// 读取testStatus.json文件
+	filePath := "static/testStatus.json"
+	data, err := os.ReadFile(filePath)
+	if err != nil {
+		c.Ctx.Output.SetStatus(500)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取文件失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 解析JSON数据
+	var jsonDataList []jsonData
+	err = json.Unmarshal(data, &jsonDataList)
+	if err != nil {
+		c.Ctx.Output.SetStatus(500)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "解析JSON失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 转换为EquipmentData结构体
+	type EquipmentData struct {
+		DataID   string `json:"dataId"`
+		DataName string `json:"dataName"`
+		Value    string `json:"value"`
+		ID       string `json:"id"`
+	}
+	//动态生成值 1-3改变
+
+	// 初始化随机数种子
+	rand.Seed(time.Now().UnixNano())
+
+	// 生成1-3之间的随机数
+	nValue := rand.Intn(3) + 1
+
+	var equipmentDataList []EquipmentData
+	for _, item := range jsonDataList {
+		equipment := EquipmentData{
+			DataID:   item.DataID,
+			DataName: item.DataName,
+			Value:    fmt.Sprintf("%d", nValue),
+			ID:       item.ID,
+		}
+		equipmentDataList = append(equipmentDataList, equipment)
+	}
+
+	// 返回结果
+	c.Data["json"] = equipmentDataList
+	c.ServeJSON()
+
+}
+
+// /serverCtrl/alleqpmtlist 获取所有设备列表
+func (c *EDispatchController) AllEqpmtList2() {
+	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
+	// 定义与testStatus.json文件匹配的结构体
+	type jsonData struct {
+		DataID   string `json:"dataId"`
+		DataName string `json:"dataName"`
+		Value    string `json:"value"`
+		ID       string `json:"id"`
+	}
+
+	// 读取testStatus.json文件
+	filePath := "static/testStatus.json"
+	data, err := os.ReadFile(filePath)
+	if err != nil {
+		c.Ctx.Output.SetStatus(500)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取文件失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 解析JSON数据
+	var jsonDataList []jsonData
+	err = json.Unmarshal(data, &jsonDataList)
+	if err != nil {
+		c.Ctx.Output.SetStatus(500)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "解析JSON失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 转换为EquipmentData结构体
+	type EquipmentData struct {
+		DataID   string `json:"dataId"`
+		DataName string `json:"dataName"`
+		Value    string `json:"value"`
+		ID       string `json:"id"`
+	}
+	//动态生成值 1-3改变
+
+	// 初始化随机数种子
+	rand.Seed(time.Now().UnixNano())
+
+	// 生成1-3之间的随机数
+	nValue := rand.Intn(3) + 1
+
+	var equipmentDataList []EquipmentData
+	for _, item := range jsonDataList {
+		equipment := EquipmentData{
+			DataID:   item.DataID,
+			DataName: item.DataName,
+			Value:    fmt.Sprintf("%d", nValue),
+			ID:       item.ID,
+		}
+		equipmentDataList = append(equipmentDataList, equipment)
+	}
+
+	// 返回结果
+	c.Data["json"] = equipmentDataList
+	c.ServeJSON()
+
+}
+
+// /serverCtrl/alleqpmtlist 获取所有设备列表
+func (c *EDispatchController) AllEqpmtList_bak() {
+	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
+	// 转换缓存数据为指定格式
+	type EquipmentData struct {
+		DataID   string `json:"dataId"`
+		DataName string `json:"dataName"`
+		Value    string `json:"value"`
+		ID       string `json:"id"`
+	}
+
 	// 从配置文件读取电调服务IP和端口
 	electricalIP, err := beego.AppConfig.String("ElectricalIP")
 	if err != nil {
@@ -212,6 +595,44 @@ func (c *EDispatchController) AllEqpmtList() {
 		}
 	}
 
+	// 生成请求key
+	model := models.DiandiaoModel{
+		LineID:    lineID,
+		StationID: 0,
+		ViewID:    0,
+	}
+	key := model.GenerateModelKey()
+
+	// 获取 ElectricModelManager 单例实例
+	manager := models.GetInstance()
+
+	// 检查缓存中是否存在对应key的数据,且最后更新时间在5秒内
+	if viewMapModel, exists := manager.GetModelByKey(key); exists {
+		// 检查最后总包更新时间是否在5秒内
+		if time.Since(viewMapModel.LastBatchUpdate) <= 5*time.Second || time.Since(viewMapModel.LastDeviceUpdate) <= 5*time.Second {
+
+			var equipmentsData []EquipmentData
+			for _, model := range viewMapModel.Models {
+				equip := EquipmentData{
+					DataID:   model.EqpmtID,
+					ID:       model.EqpmtID,
+					Value:    fmt.Sprintf("%d", model.Status),
+					DataName: model.StatusName,
+				}
+				equipmentsData = append(equipmentsData, equip)
+			}
+
+			// 使用缓存数据
+			c.Data["json"] = map[string]interface{}{
+				"code": 200,
+				"msg":  "获取所有设备列表成功(缓存)",
+				"data": equipmentsData,
+			}
+			c.ServeJSON()
+			return
+		}
+	}
+
 	// 准备请求数据
 	type RequestData struct {
 		LineID    int `json:"lineID"`
@@ -281,21 +702,47 @@ func (c *EDispatchController) AllEqpmtList() {
 	} else {
 		// 如果是JSON格式,检查是否有data字段
 		if data, exists := result["data"]; exists {
-			// 如果电调返回的数据中有data字段,直接使用它
+			// 解析data中的设备列表并更新到模型管理器
+			var equipments []models.DiandiaoModel
+			if equipBytes, err := json.Marshal(data); err == nil {
+				if err := json.Unmarshal(equipBytes, &equipments); err == nil {
+					// 更新总包设备数据
+					manager.UpdateBatchData(equipments)
+				}
+			}
+
+			var equipmentsData []EquipmentData
+			for _, equip := range equipments {
+				equipmentData := EquipmentData{
+					DataID:   equip.EqpmtID,
+					DataName: equip.StatusName,
+					Value:    fmt.Sprintf("%d", equip.Status),
+					ID:       equip.EqpmtID,
+				}
+				equipmentsData = append(equipmentsData, equipmentData)
+			}
+
+			// 返回响应
 			c.Data["json"] = map[string]interface{}{
 				"code": 200,
 				"msg":  "获取所有设备列表成功",
-				"data": data,
+				"data": equipmentsData,
 			}
 		} else {
 			// 如果没有data字段,返回整个响应
 			c.Data["json"] = map[string]interface{}{
-				"code": 200,
-				"msg":  "获取所有设备列表成功",
-				"data": result,
+				"code": 500,
+				"msg":  "获取所有设备列表失败",
 			}
 		}
 	}
 
 	c.ServeJSON()
 }
+
+func (c *EDispatchController) Options() {
+	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
+	c.Ctx.Output.Header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
+	c.Ctx.Output.Header("Access-Control-Allow-Headers", "Content-Type,Authorization")
+	c.Ctx.ResponseWriter.WriteHeader(200)
+}

+ 28 - 8
Tech/controllers/节点解析存储.go

@@ -18,7 +18,7 @@ func ParserAndSaveNode(courseId int, strJson string) (bool, string) {
 	var rootNode models.Node
 	err := json.Unmarshal([]byte(strJson), &rootNode)
 	if err != nil {
-		return false, "JSON解析失败"
+		return false, fmt.Sprintf("JSON解析失败败: %v", err)
 	}
 
 	//1.清除 课程 CourseActionNode CourseOperationNode CourseVoiceNode CourseFaultNode CourseNodeTrigger 数据
@@ -90,7 +90,7 @@ func saveNodeToDB(classID int, parentID int, node *models.Node) (bool, string) {
 
 	// // 保存节点数据
 	if node.NodeData != nil {
-		success, msg := saveNodeData(classID, parentID, node.NodeData)
+		success, msg := saveNodeData(classID, node.NodeData.NodeID, node.NodeData)
 		if !success {
 			return false, msg
 		}
@@ -104,6 +104,23 @@ func saveNodeToDB(classID int, parentID int, node *models.Node) (bool, string) {
 		}
 	}
 
+	// 递归保存条件节点
+	if node.ConditionNodes != nil {
+		for _, conditionNode := range node.ConditionNodes {
+			// 将 STConditionNodes 转换为 Node 结构
+			convertedNode := &models.Node{
+				NodeName:       conditionNode.NodeName,
+				NodeType:       conditionNode.NodeType,
+				NodeData:       conditionNode.NodeData,
+				ChildNode:      conditionNode.ChildNode,
+				ConditionNodes: nil, // 条件节点通常不会有自己的条件节点
+			}
+			success, msg := saveNodeToDB(classID, node.NodeData.NodeID, convertedNode)
+			if !success {
+				return false, msg
+			}
+		}
+	}
 	return true, ""
 }
 
@@ -134,6 +151,8 @@ func SaveCourseActionNode(classID int, parentID int, node *models.Node) (bool, e
 		nodeType = 4
 	case "voice":
 		nodeType = 5
+	case "condition":
+		nodeType = 6
 	}
 
 	// 创建CourseActionNode对象
@@ -155,12 +174,13 @@ func SaveCourseActionNode(classID int, parentID int, node *models.Node) (bool, e
 	}
 	println(courseActionNode)
 
-	// 插入数据并获取ID
-	_, err := o.Insert(courseActionNode)
-	if err != nil {
-		return false, fmt.Errorf("插入CourseActionNode失败,节点重复: %v", err)
+	if courseActionNode.NodeID > 0 {
+		// 插入数据并获取ID
+		_, err := o.Insert(courseActionNode)
+		if err != nil {
+			return false, fmt.Errorf("插入CourseActionNode失败,节点重复: %v", err)
+		}
 	}
-
 	if nodeType != common.NoteTypeDef_operation && nodeType != common.NoteTypeDef_Voice {
 		return true, nil //语音节点和操作节点才需要保存评价
 	}
@@ -172,7 +192,7 @@ func SaveCourseActionNode(classID int, parentID int, node *models.Node) (bool, e
 
 	// 查询课程信息,检查虚拟角色设置
 	courseInfo := models.CourseInfo{CourseID: classID}
-	err = o.Read(&courseInfo, "CourseID")
+	err := o.Read(&courseInfo, "CourseID")
 	if err != nil {
 		return false, fmt.Errorf("查询课程信息失败: %v", err)
 	}

+ 174 - 18
Tech/controllers/评价.go

@@ -458,33 +458,165 @@ func (c *EvaController) EvaRecordList() {
 	requestBody := c.Ctx.Input.RequestBody
 	println("Request Body:", string(requestBody))
 
-	if err := json.Unmarshal(requestBody, &req); err != nil {
-		c.Ctx.Output.SetStatus(400)
-		c.Data["json"] = map[string]interface{}{
-			"code": 400,
-			"msg":  "请求参数格式错误: " + err.Error(),
+	if len(requestBody) > 0 {
+		if err := json.Unmarshal(requestBody, &req); err != nil {
+			c.Ctx.Output.SetStatus(400)
+			c.Data["json"] = map[string]interface{}{
+				"code": 400,
+				"msg":  "请求参数格式错误: " + err.Error(),
+			}
+			c.ServeJSON()
+			return
 		}
-		c.ServeJSON()
-		return
 	}
 
-	if req.RunLogID == 0 {
-		c.Ctx.Output.SetStatus(400)
+	o := orm.NewOrm()
+
+	// 查询所有角色信息用于关联角色名称
+	var roleInfos []*models.RoleInfo
+	_, err := o.QueryTable(new(models.RoleInfo)).All(&roleInfos)
+	if err != nil {
 		c.Data["json"] = map[string]interface{}{
-			"code": 400,
-			"msg":  "缺少运行记录编号参数",
+			"code": 500,
+			"msg":  "查询角色信息失败: " + err.Error(),
 		}
 		c.ServeJSON()
 		return
 	}
 
-	o := orm.NewOrm()
-	var evaLogList []*models.CourseEvaLog
+	// 创建角色ID到角色名称的映射
+	roleMap := make(map[int]string)
+	for _, role := range roleInfos {
+		roleMap[role.RoleID] = role.RoleName
+	}
+
+	// 定义联合查询的结果结构体
+	type EvaRecord struct {
+		// CourseEvaLog 字段
+		RunLogID    int     `orm:"column(运行记录编号)" json:"runLogID"`
+		RunCourseID int     `orm:"column(运行课程ID)" json:"runCourseID"`
+		RunOperID   int     `orm:"column(运行操作ID)" json:"runOperID"`
+		OperName    string  `orm:"column(操作名称)" json:"operName"`
+		OperTime    int     `orm:"column(操作时间)" json:"operTime"`
+		OperScore   float64 `orm:"column(操作得分)" json:"operScore"`
+		OperParam1  string  `orm:"column(操作参数1)" json:"operParam1"`
+		OperParam2  string  `orm:"column(操作参数2)" json:"operParam2"`
+		OperParam3  string  `orm:"column(操作参数3)" json:"operParam3"`
+		OperParam4  string  `orm:"column(操作参数4)" json:"operParam4"`
+		OperParam5  string  `orm:"column(操作参数5)" json:"operParam5"`
+
+		// CourseEvaList 字段
+		EvaTargetRole int `orm:"column(评价目标角色)" json:"evaTargetRole"`
+		EvaType       int `orm:"column(评价类型)" json:"evaType"`
+		EvaSource     int `orm:"column(评价来源)" json:"evaSource"`
+		EvaScore      int `orm:"column(评价赋分)" json:"evaScore"`
+		EvaDeduction  int `orm:"column(评价失分)" json:"evaDeduction"`
+	}
+
+	// 定义带有角色名称的扩展结果结构体
+	type EvaRecordWithRoleName struct {
+		// CourseEvaLog 字段
+		RunLogID    int     `json:"runLogID"`
+		RunCourseID int     `json:"runCourseID"`
+		RunOperID   int     `json:"runOperID"`
+		OperName    string  `json:"operName"`
+		OperTime    int     `json:"operTime"`
+		OperScore   float64 `json:"operScore"`
+		OperParam1  string  `json:"operParam1"`
+		OperParam2  string  `json:"operParam2"`
+		OperParam3  string  `json:"operParam3"`
+		OperParam4  string  `json:"operParam4"`
+		OperParam5  string  `json:"operParam5"`
+
+		// CourseEvaList 字段
+		EvaTargetRole  int    `json:"evaTargetRole"`
+		TargetRoleName string `json:"targetRoleName"`
+		EvaType        int    `json:"evaType"`
+		EvaSource      int    `json:"evaSource"`
+		EvaScore       int    `json:"evaScore"`
+		EvaDeduction   int    `json:"evaDeduction"`
+	}
+
+	var evaRecords []EvaRecord
+	var count int64
 
-	// 根据运行记录编号查询评价记录列表
-	count, err := o.QueryTable(new(models.CourseEvaLog)).
-		Filter("RunLogID", req.RunLogID).
-		All(&evaLogList)
+	// 如果RunLogID > 0,则查询对应的课程运行评价列表
+	// 否则查询最新的课程运行评价列表
+	if req.RunLogID > 0 {
+		// 根据运行记录编号查询联合评价记录列表
+		count, err = o.Raw(`
+			SELECT 
+				l.运行记录编号,
+				l.运行课程ID,
+				l.运行操作ID,
+				l.操作名称,
+				l.操作时间,
+				l.操作得分,
+				l.操作参数1,
+				l.操作参数2,
+				l.操作参数3,
+				l.操作参数4,
+				l.操作参数5,
+				e.评价目标角色,
+				e.评价类型,
+				e.评价来源,
+				e.评价赋分,
+				e.评价失分
+			FROM CourseEvaLog l
+			LEFT JOIN CourseEvaList e ON l.运行课程ID = e.课程ID AND l.运行操作ID = e.序号
+			WHERE l.运行记录编号 = ?
+		`, req.RunLogID).QueryRows(&evaRecords)
+	} else {
+		// 查询最新的课程运行记录ID
+		var latestRunLog models.CourseRunLog
+		err = o.QueryTable(new(models.CourseRunLog)).
+			OrderBy("-RunLogID").
+			One(&latestRunLog)
+
+		if err != nil {
+			if err == orm.ErrNoRows {
+				// 没有运行记录
+				c.Data["json"] = map[string]interface{}{
+					"code": 404,
+					"msg":  "未找到任何课程运行记录",
+				}
+				c.ServeJSON()
+				return
+			} else {
+				// 查询出错
+				c.Data["json"] = map[string]interface{}{
+					"code": 500,
+					"msg":  "查询课程运行记录失败: " + err.Error(),
+				}
+				c.ServeJSON()
+				return
+			}
+		}
+
+		// 根据最新运行记录ID查询联合评价记录列表
+		count, err = o.Raw(`
+			SELECT 
+				l.运行记录编号,
+				l.运行课程ID,
+				l.运行操作ID,
+				l.操作名称,
+				l.操作时间,
+				l.操作得分,
+				l.操作参数1,
+				l.操作参数2,
+				l.操作参数3,
+				l.操作参数4,
+				l.操作参数5,
+				e.评价目标角色,
+				e.评价类型,
+				e.评价来源,
+				e.评价赋分,
+				e.评价失分
+			FROM CourseEvaLog l
+			LEFT JOIN CourseEvaList e ON l.运行课程ID = e.课程ID AND l.运行操作ID = e.序号
+			WHERE l.运行记录编号 = ?
+		`, latestRunLog.RunLogID).QueryRows(&evaRecords)
+	}
 
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{
@@ -495,11 +627,35 @@ func (c *EvaController) EvaRecordList() {
 		return
 	}
 
+	// 为每个评价项添加角色名称(适配 evaRecords 为值切片)
+	evaRecordsWithRoles := make([]*EvaRecordWithRoleName, len(evaRecords))
+	for i, record := range evaRecords {
+		evaRecordsWithRoles[i] = &EvaRecordWithRoleName{
+			RunLogID:       record.RunLogID,
+			RunCourseID:    record.RunCourseID,
+			RunOperID:      record.RunOperID,
+			OperName:       record.OperName,
+			OperTime:       record.OperTime,
+			OperScore:      record.OperScore,
+			OperParam1:     record.OperParam1,
+			OperParam2:     record.OperParam2,
+			OperParam3:     record.OperParam3,
+			OperParam4:     record.OperParam4,
+			OperParam5:     record.OperParam5,
+			EvaTargetRole:  record.EvaTargetRole,
+			TargetRoleName: roleMap[record.EvaTargetRole],
+			EvaType:        record.EvaType,
+			EvaSource:      record.EvaSource,
+			EvaScore:       record.EvaScore,
+			EvaDeduction:   record.EvaDeduction,
+		}
+	}
+
 	c.Data["json"] = map[string]interface{}{
 		"code":  200,
 		"count": count,
 		"msg":   "成功",
-		"data":  evaLogList,
+		"data":  evaRecordsWithRoles,
 	}
 	c.ServeJSON()
 }

+ 105 - 1
Tech/controllers/课程.go

@@ -68,7 +68,7 @@ func (c *CourseController) List() {
 	}
 
 	var courses []models.CourseInfo
-	count, err := qs.All(&courses, "课程ID", "课程GUID", "课程名称", "分类ID", "外部分类ID", "虚拟起始时间", "课程总时长", "线路号", "运行图", "课程描述", "创建人", "创建时间", "修改时间", "指导描述", "指导文件地址", "虚拟角色")
+	count, err := qs.OrderBy("-CreateTime").All(&courses, "课程ID", "课程GUID", "课程名称", "分类ID", "外部分类ID", "虚拟起始时间", "课程总时长", "线路号", "运行图", "课程描述", "创建人", "创建时间", "修改时间", "指导描述", "指导文件地址", "虚拟角色")
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{"code": 500, "error": "查询失败: " + err.Error()}
 		c.ServeJSON()
@@ -79,6 +79,110 @@ func (c *CourseController) List() {
 	c.ServeJSON()
 }
 
+// /course/listpage 获取所有课程信息列表
+func (c *CourseController) ListPage() {
+	type Request struct {
+		PageNum    int    `json:"pageNum"`
+		PageSize   int    `json:"pageSize"`
+		CourseID   int    `json:"courseID"`
+		CourseName string `json:"courseName"`
+		TypeID     int    `json:"typeID"`
+		Creator    string `json:"creator"`
+		LineNo     int    `json:"lineNo"`
+	}
+
+	var req Request
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		c.Ctx.Output.SetStatus(400)
+		c.Data["json"] = map[string]interface{}{
+			"code": 400,
+			"msg":  "请求参数格式错误: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 设置默认值
+	if req.PageNum <= 0 {
+		req.PageNum = 1
+	}
+	if req.PageSize <= 0 {
+		req.PageSize = 10
+	}
+
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(models.CourseInfo))
+
+	// 编号查询
+	if req.CourseID != 0 {
+		qs = qs.Filter("CourseID", req.CourseID)
+	}
+
+	// 课程名称模糊查询
+	if req.CourseName != "" {
+		qs = qs.Filter("CourseName__icontains", req.CourseName)
+	}
+
+	// 培训类型查询(分类ID)
+	if req.TypeID != 0 {
+		qs = qs.Filter("TypeID", req.TypeID)
+	}
+
+	// 创建人查询
+	if req.Creator != "" {
+		qs = qs.Filter("Creator__icontains", req.Creator)
+	}
+
+	// 线路查询(线路号)
+	if req.LineNo != 0 {
+		qs = qs.Filter("LineNo", req.LineNo)
+	}
+
+	// 获取总数
+	totalCount, err := qs.Count()
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "查询失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 计算总页数
+	totalPage := int((totalCount + int64(req.PageSize) - 1) / int64(req.PageSize))
+
+	// 分页查询,按创建时间倒序排列
+	var courses []models.CourseInfo
+	_, err = qs.OrderBy("-CreateTime").Limit(req.PageSize).Offset((req.PageNum-1)*req.PageSize).All(&courses,
+		"课程ID", "课程GUID", "课程名称", "分类ID", "外部分类ID", "虚拟起始时间", "课程总时长", "线路号", "运行图",
+		"课程描述", "创建人", "创建时间", "修改时间", "指导描述", "指导文件地址", "虚拟角色")
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "查询失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 构造分页数据
+	pageData := map[string]interface{}{
+		"pageNum":    req.PageNum,
+		"pageSize":   req.PageSize,
+		"totalCount": totalCount,
+		"totalPage":  totalPage,
+		"list":       courses,
+	}
+
+	c.Data["json"] = map[string]interface{}{
+		"code": 200,
+		"msg":  "success",
+		"data": pageData,
+	}
+	c.ServeJSON()
+}
+
 // /course/add 新增课程信息
 func (c *CourseController) Add() {
 	var course models.CourseInfo

+ 112 - 0
Tech/controllers/课程运行.go

@@ -779,3 +779,115 @@ func (c *CourseRunController) RunRecordList() {
 	}
 	c.ServeJSON()
 }
+
+// /runrecord/delete 删除课程运行记录
+func (c *CourseRunController) RunRecordDelete() {
+	// 定义请求参数结构体
+	type Request struct {
+		RunLogID int `json:"runLogID"`
+	}
+
+	var req Request
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 400,
+			"msg":  "请求参数格式错误: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	if req.RunLogID == 0 {
+		c.Data["json"] = map[string]interface{}{
+			"code": 400,
+			"msg":  "请提供有效的运行记录ID",
+		}
+		c.ServeJSON()
+		return
+	}
+
+	o := orm.NewOrm()
+
+	// 删除课程运行记录
+	n, err := o.Delete(&models.CourseRunLog{RunLogID: req.RunLogID})
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "删除失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	if n == 0 {
+		c.Data["json"] = map[string]interface{}{
+			"code": 404,
+			"msg":  "运行记录不存在",
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 同时删除相关的操作记录和评价记录
+	o.QueryTable(new(models.CourseOperLog)).Filter("RunLogID", req.RunLogID).Delete()
+	o.QueryTable(new(models.CourseEvaLog)).Filter("RunLogID", req.RunLogID).Delete()
+
+	// 构造返回结果
+	c.Data["json"] = map[string]interface{}{
+		"code": 200,
+		"msg":  "删除成功",
+	}
+	c.ServeJSON()
+}
+
+// /oper/runrecord/list 获取操作运行记录列表
+func (c *CourseRunController) OperRunRecordList() {
+	// 获取数据库连接
+	o := orm.NewOrm()
+
+	// 查找最近的课程运行记录(按RunLogID倒序排列,取第一个)
+	var latestCourseRun models.CourseRunLog
+	err := o.QueryTable(new(models.CourseRunLog)).
+		OrderBy("-RunLogID").
+		One(&latestCourseRun)
+
+	if err != nil {
+		if err == orm.ErrNoRows {
+			c.Data["json"] = map[string]interface{}{
+				"code": 404,
+				"msg":  "未找到任何课程运行记录",
+			}
+		} else {
+			c.Data["json"] = map[string]interface{}{
+				"code": 500,
+				"msg":  "查询课程运行记录失败: " + err.Error(),
+			}
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 查找该课程运行记录对应的所有操作日志,并按RunOperID排序
+	var operLogs []models.CourseOperLog
+	_, err = o.QueryTable(new(models.CourseOperLog)).
+		Filter("RunLogID", latestCourseRun.RunLogID).
+		OrderBy("RunOperID").
+		All(&operLogs)
+
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "查询操作日志失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 返回结果,只返回操作日志列表
+	c.Data["json"] = map[string]interface{}{
+		"code": 200,
+		"msg":  "获取操作日志列表成功",
+		"data": operLogs,
+	}
+	c.ServeJSON()
+}

+ 12 - 1
Tech/main.go

@@ -6,6 +6,7 @@ import (
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/beego/beego/v2/server/web"
 	beego "github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/filter/cors"
 )
 
 func init() {
@@ -28,8 +29,18 @@ func main() {
 
 	// 可选:开启 ORM 调试模式,打印 SQL 日志
 	// 将 URL 路径 /static/upload 映射到本地目录 static/upload
+
+	// CORS 过滤器
+	beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
+		AllowAllOrigins:  true,
+		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
+		AllowHeaders:     []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Content-Type"},
+		ExposeHeaders:    []string{"Content-Length", "Access-Control-Allow-Origin"},
+		AllowCredentials: true,
+	}))
+
 	web.SetStaticPath("/static/upload", "static/upload")
 	orm.Debug = true
 	beego.Run()
-	
+
 }

+ 2 - 3
Tech/models/教员模型.go

@@ -100,7 +100,6 @@ type CourseFaultNode struct {
 	TextParam3 string `orm:"column(文本参数3);type(text)" json:"textParam3"`
 	TextParam4 string `orm:"column(文本参数4);type(text)" json:"textParam4"`
 	TextParam5 string `orm:"column(文本参数5);type(text)" json:"textParam5"`
-	RuleID     int    `orm:"column(规则编号)" json:"ruleID"`
 }
 
 func (c *CourseFaultNode) TableName() string { return "CourseFaultNode" }
@@ -218,9 +217,9 @@ func (c *CourseRunLog) TableName() string { return "CourseRunLog" }
 
 // 14. CourseOperLog - 课程操作记录表
 type CourseOperLog struct {
-	RunLogID    string  `orm:"column(运行记录编号);pk;type(text)" json:"runLogID"`
+	RunLogID    int     `orm:"column(运行记录编号);pk;" json:"runLogID"`
 	RunCourseID int     `orm:"column(运行课程ID)" json:"runCourseID"`
-	RunOperID   string  `orm:"column(运行操作ID);type(text)" json:"runOperID"`
+	RunOperID   int     `orm:"column(运行操作ID)" json:"runOperID"`
 	OperName    string  `orm:"column(操作名称);type(text)" json:"operName"`
 	OperTime    int     `orm:"column(操作时间)" json:"operTime"`
 	OperScore   float64 `orm:"column(操作得分)" json:"operScore"`

+ 153 - 0
Tech/models/电调模型.go

@@ -0,0 +1,153 @@
+package models
+
+import (
+	"fmt"
+	"sync"
+	"time"
+)
+
+// DiandiaoModel 表示电调的 JSON 结构
+type DiandiaoModel struct {
+	SubSys              int    `json:"SubSys"`
+	CtrlType            int    `json:"CtrlType"`
+	Status              int    `json:"Status"`
+	StatusName          string `json:"StatusName"`
+	Category            int    `json:"Category"`
+	LineID              int    `json:"LineID"`
+	StationID           int    `json:"StationID"`
+	ViewID              int    `json:"ViewID"`
+	EqpmtID             string `json:"EqpmtID"`
+	CtrlLock            int    `json:"CtrlLock"`
+	FaultLock           int    `json:"FaultLock"`
+	RemoteLock          int    `json:"RemoteLock"`
+	CommunicationStatus int    `json:"CommunicationStaus"` // JSON 中字段为 CommunicationStaus(原样对应)
+	CtrlArea            int    `json:"CtrlArea"`
+}
+
+// generateModelKey 生成电调模型唯一键
+func (em *DiandiaoModel) GenerateModelKey() string {
+	return fmt.Sprintf("%d:%d:%d", em.LineID, em.StationID, em.ViewID)
+}
+
+// 单图元电调模型
+type EViewMapModel struct {
+	Models   []DiandiaoModel // key: modelKey, value: 设备列表
+	ModelKey string          // 唯一键
+
+	LastBatchUpdate  time.Time // 最后总包更新时间
+	LastDeviceUpdate time.Time // 单设备更新时间
+
+}
+
+// ElectricModelManager 电调模型管理器
+type ElectricModelManager struct {
+	Models map[string]EViewMapModel // key: modelKey, value: 单图元电调模型
+	Mutex  sync.RWMutex             // 读写锁保护并发访问
+	once   sync.Once                // 确保初始化只执行一次
+}
+
+// 使用 sync.Once 确保线程安全的单例实例创建
+var (
+	instance *ElectricModelManager
+	once     sync.Once
+)
+
+// GetInstance 获取 ElectricModelManager 的单例实例
+func GetInstance() *ElectricModelManager {
+	once.Do(func() {
+		instance = &ElectricModelManager{
+			Models: make(map[string]EViewMapModel),
+		}
+	})
+	return instance
+}
+
+// UpdateBatchData 更新总包数据
+func (em *ElectricModelManager) UpdateBatchData(models []DiandiaoModel) {
+	em.once.Do(func() {
+		em.Models = make(map[string]EViewMapModel)
+	})
+
+	// 创建新的映射而不是直接清空,提高并发安全性
+	newModels := make(map[string]EViewMapModel)
+
+	for _, model := range models {
+		key := model.GenerateModelKey()
+		if viewMapModel, exists := newModels[key]; exists {
+			viewMapModel.Models = append(viewMapModel.Models, model)
+			viewMapModel.LastBatchUpdate = time.Now()
+			newModels[key] = viewMapModel
+		} else {
+			newModels[key] = EViewMapModel{
+				Models:           []DiandiaoModel{model},
+				ModelKey:         key,
+				LastBatchUpdate:  time.Now(),
+				LastDeviceUpdate: time.Time{},
+			}
+		}
+	}
+
+	// 原子性地替换整个映射
+	em.Mutex.Lock()
+	em.Models = newModels
+	em.Mutex.Unlock()
+}
+
+// GetModelByKey 根据Key获取EViewMapModel
+func (em *ElectricModelManager) GetModelByKey(key string) (EViewMapModel, bool) {
+	em.Mutex.RLock()
+	defer em.Mutex.RUnlock()
+
+	model, exists := em.Models[key]
+	if !exists {
+		// 返回空值和false表示未找到
+		return EViewMapModel{}, false
+	}
+
+	// 返回拷贝以避免外部修改影响内部状态
+	modelsCopy := make([]DiandiaoModel, len(model.Models))
+	copy(modelsCopy, model.Models)
+
+	return EViewMapModel{
+		Models:           modelsCopy,
+		ModelKey:         model.ModelKey,
+		LastBatchUpdate:  model.LastBatchUpdate,
+		LastDeviceUpdate: model.LastDeviceUpdate,
+	}, true
+}
+
+// UpdateSingleDevice 更新单设备数据
+func (em *ElectricModelManager) UpdateSingleDevice(model DiandiaoModel) {
+	key := model.GenerateModelKey()
+
+	em.Mutex.Lock()
+	defer em.Mutex.Unlock()
+
+	if viewMapModel, exists := em.Models[key]; exists {
+		// 查找是否已存在该设备
+		found := false
+		for i, existingModel := range viewMapModel.Models {
+			if existingModel.EqpmtID == model.EqpmtID {
+				viewMapModel.Models[i] = model
+				found = true
+				break
+			}
+		}
+
+		// 如果未找到该设备,则添加新设备
+		if !found {
+			viewMapModel.Models = append(viewMapModel.Models, model)
+		}
+
+		viewMapModel.LastDeviceUpdate = time.Now()
+		em.Models[key] = viewMapModel
+	} else {
+		// 如果不存在该图元,则创建新的
+		em.Models[key] = EViewMapModel{
+			Models:           []DiandiaoModel{model},
+			ModelKey:         key,
+			LastBatchUpdate:  time.Time{},
+			LastDeviceUpdate: time.Now(),
+		}
+	}
+}

+ 10 - 0
Tech/models/节点模型.go

@@ -7,6 +7,16 @@ type Node struct {
 	NodeType  string    `json:"nodeType"`
 	NodeData  *NodeData `json:"nodeData"`
 	ChildNode *Node     `json:"childNode"`
+
+	ConditionNodes []*STConditionNodes `json:"conditionNodes"`
+}
+
+type STConditionNodes struct {
+	NodeName string `json:"nodeName"`
+	// 节点类型 start end operation fault voice
+	NodeType  string    `json:"nodeType"`
+	NodeData  *NodeData `json:"nodeData"`
+	ChildNode *Node     `json:"childNode"`
 }
 
 // NodeData 节点数据

+ 7 - 0
Tech/routers/router.go

@@ -15,6 +15,7 @@ func init() {
 
 	// 课程相关接口
 	beego.Router("/course/list", &controllers.CourseController{}, "post:List")
+	beego.Router("/course/listpage", &controllers.CourseController{}, "post:ListPage")
 	beego.Router("/course/add", &controllers.CourseController{}, "post:Add")
 	beego.Router("/course/update", &controllers.CourseController{}, "post:Update")
 	beego.Router("/course/delete", &controllers.CourseController{}, "post:Delete")
@@ -59,6 +60,12 @@ func init() {
 	beego.Router("/serverctrl/subsysstatus", &controllers.EDispatchController{}, "post:SubSysStatus")
 	beego.Router("/serverctrl/alleqpmtList", &controllers.EDispatchController{}, "post:AllEqpmtList")
 
+	beego.Router("/serverctrl/alleqpmtList2", &controllers.EDispatchController{}, "get:AllEqpmtList2")
+
 	//运行记录
 	beego.Router("/runrecord/list ", &controllers.CourseRunController{}, "post:RunRecordList")
+	beego.Router("/runrecord/delete ", &controllers.CourseRunController{}, "post:RunRecordDelete")
+
+	//操作日志
+	beego.Router("oper/runrecord/list ", &controllers.CourseRunController{}, "post:OperRunRecordList")
 }

+ 56 - 0
Tech/static/testStatus.json

@@ -0,0 +1,56 @@
+[
+    {
+        "dataId": "{C98FF90B-680C-4AC3-A73A-1434EACB4B3A}",
+        "dataName": "1",
+        "value": "1",
+        "id": "{C98FF90B-680C-4AC3-A73A-1434EACB4B3A}"
+    },
+    {
+        "dataId": "{F5DBDCC3-4335-4F37-98E2-175A20DAC757}",
+        "dataName": "2",
+        "value": "1",
+        "id": "{F5DBDCC3-4335-4F37-98E2-175A20DAC757}"
+    },
+    {
+        "dataId": "{324E889E-E10B-44D2-A2E8-EEB0BA7911F4}",
+        "dataName": "3",
+        "value": "1",
+        "id": "{324E889E-E10B-44D2-A2E8-EEB0BA7911F4}"
+    },
+    {
+        "dataId": "{082475CA-CC75-47A1-8F6C-B45494C86263}",
+        "dataName": "4",
+        "value": "1",
+        "id": "{082475CA-CC75-47A1-8F6C-B45494C86263}"
+    },
+    {
+        "dataId": "{BF5446C9-E6E0-4C03-9F22-164E091F7DF4}",
+        "dataName": "5",
+        "value": "1",
+        "id":"{BF5446C9-E6E0-4C03-9F22-164E091F7DF4}"
+    },
+    {
+        "dataId": "{5848FB4E-9CD4-4521-90CB-AC36B286C509}",
+        "dataName": "6",
+        "value": "1",
+        "id": "{5848FB4E-9CD4-4521-90CB-AC36B286C509}"
+    },
+    {
+        "dataId": "{2CC37E70-3972-4DB7-8AC7-4B7AC27048FF}",
+        "dataName": "7",
+        "value": "1",
+        "id": "{2CC37E70-3972-4DB7-8AC7-4B7AC27048FF}"
+    },
+    {
+        "dataId": "{9C483A67-D328-4880-91B8-CF8EAE8CC544}",
+        "dataName": "7",
+        "value": "1",
+        "id": "{9C483A67-D328-4880-91B8-CF8EAE8CC544}"
+    },
+    {
+        "dataId": "{B2B52F3C-5889-44FB-B311-E7429C66701A}",
+        "dataName": "8",
+        "value": "1",
+        "id": "{B2B52F3C-5889-44FB-B311-E7429C66701A}"
+    }
+]

+ 271 - 0
Tech/test.json

@@ -0,0 +1,271 @@
+{
+    "nodeId": 425930,
+    "nodeName": "开始",
+    "nodeType": "start",
+    "nodeData": {},
+    "childNode": {
+        "nodeId": "993911",
+        "nodeName": "路由",
+        "nodeType": "router",
+        "nodeData": {},
+        "conditionNodes": [
+            {
+                "nodeId": "993479",
+                "nodeName": "条件",
+                "nodeType": "condition",
+                "isLastCondition": false,
+                "nodeData": {
+                    "condition": "1"
+                },
+                "childNode": {
+                    "nodeId": "581959",
+                    "nodeName": "基本操作",
+                    "nodeType": "operation",
+                    "nodeData": {
+                        "nodeID": 581959,
+                        "name": "1111",
+                        "bindRole": 101,
+                        "nodeDetail": "",
+                        "delaySkip": 0,
+                        "loseItem": 1,
+                        "virtualOperation": 0,
+                        "nodeTrigger": {
+                            "nodeID": 581959,
+                            "triggerMode": 0,
+                            "textParam1": "",
+                            "textParam2": "",
+                            "event": "",
+                            "triggerDelay": 0
+                        },
+                        "operationNode": {
+                            "templateID": 1005,
+                            "categoryName": "电力设备控制",
+                            "subCategoryName": "遥信封锁",
+                            "param1Type": 2,
+                            "param2Type": 2,
+                            "param3Type": 2,
+                            "param4Type": 2,
+                            "param5Type": 2,
+                            "param1Desc": "",
+                            "param2Desc": "",
+                            "param3Desc": "",
+                            "param4Desc": "",
+                            "param5Desc": "",
+                            "score": 0,
+                            "deduction": 0
+                        }
+                    }
+                }
+            },
+            {
+                "nodeId": "993373",
+                "nodeName": "条件",
+                "nodeType": "condition",
+                "isLastCondition": true,
+                "nodeData": {
+                    "condition": "1"
+                },
+                "childNode": {
+                    "nodeId": "712268",
+                    "nodeName": "路由",
+                    "nodeType": "router",
+                    "nodeData": {},
+                    "conditionNodes": [
+                        {
+                            "nodeId": "712614",
+                            "nodeName": "条件",
+                            "nodeType": "condition",
+                            "isLastCondition": false,
+                            "nodeData": {
+                                "condition": "1"
+                            },
+                            "childNode": {
+                                "nodeId": "136267",
+                                "nodeName": "基本操作",
+                                "nodeType": "operation",
+                                "nodeData": {
+                                    "nodeID": 136267,
+                                    "name": "222",
+                                    "bindRole": 104,
+                                    "nodeDetail": "",
+                                    "delaySkip": 0,
+                                    "loseItem": 1,
+                                    "virtualOperation": 0,
+                                    "nodeTrigger": {
+                                        "nodeID": 136267,
+                                        "triggerMode": 0,
+                                        "textParam1": "",
+                                        "textParam2": "",
+                                        "event": "",
+                                        "triggerDelay": 0
+                                    },
+                                    "operationNode": {
+                                        "templateID": 1002,
+                                        "categoryName": "电力设备控制",
+                                        "subCategoryName": "分合闸",
+                                        "param1Type": 2,
+                                        "param2Type": 2,
+                                        "param3Type": 2,
+                                        "param4Type": 2,
+                                        "param5Type": 2,
+                                        "param1Desc": "",
+                                        "param2Desc": "",
+                                        "param3Desc": "",
+                                        "param4Desc": "",
+                                        "param5Desc": "",
+                                        "score": 3,
+                                        "deduction": 3
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "nodeId": "171260",
+                            "nodeName": "条件",
+                            "nodeType": "condition",
+                            "isLastCondition": true,
+                            "nodeData": {
+                                "condition": "1"
+                            },
+                            "childNode": {
+                                "nodeId": "649612",
+                                "nodeName": "基本操作",
+                                "nodeType": "operation",
+                                "nodeData": {
+                                    "nodeID": 649612,
+                                    "name": "555",
+                                    "bindRole": 104,
+                                    "nodeDetail": "111",
+                                    "delaySkip": 0,
+                                    "loseItem": 1,
+                                    "virtualOperation": 0,
+                                    "nodeTrigger": {
+                                        "nodeID": 649612,
+                                        "triggerMode": 0,
+                                        "textParam1": "",
+                                        "textParam2": "",
+                                        "event": "",
+                                        "triggerDelay": 0
+                                    },
+                                    "operationNode": {
+                                        "templateID": 1004,
+                                        "categoryName": "电力设备控制",
+                                        "subCategoryName": "遥信封锁",
+                                        "param1Type": 2,
+                                        "param2Type": 2,
+                                        "param3Type": 2,
+                                        "param4Type": 2,
+                                        "param5Type": 2,
+                                        "param1Desc": "",
+                                        "param2Desc": "",
+                                        "param3Desc": "",
+                                        "param4Desc": "",
+                                        "param5Desc": "",
+                                        "score": 2,
+                                        "deduction": 2
+                                    }
+                                }
+                            }
+                        }
+                    ]
+                }
+            }
+        ],
+        "childNode": {
+            "nodeId": 301942,
+            "nodeName": "基本操作",
+            "nodeType": "operation",
+            "nodeData": {
+                "name": "111",
+                "role": 102,
+                "templateID": 1002,
+                "categoryName": "电力设备控制",
+                "subCategoryName": "分合闸",
+                "param1Type": "2",
+                "param1Desc": "111",
+                "param2Type": "1",
+                "param2Desc": "111",
+                "nodeId": 301942,
+                "nodeDetail": "",
+                "bindRole": 101,
+                "delaySkip": 0,
+                "loseItem": 1,
+                "virtualOperation": 0,
+                "nodeTrigger": {
+                    "triggerMode": 0,
+                    "triggerDelay": 0
+                },
+                "nodeID": 301942,
+                "operationNode": {
+                    "templateID": 1002,
+                    "categoryName": "电力设备控制",
+                    "subCategoryName": "分合闸",
+                    "param1Type": "2",
+                    "param1Desc": "111",
+                    "param2Type": "1",
+                    "param2Desc": "111",
+                    "score": 0,
+                    "deduction": 0
+                }
+            },
+            "childNode": {
+                "nodeId": 221487,
+                "nodeName": "语音交互",
+                "nodeType": "voice",
+                "nodeData": {
+                    "name": "222",
+                    "role": 103,
+                    "templateID": 3003,
+                    "categoryName": "目标分类",
+                    "subCategoryName": "就地人员",
+                    "voiceContent": "2222",
+                    "nodeId": 221487,
+                    "nodeDetail": "",
+                    "bindRole": 102,
+                    "delaySkip": 0,
+                    "loseItem": 1,
+                    "virtualOperation": 0,
+                    "nodeTrigger": {
+                        "triggerMode": 0,
+                        "triggerDelay": 0
+                    },
+                    "nodeID": 221487,
+                    "voiceNode": {
+                        "templateID": 3003,
+                        "categoryName": "目标分类",
+                        "subCategoryName": "就地人员",
+                        "voiceContent": "2222"
+                    }
+                },
+                "childNode": {
+                    "nodeId": "466193",
+                    "nodeName": "故障触发",
+                    "nodeType": "fault",
+                    "nodeData": {
+                        "name": "222",
+                        "role": 102,
+                        "templateID": 2002,
+                        "categoryName": "设备故障",
+                        "subCategoryName": "设备类型1",
+                        "nodeId": 466193,
+                        "nodeDetail": "",
+                        "bindRole": 104,
+                        "delaySkip": 0,
+                        "loseItem": 1,
+                        "virtualOperation": 0,
+                        "nodeTrigger": {
+                            "triggerMode": 0,
+                            "triggerDelay": 0
+                        },
+                        "nodeID": 466193,
+                        "faultNode": {
+                            "templateID": 2002,
+                            "categoryName": "设备故障",
+                            "subCategoryName": "设备类型1"
+                        }
+                    }
+                }
+            }
+        }
+    }
+}