波比 месяцев назад: 11
Родитель
Сommit
c569f47f12

+ 0 - 6
Tech/controllers/default.go

@@ -15,9 +15,3 @@ func (c *MainController) Get() {
 	c.TplName = "index.tpl"
 	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)
-}

Разница между файлами не показана из-за своего большого размера
+ 144 - 1
Tech/controllers/test.json


Разница между файлами не показана из-за своего большого размера
+ 1147 - 0
Tech/controllers/电子考评.go


+ 524 - 125
Tech/controllers/电调.go

@@ -7,9 +7,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
-	"math/rand"
 	"net/http"
 	"net/http"
-	"os"
 	"time"
 	"time"
 
 
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/beego/beego/v2/client/orm"
@@ -88,9 +86,9 @@ func updateElectricalData() {
 				ViewID    int `json:"ViewID"`
 				ViewID    int `json:"ViewID"`
 			}
 			}
 			reqData := RequestData{
 			reqData := RequestData{
-				LineID:    firstModel.LineID,
-				StationID: firstModel.StationID,
-				ViewID:    firstModel.ViewID,
+				LineID: firstModel.LineID,
+				// StationID: firstModel.StationID,
+				// ViewID:    firstModel.ViewID,
 			}
 			}
 
 
 			// 将请求数据转换为JSON
 			// 将请求数据转换为JSON
@@ -136,7 +134,7 @@ func updateElectricalData() {
 					if err := json.Unmarshal(equipBytes, &equipments); err == nil {
 					if err := json.Unmarshal(equipBytes, &equipments); err == nil {
 						// 更新总包设备数据 (在更新时加锁)
 						// 更新总包设备数据 (在更新时加锁)
 						manager.UpdateBatchData(equipments)
 						manager.UpdateBatchData(equipments)
-						fmt.Printf("成功更新线路%d车站%d视图%d的电调模型数据\n", firstModel.LineID, firstModel.StationID, firstModel.ViewID)
+						fmt.Printf("成功更新线路%d的电调模型数据\n", firstModel.LineID)
 					} else {
 					} else {
 						fmt.Printf("解析设备列表失败: %v\n", err)
 						fmt.Printf("解析设备列表失败: %v\n", err)
 					}
 					}
@@ -150,8 +148,8 @@ type EDispatchController struct {
 	beego.Controller
 	beego.Controller
 }
 }
 
 
-// /courserun/eqpmtstatus 更新电调设备状态
-func (c *EDispatchController) Eqpmtstatus() {
+// /courserun/eqpmtvalue 更新电调设备状态
+func (c *EDispatchController) Eqpmtvalue() {
 	var req models.DiandiaoModel
 	var req models.DiandiaoModel
 
 
 	requestBody := c.Ctx.Input.RequestBody
 	requestBody := c.Ctx.Input.RequestBody
@@ -299,7 +297,6 @@ func (c *EDispatchController) Addctrllog() {
 	c.ServeJSON()
 	c.ServeJSON()
 }
 }
 
 
-// /serverCtrl/subsysstatus 获取子系统状态
 func (c *EDispatchController) SubSysStatus() {
 func (c *EDispatchController) SubSysStatus() {
 	// 从配置文件读取电调服务IP和端口
 	// 从配置文件读取电调服务IP和端口
 	electricalIP, err := beego.AppConfig.String("ElectricalIP")
 	electricalIP, err := beego.AppConfig.String("ElectricalIP")
@@ -325,8 +322,26 @@ func (c *EDispatchController) SubSysStatus() {
 	// 构造电调服务地址
 	// 构造电调服务地址
 	electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/SubSysStatus", electricalIP, electricalPort)
 	electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/SubSysStatus", electricalIP, electricalPort)
 
 
-	// 调用电调服务获取子系统状态接口
-	resp, err := http.Get(electricalAddr)
+	// 构造请求体,使用空的JSON对象
+	reqBody := "{}"
+
+	// 创建带适当头部的请求
+	req, err := http.NewRequest("POST", electricalAddr, bytes.NewBufferString(reqBody))
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "创建请求失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 设置Content-Type头部
+	req.Header.Set("Content-Type", "application/json")
+
+	// 创建HTTP客户端并发送请求
+	client := &http.Client{}
+	resp, err := client.Do(req)
 	if err != nil {
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
@@ -359,171 +374,320 @@ func (c *EDispatchController) SubSysStatus() {
 		return
 		return
 	}
 	}
 
 
-	// 尝试解析JSON响应
-	var result interface{}
+	// 尝试解析电调服务返回的JSON
+	var result map[string]interface{}
 	if err := json.Unmarshal(bodyBytes, &result); err != nil {
 	if err := json.Unmarshal(bodyBytes, &result); err != nil {
-		// 如果不是JSON格式,作为字符串返回
-		c.Data["json"] = map[string]interface{}{
-			"code": 200,
-			"msg":  "获取子系统状态成功",
-			"data": string(bodyBytes),
-		}
-	} else {
-		// 如果是JSON格式,直接返回解析结果
-		c.Data["json"] = map[string]interface{}{
-			"code": 200,
-			"msg":  "获取子系统状态成功",
-			"data": result,
-		}
+		// 如果解析失败,返回原始内容
+		c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+		c.Ctx.Output.Body(bodyBytes)
+		return
 	}
 	}
 
 
+	// 如果解析成功,直接返回JSON结果
+	c.Data["json"] = result
 	c.ServeJSON()
 	c.ServeJSON()
 }
 }
 func (c *EDispatchController) UpdateTestStatus() {
 func (c *EDispatchController) UpdateTestStatus() {
 
 
 }
 }
 
 
+// // /serverCtrl/alleqpmtlist 获取所有设备列表
+// func (c *EDispatchController) AllEqpmtList() {
+// 	// 定义与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 获取所有设备列表
 // /serverCtrl/alleqpmtlist 获取所有设备列表
 func (c *EDispatchController) AllEqpmtList() {
 func (c *EDispatchController) AllEqpmtList() {
-	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
-	// 定义与testStatus.json文件匹配的结构体
-	type jsonData struct {
+	// 转换缓存数据为指定格式
+	type EquipmentData struct {
 		DataID   string `json:"dataId"`
 		DataID   string `json:"dataId"`
 		DataName string `json:"dataName"`
 		DataName string `json:"dataName"`
 		Value    string `json:"value"`
 		Value    string `json:"value"`
 		ID       string `json:"id"`
 		ID       string `json:"id"`
 	}
 	}
 
 
-	// 读取testStatus.json文件
-	filePath := "static/testStatus.json"
-	data, err := os.ReadFile(filePath)
+	// 从配置文件读取电调服务IP和端口
+	electricalIP, err := beego.AppConfig.String("ElectricalIP")
 	if err != nil {
 	if err != nil {
-		c.Ctx.Output.SetStatus(500)
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
-			"msg":  "读取文件失败: " + err.Error(),
+			"msg":  "读取电调服务IP配置失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	// 解析JSON数据
-	var jsonDataList []jsonData
-	err = json.Unmarshal(data, &jsonDataList)
+	electricalPort, err := beego.AppConfig.Int("ElectricalPort")
 	if err != nil {
 	if err != nil {
-		c.Ctx.Output.SetStatus(500)
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
-			"msg":  "解析JSON失败: " + err.Error(),
+			"msg":  "读取电调服务端口配置失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	// 转换为EquipmentData结构体
-	type EquipmentData struct {
-		DataID   string `json:"dataId"`
-		DataName string `json:"dataName"`
-		Value    string `json:"value"`
-		ID       string `json:"id"`
+	// 构造电调服务地址
+	electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/AllEqpmtList", electricalIP, electricalPort)
+
+	// 获取最新的课程运行记录以获取线路号
+	o := orm.NewOrm()
+	var latestCourse models.CourseRunLog
+	err = o.QueryTable(new(models.CourseRunLog)).
+		OrderBy("-RunLogID").
+		One(&latestCourse)
+
+	if err != nil && err != orm.ErrNoRows {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "查询最新课程运行记录失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
 	}
 	}
-	//动态生成值 1-3改变
 
 
-	// 初始化随机数种子
-	rand.Seed(time.Now().UnixNano())
+	// 如果没有找到运行记录,默认线路号为0
+	lineID := 0
+	if err != orm.ErrNoRows {
+		// 根据运行课程ID查询课程信息以获取线路号
+		var courseInfo models.CourseInfo
+		err = o.QueryTable(new(models.CourseInfo)).
+			Filter("CourseID", latestCourse.RunCourseID).
+			One(&courseInfo)
 
 
-	// 生成1-3之间的随机数
-	nValue := rand.Intn(3) + 1
+		if err != nil && err != orm.ErrNoRows {
+			c.Data["json"] = map[string]interface{}{
+				"code": 500,
+				"msg":  "查询课程信息失败: " + err.Error(),
+			}
+			c.ServeJSON()
+			return
+		}
 
 
-	var equipmentDataList []EquipmentData
-	for _, item := range jsonDataList {
-		equipment := EquipmentData{
-			DataID:   item.DataID,
-			DataName: item.DataName,
-			Value:    fmt.Sprintf("%d", nValue),
-			ID:       item.ID,
+		if err != orm.ErrNoRows {
+			lineID = courseInfo.LineNo
 		}
 		}
-		equipmentDataList = append(equipmentDataList, equipment)
 	}
 	}
 
 
-	// 返回结果
-	c.Data["json"] = equipmentDataList
-	c.ServeJSON()
+	// 生成请求key
+	model := models.DiandiaoModel{
+		LineID: lineID,
+	}
+	key := model.GenerateModelKey()
 
 
-}
+	// 获取 ElectricModelManager 单例实例
+	manager := models.GetInstance()
 
 
-// /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"`
+	// 检查缓存中是否存在对应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.EqpmtStrID,
+					ID:       model.EqpmtStrID,
+					DataName: model.EqpmtStdName,
+				}
+
+				switch model.CMDType {
+				case 0: //设备状态
+					equip.Value = fmt.Sprintf("%d", model.EqpmtStatus)
+				case 1: //设备数据控制
+					equip.Value = fmt.Sprintf("%d", model.FValue)
+				}
+				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"`
+		StationID int `json:"StationID"`
+		ViewID    int `json:"ViewID"`
+	}
+	reqData := RequestData{
+		LineID:    lineID,
+		StationID: 0,
+		ViewID:    0,
 	}
 	}
 
 
-	// 读取testStatus.json文件
-	filePath := "static/testStatus.json"
-	data, err := os.ReadFile(filePath)
+	// 将请求数据转换为JSON
+	reqBody, err := json.Marshal(reqData)
 	if err != nil {
 	if err != nil {
-		c.Ctx.Output.SetStatus(500)
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
-			"msg":  "读取文件失败: " + err.Error(),
+			"msg":  "构造请求数据失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	// 解析JSON数据
-	var jsonDataList []jsonData
-	err = json.Unmarshal(data, &jsonDataList)
+	// 调用电调服务获取所有设备列表接口,使用POST方法
+	resp, err := http.Post(electricalAddr, "application/json", bytes.NewBuffer(reqBody))
 	if err != nil {
 	if err != nil {
-		c.Ctx.Output.SetStatus(500)
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
-			"msg":  "解析JSON失败: " + err.Error(),
+			"msg":  "调用电调服务获取所有设备列表接口失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
+	defer resp.Body.Close()
 
 
-	// 转换为EquipmentData结构体
-	type EquipmentData struct {
-		DataID   string `json:"dataId"`
-		DataName string `json:"dataName"`
-		Value    string `json:"value"`
-		ID       string `json:"id"`
+	// 检查响应状态
+	if resp.StatusCode != http.StatusOK {
+		bodyBytes, _ := io.ReadAll(resp.Body)
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  fmt.Sprintf("电调服务返回异常状态码: %d,响应内容: %s", resp.StatusCode, string(bodyBytes)),
+		}
+		c.ServeJSON()
+		return
 	}
 	}
-	//动态生成值 1-3改变
 
 
-	// 初始化随机数种子
-	rand.Seed(time.Now().UnixNano())
+	// 读取并解析响应体
+	bodyBytes, err := io.ReadAll(resp.Body)
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务响应失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
 
 
-	// 生成1-3之间的随机数
-	nValue := rand.Intn(3) + 1
+	// 尝试解析JSON响应
+	var result map[string]interface{}
+	if err := json.Unmarshal(bodyBytes, &result); err != nil {
+		// 如果不是JSON格式,作为字符串返回
+		c.Data["json"] = map[string]interface{}{
+			"code": 200,
+			"msg":  "获取所有设备列表成功",
+			"data": string(bodyBytes),
+		}
+	} else {
+		// 如果是JSON格式,检查是否有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)
+				}
+			}
+
+			var equipmentsData []EquipmentData
+			for _, model := range equipments {
+				equip := EquipmentData{
+					DataID:   model.EqpmtStrID,
+					ID:       model.EqpmtStrID,
+					DataName: model.EqpmtStdName,
+				}
+
+				if model.CMDType == 0 { //设备状态
+					equip.Value = fmt.Sprintf("%d", model.EqpmtStatus)
+				} else if model.CMDType == 1 { //设备数据控制
+					equip.Value = fmt.Sprintf("%d", model.FValue)
+				}
+				equipmentsData = append(equipmentsData, equip)
+			}
 
 
-	var equipmentDataList []EquipmentData
-	for _, item := range jsonDataList {
-		equipment := EquipmentData{
-			DataID:   item.DataID,
-			DataName: item.DataName,
-			Value:    fmt.Sprintf("%d", nValue),
-			ID:       item.ID,
+			// 返回响应
+			c.Data["json"] = map[string]interface{}{
+				"code": 200,
+				"msg":  "获取所有设备列表成功",
+				"data": equipmentsData,
+			}
+		} else {
+			// 如果没有data字段,返回整个响应
+			c.Data["json"] = map[string]interface{}{
+				"code": 500,
+				"msg":  "获取所有设备列表失败",
+			}
 		}
 		}
-		equipmentDataList = append(equipmentDataList, equipment)
 	}
 	}
 
 
-	// 返回结果
-	c.Data["json"] = equipmentDataList
 	c.ServeJSON()
 	c.ServeJSON()
-
 }
 }
 
 
-// /serverCtrl/alleqpmtlist 获取所有设备列表
-func (c *EDispatchController) AllEqpmtList_bak() {
-	c.Ctx.Output.Header("Access-Control-Allow-Origin", "*")
+// /serverCtrl/alleqpmtlist2 获取所有设备列表  测试使用
+func (c *EDispatchController) AllEqpmtList2() {
 	// 转换缓存数据为指定格式
 	// 转换缓存数据为指定格式
 	type EquipmentData struct {
 	type EquipmentData struct {
 		DataID   string `json:"dataId"`
 		DataID   string `json:"dataId"`
@@ -597,9 +761,7 @@ func (c *EDispatchController) AllEqpmtList_bak() {
 
 
 	// 生成请求key
 	// 生成请求key
 	model := models.DiandiaoModel{
 	model := models.DiandiaoModel{
-		LineID:    lineID,
-		StationID: 0,
-		ViewID:    0,
+		LineID: lineID,
 	}
 	}
 	key := model.GenerateModelKey()
 	key := model.GenerateModelKey()
 
 
@@ -614,10 +776,16 @@ func (c *EDispatchController) AllEqpmtList_bak() {
 			var equipmentsData []EquipmentData
 			var equipmentsData []EquipmentData
 			for _, model := range viewMapModel.Models {
 			for _, model := range viewMapModel.Models {
 				equip := EquipmentData{
 				equip := EquipmentData{
-					DataID:   model.EqpmtID,
-					ID:       model.EqpmtID,
-					Value:    fmt.Sprintf("%d", model.Status),
-					DataName: model.StatusName,
+					DataID:   model.EqpmtStrID,
+					ID:       model.EqpmtStrID,
+					DataName: model.EqpmtStdName,
+				}
+
+				switch model.CMDType {
+				case 0: //设备状态
+					equip.Value = fmt.Sprintf("%d", model.EqpmtStatus)
+				case 1: //设备数据控制
+					equip.Value = fmt.Sprintf("%d", model.FValue)
 				}
 				}
 				equipmentsData = append(equipmentsData, equip)
 				equipmentsData = append(equipmentsData, equip)
 			}
 			}
@@ -712,14 +880,19 @@ func (c *EDispatchController) AllEqpmtList_bak() {
 			}
 			}
 
 
 			var equipmentsData []EquipmentData
 			var equipmentsData []EquipmentData
-			for _, equip := range equipments {
-				equipmentData := EquipmentData{
-					DataID:   equip.EqpmtID,
-					DataName: equip.StatusName,
-					Value:    fmt.Sprintf("%d", equip.Status),
-					ID:       equip.EqpmtID,
+			for _, model := range equipments {
+				equip := EquipmentData{
+					DataID:   model.EqpmtStrID,
+					ID:       model.EqpmtStrID,
+					DataName: model.EqpmtStdName,
+				}
+
+				if model.CMDType == 0 { //设备状态
+					equip.Value = fmt.Sprintf("%d", model.EqpmtStatus)
+				} else if model.CMDType == 1 { //设备数据控制
+					equip.Value = fmt.Sprintf("%d", model.FValue)
 				}
 				}
-				equipmentsData = append(equipmentsData, equipmentData)
+				equipmentsData = append(equipmentsData, equip)
 			}
 			}
 
 
 			// 返回响应
 			// 返回响应
@@ -740,9 +913,235 @@ func (c *EDispatchController) AllEqpmtList_bak() {
 	c.ServeJSON()
 	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)
+// /serverctrl/seteqpmtoper 设置电调设备操作
+func (c *EDispatchController) Seteqpmtoper() {
+	// 定义接收的请求数据结构
+	var req struct {
+		EqpmtStrID  string `json:"EqpmtStrID"`
+		LineID      int    `json:"LineID"`
+		CMDType     int    `json:"CMDType"`
+		EqpmtStatus int    `json:"EqpmtStatus"`
+		FValue      int    `json:"fValue"`
+	}
+
+	// 解析请求体中的JSON数据
+	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
+	}
+
+	// 构造转发给电调服务器的请求数据
+	forwardReq := struct {
+		EqpmtStrID   string `json:"EqpmtStrID"`
+		LineID       int    `json:"LineID"`
+		EqpmtStdName string `json:"EqpmtStdName"`
+		CMDType      int    `json:"CMDType"`
+		EqpmtStatus  int    `json:"EqpmtStatus"`
+		CtrlType     int    `json:"CtrlType"`
+		OpeMark      int    `json:"OpeMark"`
+		FValue       int    `json:"fValue"`
+		NValueType   int    `json:"nValueType"`
+		IsReset      int    `json:"IsReset"`
+	}{
+		EqpmtStrID:   req.EqpmtStrID,
+		LineID:       req.LineID,
+		EqpmtStdName: "", // 默认空值
+		CMDType:      req.CMDType,
+		EqpmtStatus:  req.EqpmtStatus,
+		CtrlType:     0, // 默认值
+		OpeMark:      0, // 默认值
+		FValue:       req.FValue,
+		NValueType:   0, // 默认值
+		IsReset:      0, // 默认值
+	}
+
+	// 将构造好的请求数据序列化为JSON
+	forwardReqBody, err := json.Marshal(forwardReq)
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "构造转发请求数据失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 从配置文件读取电调服务IP和端口
+	electricalIP, err := beego.AppConfig.String("ElectricalIP")
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务IP配置失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	electricalPort, err := beego.AppConfig.Int("ElectricalPort")
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务端口配置失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 构造电调服务地址
+	electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/SetEqpmtOper", electricalIP, electricalPort)
+
+	// 将请求数据转发到电调服务器
+	resp, err := http.Post(electricalAddr, "application/json", bytes.NewBuffer(forwardReqBody))
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "转发请求到电调服务器失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+	defer resp.Body.Close()
+
+	fmt.Println("Seteqpmtoper 发送 JSON:", string(forwardReqBody))
+
+	// 读取响应体以便打印,然后将其重新放回供后续处理
+	respBodyBytes, err := io.ReadAll(resp.Body)
+	if err != nil {
+		fmt.Printf("Seteqpmtoper: 读取响应用于打印失败: %v\n", err)
+	} else {
+		fmt.Println("Seteqpmtoper 接收 JSON:", string(respBodyBytes))
+		// 由于后续代码还会读取 resp.Body,这里把数据重新放回
+		resp.Body = io.NopCloser(bytes.NewBuffer(respBodyBytes))
+	}
+
+	// 读取响应体
+	bodyBytes, err := io.ReadAll(resp.Body)
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务响应失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 检查响应状态
+	if resp.StatusCode != http.StatusOK {
+		c.Data["json"] = map[string]interface{}{
+			"code": resp.StatusCode,
+			"msg":  fmt.Sprintf("电调服务返回异常状态码: %d,响应内容: %s", resp.StatusCode, string(bodyBytes)),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 尝试解析响应为JSON
+	var result map[string]interface{}
+	if err := json.Unmarshal(bodyBytes, &result); err != nil {
+		// 如果不是JSON格式,原样返回
+		c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+		c.Ctx.Output.Body(bodyBytes)
+		return
+	}
+
+	// 返回电调服务器的响应
+	c.Data["json"] = result
+	c.ServeJSON()
+}
+
+// /serverctrl/seteqpmtfault 设置设备故障
+func (c *EDispatchController) Seteqpmtfault() {
+	// 定义接收的请求数据结构
+	var req struct {
+		EqpmtStrID string `json:"EqpmtStrID"`
+		LineID     int    `json:"LineID"`
+		EventType  int    `json:"EventType"`
+		EventId    int    `json:"EventId"`
+	}
+
+	// 解析请求体中的JSON数据
+	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
+	}
+
+	// 从配置文件读取电调服务IP和端口
+	electricalIP, err := beego.AppConfig.String("ElectricalIP")
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务IP配置失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	electricalPort, err := beego.AppConfig.Int("ElectricalPort")
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务端口配置失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 构造电调服务地址
+	electricalAddr := fmt.Sprintf("http://%s:%d/ServerCtrl/SetEqpmtFault", electricalIP, electricalPort)
+
+	// 将请求数据转发到电调服务器
+	resp, err := http.Post(electricalAddr, "application/json", bytes.NewBuffer(c.Ctx.Input.RequestBody))
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "转发请求到电调服务器失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+	defer resp.Body.Close()
+
+	// 读取响应体
+	bodyBytes, err := io.ReadAll(resp.Body)
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "读取电调服务响应失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 检查响应状态
+	if resp.StatusCode != http.StatusOK {
+		c.Data["json"] = map[string]interface{}{
+			"code": resp.StatusCode,
+			"msg":  fmt.Sprintf("电调服务返回异常状态码: %d,响应内容: %s", resp.StatusCode, string(bodyBytes)),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 尝试解析响应为JSON
+	var result map[string]interface{}
+	if err := json.Unmarshal(bodyBytes, &result); err != nil {
+		// 如果不是JSON格式,原样返回
+		c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+		c.Ctx.Output.Body(bodyBytes)
+		return
+	}
+
+	// 返回电调服务器的响应
+	c.Data["json"] = result
+	c.ServeJSON()
 }
 }

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

@@ -68,7 +68,7 @@ func ClearCourse(courseId int) (bool, string) {
 	}
 	}
 
 
 	// 清除CourseEvaList数据
 	// 清除CourseEvaList数据
-	_, err = o.Raw("DELETE FROM CourseEvaList WHERE 课程ID = ?", courseId).Exec()
+	_, err = o.Raw("DELETE FROM CourseEvaList WHERE 课程ID = ? and 评价映射ID >0", courseId).Exec()
 	if err != nil {
 	if err != nil {
 		return false, fmt.Sprintf("清除CourseEvaList数据失败: %v", err)
 		return false, fmt.Sprintf("清除CourseEvaList数据失败: %v", err)
 	}
 	}
@@ -225,7 +225,7 @@ func SaveCourseActionNode(classID int, parentID int, node *models.Node) (bool, e
 			CourseID:      classID,
 			CourseID:      classID,
 			SeqNo:         maxSeqNo + 1,
 			SeqNo:         maxSeqNo + 1,
 			EvaTargetRole: nodedata.BindRole,
 			EvaTargetRole: nodedata.BindRole,
-			EvaName:       node.NodeName,
+			EvaName:       nodedata.NodeName,
 			EvaMapID:      nodedata.NodeID, // 评价映射ID就是NodeID
 			EvaMapID:      nodedata.NodeID, // 评价映射ID就是NodeID
 			EvaType:       0,               // 0表示主观评价
 			EvaType:       0,               // 0表示主观评价
 			EvaSource:     0,               // 0表示来自流程图
 			EvaSource:     0,               // 0表示来自流程图

+ 89 - 236
Tech/controllers/评价.go

@@ -232,8 +232,8 @@ func (c *EvaController) Delete() {
 	o := orm.NewOrm()
 	o := orm.NewOrm()
 
 
 	// 先查询评价记录,判断是否来自流程图
 	// 先查询评价记录,判断是否来自流程图
-	eva := models.CourseEvaList{CourseID: req.CourseID, SeqNo: req.SeqNo}
-	err := o.Read(&eva, "CourseID", "SeqNo")
+	var eva models.CourseEvaList
+	err := o.Raw("SELECT * FROM CourseEvaList WHERE 课程ID = ? AND 序号 = ?", req.CourseID, req.SeqNo).QueryRow(&eva)
 	if err != nil {
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
@@ -254,7 +254,7 @@ func (c *EvaController) Delete() {
 	}
 	}
 
 
 	// 执行删除操作(仅对教员自定义的评价)
 	// 执行删除操作(仅对教员自定义的评价)
-	n, err := o.Delete(&models.CourseEvaList{CourseID: req.CourseID, SeqNo: req.SeqNo})
+	result, err := o.Raw("DELETE FROM CourseEvaList WHERE 课程ID = ? AND 序号 = ?", req.CourseID, req.SeqNo).Exec()
 	if err != nil {
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
@@ -264,6 +264,7 @@ func (c *EvaController) Delete() {
 		return
 		return
 	}
 	}
 
 
+	n, _ := result.RowsAffected()
 	if n == 0 {
 	if n == 0 {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 404,
 			"code": 404,
@@ -329,9 +330,26 @@ func (c *EvaController) Update() {
 		}
 		}
 	}
 	}
 
 
+	// 如果请求中没有提供相应字段,则使用现有记录中的值
+	if eva.EvaTargetRole == 0 {
+		eva.EvaTargetRole = existingEva.EvaTargetRole
+	}
+	if eva.EvaName == "" {
+		eva.EvaName = existingEva.EvaName
+	}
+	if eva.EvaMapID == 0 {
+		eva.EvaMapID = existingEva.EvaMapID
+	}
+
+	// 评价来源始终使用现有记录中的值(保留原始来源)
+	eva.EvaSource = existingEva.EvaSource
+	if eva.DisqualificationItem == 0 {
+		eva.DisqualificationItem = existingEva.DisqualificationItem
+	}
+
 	// 使用原生SQL更新记录
 	// 使用原生SQL更新记录
-	res, err := o.Raw("UPDATE CourseEvaList SET 评价目标角色=?, 评价名称=?, 评价映射ID=?, 评价类型=?, 评价赋分=?, 评价失分=?, 评价来源=? WHERE 课程ID=? AND 序号=?",
-		eva.EvaTargetRole, eva.EvaName, eva.EvaMapID, eva.EvaType, eva.EvaScore, eva.EvaDeduction, eva.EvaSource,
+	_, err = o.Raw("UPDATE CourseEvaList SET 评价目标角色=?, 评价名称=?, 评价映射ID=?, 评价类型=?, 评价赋分=?, 评价失分=?, 评价来源=?, 失格项=? WHERE 课程ID=? AND 序号=?",
+		eva.EvaTargetRole, eva.EvaName, eva.EvaMapID, eva.EvaType, eva.EvaScore, eva.EvaDeduction, eva.EvaSource, eva.DisqualificationItem,
 		eva.CourseID, eva.SeqNo).Exec()
 		eva.CourseID, eva.SeqNo).Exec()
 
 
 	if err != nil {
 	if err != nil {
@@ -343,17 +361,6 @@ func (c *EvaController) Update() {
 		return
 		return
 	}
 	}
 
 
-	// 获取影响的行数
-	num, _ := res.RowsAffected()
-	if num == 0 {
-		c.Data["json"] = map[string]interface{}{
-			"code": 500,
-			"msg":  "更新评价失败: 无记录被更新",
-		}
-		c.ServeJSON()
-		return
-	}
-
 	c.Data["json"] = map[string]interface{}{
 	c.Data["json"] = map[string]interface{}{
 		"code": 200,
 		"code": 200,
 		"msg":  "更新评价成功",
 		"msg":  "更新评价成功",
@@ -362,12 +369,12 @@ func (c *EvaController) Update() {
 	c.ServeJSON()
 	c.ServeJSON()
 }
 }
 
 
-// /eva/setscore 设置评价分数
-func (c *EvaController) SetScore() {
+// /eva/orderupdate 评价排序更新
+func (c *EvaController) Orderupdate() {
 	type Request struct {
 	type Request struct {
-		RunLogID  int     `json:"runLogID"`
-		RunOperID int     `json:"runOperID"`
-		OperScore float64 `json:"operScore"`
+		CourseID int `json:"courseID"`
+		SeqNo    int `json:"seqNo"`
+		SetOrder int `json:"setorder"`
 	}
 	}
 
 
 	var req Request
 	var req Request
@@ -384,7 +391,7 @@ func (c *EvaController) SetScore() {
 		return
 		return
 	}
 	}
 
 
-	if req.RunLogID == 0 || req.RunOperID == 0 {
+	if req.CourseID == 0 || req.SeqNo == 0 || req.SetOrder == 0 {
 		c.Ctx.Output.SetStatus(400)
 		c.Ctx.Output.SetStatus(400)
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 400,
 			"code": 400,
@@ -396,266 +403,112 @@ func (c *EvaController) SetScore() {
 
 
 	o := orm.NewOrm()
 	o := orm.NewOrm()
 
 
-	// 先检查记录是否存在
-	var count int64
-	err := o.Raw("SELECT COUNT(*) FROM CourseEvaLog WHERE 运行记录编号 = ? AND 运行操作ID = ?",
-		req.RunLogID, req.RunOperID).QueryRow(&count)
+	// 先尝试读取记录,判断是否存在
+	existingEva := models.CourseEvaList{CourseID: req.CourseID, SeqNo: req.SeqNo}
+	err := o.Read(&existingEva, "CourseID", "SeqNo")
 	if err != nil {
 	if err != nil {
-		c.Data["json"] = map[string]interface{}{
-			"code": 500,
-			"msg":  "查询评价记录失败: " + err.Error(),
+		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()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	if count == 0 {
+	// 获取该课程的所有评价记录,按序号排序
+	var evaList []models.CourseEvaList
+	_, err = o.QueryTable(new(models.CourseEvaList)).
+		Filter("CourseID", req.CourseID).
+		OrderBy("SeqNo").
+		All(&evaList)
+
+	if err != nil {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
-			"code": 404,
-			"msg":  "未找到对应的评价记录",
+			"code": 500,
+			"msg":  "查询评价列表失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	// 使用原生SQL更新操作得分字段
-	res, err := o.Raw("UPDATE CourseEvaLog SET 操作得分 = ? WHERE 运行记录编号 = ? AND 运行操作ID = ?",
-		req.OperScore, req.RunLogID, req.RunOperID).Exec()
-	if err != nil {
+	// 检查边界条件
+	if req.SetOrder == 1 && req.SeqNo <= 1 {
+		// 上移但已经在最顶部
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
-			"code": 500,
-			"msg":  "更新操作得分失败: " + err.Error(),
+			"code": 400,
+			"msg":  "无法执行上移操作,已到达顶部",
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	// 获取影响的行数
-	num, _ := res.RowsAffected()
-	if num == 0 {
+	if req.SetOrder == 2 && req.SeqNo >= len(evaList) {
+		// 下移但已经在最底部
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
-			"code": 500,
-			"msg":  "更新操作得分失败: 无记录被更新",
+			"code": 400,
+			"msg":  "无法执行下移操作,已到达底部",
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	c.Data["json"] = map[string]interface{}{
-		"code": 200,
-		"msg":  "设置操作得分成功",
-	}
-	c.ServeJSON()
-}
-
-// /eva/record/list 获取课程评价记录列表
-func (c *EvaController) EvaRecordList() {
-	type Request struct {
-		RunLogID int `json:"runLogID"`
-	}
-
-	var req Request
-	requestBody := c.Ctx.Input.RequestBody
-	println("Request Body:", string(requestBody))
-
-	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
-		}
+	// 确定要交换的两个序号
+	var targetSeqNo int
+	if req.SetOrder == 1 {
+		// 上移:与前一个序号交换
+		targetSeqNo = req.SeqNo - 1
+	} else {
+		// 下移:与后一个序号交换
+		targetSeqNo = req.SeqNo + 1
 	}
 	}
 
 
-	o := orm.NewOrm()
-
-	// 查询所有角色信息用于关联角色名称
-	var roleInfos []*models.RoleInfo
-	_, err := o.QueryTable(new(models.RoleInfo)).All(&roleInfos)
+	// 使用三步更新避免主键冲突
+	// 第一步:将目标序号临时设为0
+	_, err = o.Raw("UPDATE CourseEvaList SET 序号 = 0 WHERE 课程ID = ? AND 序号 = ?",
+		req.CourseID, targetSeqNo).Exec()
 	if err != nil {
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
-			"msg":  "查询角色信息失败: " + err.Error(),
+			"msg":  "更新序号失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		return
 	}
 	}
 
 
-	// 创建角色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
-
-	// 如果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)
-	}
-
+	// 第二步:将当前序号更新为目标序号
+	_, err = o.Raw("UPDATE CourseEvaList SET 序号 = ? WHERE 课程ID = ? AND 序号 = ?",
+		targetSeqNo, req.CourseID, req.SeqNo).Exec()
 	if err != nil {
 	if err != nil {
 		c.Data["json"] = map[string]interface{}{
 		c.Data["json"] = map[string]interface{}{
 			"code": 500,
 			"code": 500,
-			"msg":  "查询评价记录列表失败: " + err.Error(),
+			"msg":  "更新序号失败: " + err.Error(),
 		}
 		}
 		c.ServeJSON()
 		c.ServeJSON()
 		return
 		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,
+	// 第三步:将临时序号0更新为当前序号
+	_, err = o.Raw("UPDATE CourseEvaList SET 序号 = ? WHERE 课程ID = ? AND 序号 = 0",
+		req.SeqNo, req.CourseID).Exec()
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "更新序号失败: " + err.Error(),
 		}
 		}
+		c.ServeJSON()
+		return
 	}
 	}
 
 
 	c.Data["json"] = map[string]interface{}{
 	c.Data["json"] = map[string]interface{}{
-		"code":  200,
-		"count": count,
-		"msg":   "成功",
-		"data":  evaRecordsWithRoles,
+		"code": 200,
+		"msg":  "顺序调整成功",
 	}
 	}
 	c.ServeJSON()
 	c.ServeJSON()
 }
 }

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

@@ -406,6 +406,37 @@ func (c *CourseController) Delete() {
 	}
 	}
 
 
 	for _, courseID := range courseIds {
 	for _, courseID := range courseIds {
+		// 先删除相关的课程运行记录
+		_, err := o.Raw("DELETE FROM CourseRunLog WHERE 运行课程ID = ?", courseID).Exec()
+		if err != nil {
+			failedCourses = append(failedCourses, map[string]interface{}{
+				"courseId": courseID,
+				"reason":   "删除课程运行记录失败: " + err.Error(),
+			})
+			continue
+		}
+
+		// 删除课程运行操作日志记录
+		_, err = o.Raw("DELETE FROM CourseOperLog WHERE 运行课程ID = ?", courseID).Exec()
+		if err != nil {
+			failedCourses = append(failedCourses, map[string]interface{}{
+				"courseId": courseID,
+				"reason":   "删除课程操作日志失败: " + err.Error(),
+			})
+			continue
+		}
+
+		// 删除课程评价日志记录
+		_, err = o.Raw("DELETE FROM CourseEvaLog WHERE 运行课程ID = ?", courseID).Exec()
+		if err != nil {
+			failedCourses = append(failedCourses, map[string]interface{}{
+				"courseId": courseID,
+				"reason":   "删除课程评价日志失败: " + err.Error(),
+			})
+			continue
+		}
+
+		// 删除课程基本信息
 		nCount, err := o.Delete(&models.CourseInfo{CourseID: courseID})
 		nCount, err := o.Delete(&models.CourseInfo{CourseID: courseID})
 		if err != nil {
 		if err != nil {
 			failedCourses = append(failedCourses, map[string]interface{}{
 			failedCourses = append(failedCourses, map[string]interface{}{
@@ -422,7 +453,7 @@ func (c *CourseController) Delete() {
 			continue
 			continue
 		}
 		}
 
 
-		// 成功删除课程基本信息后,清理相关数据
+		// 成功删除课程基本信息后,清理相关节点数据
 		ClearCourse(courseID)
 		ClearCourse(courseID)
 		successCount++
 		successCount++
 	}
 	}

+ 331 - 71
Tech/controllers/课程运行.go

@@ -131,7 +131,7 @@ func (c *CourseRunController) CourseRun() {
 	}
 	}
 
 
 	// 通知电调开课
 	// 通知电调开课
-	isret, err := c.tellEStartCourse(req.CourseID, int(id))
+	isret, err := c.tellEStartCourse(req.CourseID, int(id), course.LineNo)
 	if !isret || err != nil {
 	if !isret || err != nil {
 		// 如果通知电调开课失败,删除刚刚创建的课程运行记录
 		// 如果通知电调开课失败,删除刚刚创建的课程运行记录
 		o.Delete(&newRunLog)
 		o.Delete(&newRunLog)
@@ -161,19 +161,22 @@ func (c *CourseRunController) CourseRun() {
 	// 为每个评价项创建评价日志记录
 	// 为每个评价项创建评价日志记录
 	for _, eva := range evaList {
 	for _, eva := range evaList {
 		evaLog := models.CourseEvaLog{
 		evaLog := models.CourseEvaLog{
-			RunLogID:    int(id), // 使用运行记录ID作为关联标识
-			RunCourseID: req.CourseID,
-			RunOperID:   eva.SeqNo,   // 使用评价序号作为操作ID
-			OperName:    eva.EvaName, // 使用评价名称作为操作名称
-			OperTime:    0,           // 初始化时间为0
-			OperScore:   0,           // 初始化得分为0
-			OperParam1:  "",          // 参数初始化为空字符串
-			OperParam2:  "",
-			OperParam3:  "",
-			OperParam4:  "",
-			OperParam5:  "",
+			RunLogID:             int(id), // 使用运行记录ID作为关联标识
+			RunCourseID:          req.CourseID,
+			RunOperID:            eva.SeqNo, // 使用评价序号作为操作ID
+			OperTime:             0,         // 初始化时间为0
+			OperScore:            0,         // 初始化得分为0
+			SeqNo:                eva.SeqNo,
+			EvaTargetRole:        eva.EvaTargetRole,
+			EvaName:              eva.EvaName,
+			EvaMapID:             eva.EvaMapID,
+			EvaType:              eva.EvaType,
+			EvaSource:            eva.EvaSource,
+			EvaScore:             eva.EvaScore,
+			EvaDeduction:         eva.EvaDeduction,
+			DisqualificationItem: eva.DisqualificationItem,
+			IsOperated:           0, // 节点是否操作 0 未操作 1 已操作
 		}
 		}
-
 		_, err = o.Insert(&evaLog)
 		_, err = o.Insert(&evaLog)
 		if err != nil {
 		if err != nil {
 			c.Data["json"] = map[string]interface{}{
 			c.Data["json"] = map[string]interface{}{
@@ -198,7 +201,7 @@ func (c *CourseRunController) CourseRun() {
 }
 }
 
 
 // / 通知电调服务课程开始
 // / 通知电调服务课程开始
-func (c *CourseRunController) tellEStartCourse(courseID int, runLogID int) (bool, error) {
+func (c *CourseRunController) tellEStartCourse(courseID int, runLogID int, lineNo int) (bool, error) {
 
 
 	// 从配置文件读取电调服务IP和端口
 	// 从配置文件读取电调服务IP和端口
 	electricalIP, err := beego.AppConfig.String("ElectricalIP")
 	electricalIP, err := beego.AppConfig.String("ElectricalIP")
@@ -228,12 +231,14 @@ func (c *CourseRunController) tellEStartCourse(courseID int, runLogID int) (bool
 	type CourseStartReq struct {
 	type CourseStartReq struct {
 		CourseID    int    `json:"CourseID"`
 		CourseID    int    `json:"CourseID"`
 		CourseRunID int    `json:"CourseRunID"`
 		CourseRunID int    `json:"CourseRunID"`
+		LineNo      int    `json:"LineNo"`
 		SubParam1   string `json:"subParam1"`
 		SubParam1   string `json:"subParam1"`
 		SubParam2   string `json:"subParam2"`
 		SubParam2   string `json:"subParam2"`
 	}
 	}
 	startReq := CourseStartReq{
 	startReq := CourseStartReq{
 		CourseID:    courseID,
 		CourseID:    courseID,
 		CourseRunID: runLogID,
 		CourseRunID: runLogID,
+		LineNo:      lineNo,
 		SubParam1:   "",
 		SubParam1:   "",
 		SubParam2:   "",
 		SubParam2:   "",
 	}
 	}
@@ -660,44 +665,71 @@ func (c *CourseRunController) CourseStatus() {
 	c.ServeJSON()
 	c.ServeJSON()
 }
 }
 
 
-// /runrecord/list 获取课程运行记录列表 查询课程运行时间
-func (c *CourseRunController) RunRecordList() {
+// /runrecord/listone 获取课程运行记录数据
+func (c *CourseRunController) RunRecordListOne() {
 	// 定义请求参数结构体
 	// 定义请求参数结构体
 	type Request struct {
 	type Request struct {
-		CourseName string `json:"courseName"`
-		TypeID     int    `json:"typeID"`
-		CourseID   int    `json:"courseID"`
-		LineNo     int    `json:"lineNo"`
-		Creator    string `json:"creator"`
+		RunLogID int `json:"runLogID"`
 	}
 	}
 
 
 	var req Request
 	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(),
+	if len(c.Ctx.Input.RequestBody) > 0 {
+		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
 		}
 		}
-		c.ServeJSON()
-		return
 	}
 	}
 
 
 	o := orm.NewOrm()
 	o := orm.NewOrm()
 
 
-	// 先查询所有运行记录
 	var runRecords []models.CourseRunLog
 	var runRecords []models.CourseRunLog
-	qs := o.QueryTable(new(models.CourseRunLog)).OrderBy("-RunLogID")
-	_, err := qs.All(&runRecords)
-	if err != nil {
-		c.Data["json"] = map[string]interface{}{
-			"code": 500,
-			"msg":  "查询课程运行记录失败: " + err.Error(),
+	var err error
+
+	// 如果RunLogID > 0,则查询对应运行记录ID的记录
+	// 如果RunLogID = 0 或者没有传参,则查询最新一条记录
+	if req.RunLogID > 0 {
+		// 查询指定RunLogID的运行记录
+		var record models.CourseRunLog
+		err = o.QueryTable(new(models.CourseRunLog)).Filter("RunLogID", req.RunLogID).One(&record)
+		if err != nil && err != orm.ErrNoRows {
+			c.Data["json"] = map[string]interface{}{
+				"code": 500,
+				"msg":  "查询课程运行记录失败: " + err.Error(),
+			}
+			c.ServeJSON()
+			return
+		}
+
+		// 如果找到了记录,则添加到数组中
+		if err != orm.ErrNoRows {
+			runRecords = append(runRecords, record)
+		}
+	} else {
+		// 查询最新一条运行记录
+		var latestRecord models.CourseRunLog
+		err = o.QueryTable(new(models.CourseRunLog)).OrderBy("-RunLogID").One(&latestRecord)
+		if err != nil && err != orm.ErrNoRows {
+			c.Data["json"] = map[string]interface{}{
+				"code": 500,
+				"msg":  "查询课程运行记录失败: " + err.Error(),
+			}
+			c.ServeJSON()
+			return
+		}
+
+		// 如果找到了记录,则添加到数组中
+		if err != orm.ErrNoRows {
+			runRecords = append(runRecords, latestRecord)
 		}
 		}
-		c.ServeJSON()
-		return
 	}
 	}
 
 
+	//判断课程是否结束,如果课程未结束,计算课程运行时间 CourseTime
 	// 构建结果
 	// 构建结果
 	type RunRecordDetail struct {
 	type RunRecordDetail struct {
 		RunLogID       int     `json:"runLogID"`
 		RunLogID       int     `json:"runLogID"`
@@ -706,8 +738,9 @@ func (c *CourseRunController) RunRecordList() {
 		RunDateTime    string  `json:"runDateTime"`
 		RunDateTime    string  `json:"runDateTime"`
 		CourseTime     int     `json:"courseTime"`
 		CourseTime     int     `json:"courseTime"`
 		CourseScore    float64 `json:"courseScore"`
 		CourseScore    float64 `json:"courseScore"`
-		PauseFlag      int     `json:"pauseFlag"`
+		PauseFlag      int     `json:"pauseFlag"` //1:已经暂停,1运行中,-1课程结束
 		PauseTotalTime int     `json:"pauseTotalTime"`
 		PauseTotalTime int     `json:"pauseTotalTime"`
+		RunStatus      int     `json:"runStatus"` // 0表示未运行,1表示正在运行,2表示暂停中
 	}
 	}
 
 
 	var results []RunRecordDetail
 	var results []RunRecordDetail
@@ -726,49 +759,214 @@ func (c *CourseRunController) RunRecordList() {
 			return
 			return
 		}
 		}
 
 
-		// 检查是否符合筛选条件
-		match := true
+		// 判断课程是否结束,如果课程未结束,计算课程运行时间 CourseTime
+		if record.PauseFlag != -1 {
+			// 课程未结束,重新计算运行时间
+			// 将字符串转换为时间
+			startTime, err := time.ParseInLocation("2006-01-02 15:04:05", record.RunDateTime, time.Local)
+			if err == nil {
+				// 计算从开始时间到当前时间的时间差(秒)
+				duration := time.Since(startTime).Seconds()
+				// 减去暂停的总时间得到实际运行时间
+				record.CourseTime = int(duration) - record.PauseTotalTime
+				if record.CourseTime < 0 {
+					record.CourseTime = 0
+				}
+			}
+		}
+
+		detail := RunRecordDetail{
+			RunLogID:       record.RunLogID,
+			RunCourseID:    record.RunCourseID,
+			RunCourseName:  record.RunCourseName,
+			RunDateTime:    record.RunDateTime,
+			CourseTime:     record.CourseTime,
+			CourseScore:    record.CourseScore,
+			PauseFlag:      record.PauseFlag,
+			PauseTotalTime: record.PauseTotalTime,
+			RunStatus: func() int {
+				// 根据PauseFlag确定运行状态
+				if record.PauseFlag == 1 {
+					return 2 // 暂停中(默认情况)
+				} else if record.PauseFlag == -1 {
+					return 0 // 课程结束(未运行)
+				} else {
+					return 1
+				}
+			}(),
+		}
+
+		results = append(results, detail)
+	}
+
+	c.Data["json"] = map[string]interface{}{
+		"code":  200,
+		"msg":   "查询成功",
+		"count": len(results),
+		"data":  results,
+	}
+	c.ServeJSON()
+}
+
+// /runrecord/list 获取课程运行记录数据列表
+func (c *CourseRunController) RunRecordList() {
+	// 定义请求参数结构体
+	type Request struct {
+		CourseName string `json:"courseName"`
+		TypeID     int    `json:"typeID"`
+		CourseID   int    `json:"courseID"`
+		LineNo     int    `json:"lineNo"`
+		Creator    string `json:"creator"`
+		StartTime  string `json:"startTime"`
+		EndTime    string `json:"endTime"`
+	}
 
 
-		// 如果有筛选条件,检查是否匹配
-		if req.CourseName != "" && (err == orm.ErrNoRows || !strings.Contains(courseInfo.CourseName, req.CourseName)) {
-			match = false
+	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
+	}
+
+	o := orm.NewOrm()
+
+	// 构建结果
+	type RunRecordDetail struct {
+		RunLogID       int     `json:"runLogID"`
+		RunCourseID    int     `json:"runCourseID"`
+		RunCourseName  string  `json:"runCourseName"`
+		RunDateTime    string  `json:"runDateTime"`
+		CourseTime     int     `json:"courseTime"`
+		CourseScore    float64 `json:"courseScore"`
+		PauseFlag      int     `json:"pauseFlag"`
+		PauseTotalTime int     `json:"pauseTotalTime"`
+		RunStatus      int     `json:"runStatus"` // 0表示未运行,1表示正在运行,2表示暂停中
+	}
+
+	var results []RunRecordDetail
+
+	// 使用原生SQL进行联合查询,提高查询效率
+	sql := `SELECT 
+				r.运行记录编号,
+				r.运行课程ID,
+				r.运行课程名称,
+				r.运行日期时间,
+				r.课程用时,
+				r.课程得分,
+				r.暂停标记,
+				r.暂停累计时长
+			FROM CourseRunLog r`
+
+	// 构建WHERE条件
+	var conditions []string
+	var args []interface{}
+
+	// 添加课程ID筛选条件
+	if req.CourseID != 0 {
+		conditions = append(conditions, "r.运行课程ID = ?")
+		args = append(args, req.CourseID)
+	}
+
+	// 添加时间范围筛选条件
+	if req.StartTime != "" && req.EndTime != "" {
+		conditions = append(conditions, "r.运行日期时间 >= ?")
+		args = append(args, req.StartTime)
+
+		conditions = append(conditions, "r.运行日期时间 <= ?")
+		args = append(args, req.EndTime)
+	}
+
+	// 如果有其他筛选条件,则需要JOIN CourseInfo表
+	needJoin := req.CourseName != "" || req.TypeID != 0 || req.LineNo != 0 || req.Creator != ""
+	if needJoin {
+		sql += " LEFT JOIN CourseInfo c ON r.运行课程ID = c.课程ID"
 
 
-		if req.TypeID != 0 && (err == orm.ErrNoRows || courseInfo.TypeID != req.TypeID) {
-			match = false
+		if req.CourseName != "" {
+			conditions = append(conditions, "c.课程名称 LIKE ?")
+			args = append(args, "%"+req.CourseName+"%")
 		}
 		}
 
 
-		if req.CourseID != 0 && record.RunCourseID != req.CourseID {
-			match = false
+		if req.TypeID != 0 {
+			conditions = append(conditions, "c.分类ID = ?")
+			args = append(args, req.TypeID)
 		}
 		}
 
 
-		if req.LineNo != 0 && (err == orm.ErrNoRows || courseInfo.LineNo != req.LineNo) {
-			match = false
+		if req.LineNo != 0 {
+			conditions = append(conditions, "c.线路号 = ?")
+			args = append(args, req.LineNo)
 		}
 		}
 
 
-		if req.Creator != "" && (err == orm.ErrNoRows || !strings.Contains(courseInfo.Creator, req.Creator)) {
-			match = false
+		if req.Creator != "" {
+			conditions = append(conditions, "c.创建人 LIKE ?")
+			args = append(args, "%"+req.Creator+"%")
 		}
 		}
+	}
 
 
-		// 如果匹配筛选条件,则添加到结果中
-		if match {
-			detail := RunRecordDetail{
-				RunLogID:       record.RunLogID,
-				RunCourseID:    record.RunCourseID,
-				RunCourseName:  record.RunCourseName,
-				RunDateTime:    record.RunDateTime,
-				CourseTime:     record.CourseTime,
-				CourseScore:    record.CourseScore,
-				PauseFlag:      record.PauseFlag,
-				PauseTotalTime: record.PauseTotalTime,
-			}
+	// 添加WHERE条件到SQL
+	if len(conditions) > 0 {
+		sql += " WHERE " + strings.Join(conditions, " AND ")
+	}
 
 
-			if err != orm.ErrNoRows {
+	// 添加排序
+	sql += " ORDER BY r.运行记录编号 DESC"
 
 
+	// 执行查询
+	var runRecords []models.CourseRunLog
+	_, err := o.Raw(sql, args...).QueryRows(&runRecords)
+	if err != nil {
+		c.Data["json"] = map[string]interface{}{
+			"code": 500,
+			"msg":  "查询课程运行记录失败: " + err.Error(),
+		}
+		c.ServeJSON()
+		return
+	}
+
+	// 转换为结果格式
+	for _, record := range runRecords {
+		// 判断课程是否结束,如果课程未结束,计算课程运行时间 CourseTime
+		courseTime := record.CourseTime
+		if record.PauseFlag != -1 {
+			// 课程未结束,重新计算运行时间
+			// 将字符串转换为时间
+			startTime, err := time.ParseInLocation("2006-01-02 15:04:05", record.RunDateTime, time.Local)
+			if err == nil {
+				// 计算从开始时间到当前时间的时间差(秒)
+				duration := time.Since(startTime).Seconds()
+				// 减去暂停的总时间得到实际运行时间
+				calculatedTime := int(duration) - record.PauseTotalTime
+				if calculatedTime > 0 {
+					courseTime = calculatedTime
+				}
 			}
 			}
+		}
 
 
-			results = append(results, detail)
+		detail := RunRecordDetail{
+			RunLogID:       record.RunLogID,
+			RunCourseID:    record.RunCourseID,
+			RunCourseName:  record.RunCourseName,
+			RunDateTime:    record.RunDateTime,
+			CourseTime:     courseTime,
+			CourseScore:    record.CourseScore,
+			PauseFlag:      record.PauseFlag,
+			PauseTotalTime: record.PauseTotalTime,
+			RunStatus: func() int {
+				// 根据PauseFlag确定运行状态
+				if record.PauseFlag == 1 {
+					return 2 // 暂停中(默认情况)
+				} else if record.PauseFlag == -1 {
+					return 0 // 课程结束(未运行)
+				} else {
+					return 1
+				}
+			}(),
 		}
 		}
+		results = append(results, detail)
 	}
 	}
 
 
 	c.Data["json"] = map[string]interface{}{
 	c.Data["json"] = map[string]interface{}{
@@ -842,14 +1040,42 @@ func (c *CourseRunController) RunRecordDelete() {
 
 
 // /oper/runrecord/list 获取操作运行记录列表
 // /oper/runrecord/list 获取操作运行记录列表
 func (c *CourseRunController) OperRunRecordList() {
 func (c *CourseRunController) OperRunRecordList() {
+	// 定义请求参数结构体
+	type Request struct {
+		RunLogID int `json:"runLogID"`
+	}
+
+	// 解析请求参数
+	var req Request
+	if len(c.Ctx.Input.RequestBody) > 0 {
+		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
+		}
+	}
+
 	// 获取数据库连接
 	// 获取数据库连接
 	o := orm.NewOrm()
 	o := orm.NewOrm()
 
 
-	// 查找最近的课程运行记录(按RunLogID倒序排列,取第一个)
+	// 查找课程运行记录:如果RunLogID > 0,则查询对应的记录,否则查询最近一条记录
 	var latestCourseRun models.CourseRunLog
 	var latestCourseRun models.CourseRunLog
-	err := o.QueryTable(new(models.CourseRunLog)).
-		OrderBy("-RunLogID").
-		One(&latestCourseRun)
+	var err error
+
+	if req.RunLogID > 0 {
+		// 查询指定RunLogID的课程运行记录
+		err = o.QueryTable(new(models.CourseRunLog)).
+			Filter("RunLogID", req.RunLogID).
+			One(&latestCourseRun)
+	} else {
+		// 查找最近的课程运行记录(按RunLogID倒序排列,取第一个)
+		err = o.QueryTable(new(models.CourseRunLog)).
+			OrderBy("-RunLogID").
+			One(&latestCourseRun)
+	}
 
 
 	if err != nil {
 	if err != nil {
 		if err == orm.ErrNoRows {
 		if err == orm.ErrNoRows {
@@ -883,11 +1109,45 @@ func (c *CourseRunController) OperRunRecordList() {
 		return
 		return
 	}
 	}
 
 
-	// 返回结果,只返回操作日志列表
+	// 为每个操作日志添加课程名称
+	type OperLogWithCourseName struct {
+		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"`
+		CourseName  string  `json:"courseName"`
+	}
+
+	operLogsWithCourseName := make([]OperLogWithCourseName, len(operLogs))
+	for i, log := range operLogs {
+		operLogsWithCourseName[i] = OperLogWithCourseName{
+			RunLogID:    log.RunLogID,
+			RunCourseID: log.RunCourseID,
+			RunOperID:   log.RunOperID,
+			OperName:    log.OperName,
+			OperTime:    log.OperTime,
+			OperScore:   log.OperScore,
+			OperParam1:  log.OperParam1,
+			OperParam2:  log.OperParam2,
+			OperParam3:  log.OperParam3,
+			OperParam4:  log.OperParam4,
+			OperParam5:  log.OperParam5,
+			CourseName:  latestCourseRun.RunCourseName,
+		}
+	}
+
+	// 返回结果,返回操作日志列表和课程名称
 	c.Data["json"] = map[string]interface{}{
 	c.Data["json"] = map[string]interface{}{
 		"code": 200,
 		"code": 200,
 		"msg":  "获取操作日志列表成功",
 		"msg":  "获取操作日志列表成功",
-		"data": operLogs,
+		"data": operLogsWithCourseName,
 	}
 	}
 	c.ServeJSON()
 	c.ServeJSON()
 }
 }

+ 3 - 1
Tech/go.mod

@@ -21,6 +21,7 @@ require (
 	github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
 	github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/jtolds/gls v4.20.0+incompatible // indirect
 	github.com/jtolds/gls v4.20.0+incompatible // indirect
+	github.com/jung-kurt/gofpdf v1.16.2
 	github.com/kr/text v0.2.0 // indirect
 	github.com/kr/text v0.2.0 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -38,4 +39,5 @@ require (
 	golang.org/x/text v0.7.0 // indirect
 	golang.org/x/text v0.7.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-)
+	github.com/pdfcpu/pdfcpu v0.8.0
+)

+ 10 - 0
Tech/go.sum

@@ -4,9 +4,11 @@ github.com/beego/beego/v2 v2.1.0 h1:Lk0FtQGvDQCx5V5yEu4XwDsIgt+QOlNjt5emUa3/ZmA=
 github.com/beego/beego/v2 v2.1.0/go.mod h1:6h36ISpaxNrrpJ27siTpXBG8d/Icjzsc7pU1bWpp0EE=
 github.com/beego/beego/v2 v2.1.0/go.mod h1:6h36ISpaxNrrpJ27siTpXBG8d/Icjzsc7pU1bWpp0EE=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
 github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
@@ -33,6 +35,9 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc=
+github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -41,6 +46,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -57,17 +64,20 @@ github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJf
 github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
 github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
 golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=

+ 26 - 21
Tech/models/教员模型.go

@@ -40,15 +40,16 @@ func (c *CourseInfo) TableName() string { return "CourseInfo" }
 
 
 // 3. CourseEvaList - 课程评价表
 // 3. CourseEvaList - 课程评价表
 type CourseEvaList struct {
 type CourseEvaList struct {
-	CourseID      int    `orm:"column(课程ID);pk" json:"courseID"`
-	SeqNo         int    `orm:"column(序号)" json:"seqNo"`
-	EvaTargetRole int    `orm:"column(评价目标角色)" json:"evaTargetRole"`
-	EvaName       string `orm:"column(评价名称);type(text)" json:"evaName"`
-	EvaMapID      int    `orm:"column(评价映射ID)" json:"evaMapID"`
-	EvaType       int    `orm:"column(评价类型)" json:"evaType"` // 0主观评价1客观评价
-	EvaScore      int    `orm:"column(评价赋分)" json:"evaScore"`
-	EvaDeduction  int    `orm:"column(评价失分)" json:"evaDeduction"`
-	EvaSource     int    `orm:"column(评价来源)" json:"evaSource"` // 0来自流程图,1.来自教员自定义
+	CourseID             int    `orm:"column(课程ID);pk" json:"courseID"`
+	SeqNo                int    `orm:"column(序号)" json:"seqNo"`
+	EvaTargetRole        int    `orm:"column(评价目标角色)" json:"evaTargetRole"`
+	EvaName              string `orm:"column(评价名称);type(text)" json:"evaName"`
+	EvaMapID             int    `orm:"column(评价映射ID)" json:"evaMapID"`
+	EvaType              int    `orm:"column(评价类型)" json:"evaType"` // 0主观评价1客观评价
+	EvaScore             int    `orm:"column(评价赋分)" json:"evaScore"`
+	EvaDeduction         int    `orm:"column(评价失分)" json:"evaDeduction"`
+	EvaSource            int    `orm:"column(评价来源)" json:"evaSource"`           // 0来自流程图,1.来自教员自定义
+	DisqualificationItem int    `orm:"column(失格项)" json:"disqualificationItem"` // 新增失格项字段 1是0否
 }
 }
 
 
 func (c *CourseEvaList) TableName() string { return "CourseEvaList" }
 func (c *CourseEvaList) TableName() string { return "CourseEvaList" }
@@ -208,7 +209,7 @@ type CourseRunLog struct {
 	RunDateTime   string  `orm:"column(运行日期时间);type(text)" json:"runDateTime"`
 	RunDateTime   string  `orm:"column(运行日期时间);type(text)" json:"runDateTime"`
 	CourseTime    int     `orm:"column(课程用时)" json:"courseTime"`
 	CourseTime    int     `orm:"column(课程用时)" json:"courseTime"`
 	CourseScore   float64 `orm:"column(课程得分)" json:"courseScore"`
 	CourseScore   float64 `orm:"column(课程得分)" json:"courseScore"`
-	//1:已经暂停,1运行中,-1课程结束
+	//1:已经暂停,0运行中,-1课程结束
 	PauseFlag      int `orm:"column(暂停标记)" json:"pauseFlag"`
 	PauseFlag      int `orm:"column(暂停标记)" json:"pauseFlag"`
 	PauseTotalTime int `orm:"column(暂停累计时长)" json:"pauseTotalTime"`
 	PauseTotalTime int `orm:"column(暂停累计时长)" json:"pauseTotalTime"`
 }
 }
@@ -234,17 +235,21 @@ func (c *CourseOperLog) TableName() string { return "CourseOperLog" }
 
 
 // 15. CourseEvaLog - 课程评价记录表
 // 15. CourseEvaLog - 课程评价记录表
 type CourseEvaLog struct {
 type CourseEvaLog struct {
-	RunLogID    int     `orm:"column(运行记录编号);pk;" json:"runLogID"`
-	RunCourseID int     `orm:"column(运行课程ID)" json:"runCourseID"`
-	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"`
-	OperParam1  string  `orm:"column(操作参数1);type(text)" json:"operParam1"`
-	OperParam2  string  `orm:"column(操作参数2);type(text)" json:"operParam2"`
-	OperParam3  string  `orm:"column(操作参数3);type(text)" json:"operParam3"`
-	OperParam4  string  `orm:"column(操作参数4);type(text)" json:"operParam4"`
-	OperParam5  string  `orm:"column(操作参数5);type(text)" json:"operParam5"`
+	RunLogID             int     `orm:"column(运行记录编号);pk;" json:"runLogID"`
+	RunCourseID          int     `orm:"column(运行课程ID)" json:"runCourseID"`
+	RunOperID            int     `orm:"column(运行操作ID);" json:"runOperID"` //暂时不用
+	OperTime             int     `orm:"column(操作时间)" json:"operTime"`
+	OperScore            float64 `orm:"column(操作得分)" json:"operScore"`
+	SeqNo                int     `orm:"column(序号)" json:"seqNo"`
+	EvaTargetRole        int     `orm:"column(评价目标角色)" json:"evaTargetRole"`
+	EvaName              string  `orm:"column(评价名称);type(text)" json:"evaName"`
+	EvaMapID             int     `orm:"column(评价映射ID)" json:"evaMapID"`
+	EvaType              int     `orm:"column(评价类型)" json:"evaType"` // 0主观评价1客观评价
+	EvaScore             int     `orm:"column(评价赋分)" json:"evaScore"`
+	EvaDeduction         int     `orm:"column(评价失分)" json:"evaDeduction"`
+	EvaSource            int     `orm:"column(评价来源)" json:"evaSource"`           // 0来自流程图,1.来自教员自定义
+	DisqualificationItem int     `orm:"column(失格项)" json:"disqualificationItem"` // 失格项 1是0否
+	IsOperated           int     `orm:"column(是否操作)" json:"isOperated"`          // 节点是否操作 0 未操作 1 已操作
 }
 }
 
 
 func (c *CourseEvaLog) TableName() string { return "CourseEvaLog" }
 func (c *CourseEvaLog) TableName() string { return "CourseEvaLog" }

+ 14 - 16
Tech/models/电调模型.go

@@ -8,25 +8,23 @@ import (
 
 
 // DiandiaoModel 表示电调的 JSON 结构
 // DiandiaoModel 表示电调的 JSON 结构
 type DiandiaoModel struct {
 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"`
+	CMDType      int    `json:"CMDType"` //0:设备状态1设备数据控制
+	CtrlType     int    `json:"CtrlType"`
+	EqpmtStatus  int    `json:"EqpmtStatus"`  //设备状态值
+	EqpmtStdName string `json:"EqpmtStdName"` //设备标准名称
+	EqpmtStrID   string `json:"EqpmtStrID"`
+	IsReset      int    `json:"IsReset"`
+	LineID       int    `json:"LineID"` //线路号
+	OpeMark      int    `json:"OpeMark"`
+	FValue       int    `json:"fValue"` //浮点数值
+	NValueType   int    `json:"nValueType"`
 }
 }
 
 
+// ... existing code ...
 // generateModelKey 生成电调模型唯一键
 // generateModelKey 生成电调模型唯一键
 func (em *DiandiaoModel) GenerateModelKey() string {
 func (em *DiandiaoModel) GenerateModelKey() string {
-	return fmt.Sprintf("%d:%d:%d", em.LineID, em.StationID, em.ViewID)
+	//return fmt.Sprintf("%d:%d:%d", em.LineID, em.StationID, em.ViewID)
+	return fmt.Sprintf("%d", em.LineID)
 }
 }
 
 
 // 单图元电调模型
 // 单图元电调模型
@@ -127,7 +125,7 @@ func (em *ElectricModelManager) UpdateSingleDevice(model DiandiaoModel) {
 		// 查找是否已存在该设备
 		// 查找是否已存在该设备
 		found := false
 		found := false
 		for i, existingModel := range viewMapModel.Models {
 		for i, existingModel := range viewMapModel.Models {
-			if existingModel.EqpmtID == model.EqpmtID {
+			if existingModel.EqpmtStrID == model.EqpmtStrID {
 				viewMapModel.Models[i] = model
 				viewMapModel.Models[i] = model
 				found = true
 				found = true
 				break
 				break

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

@@ -25,6 +25,7 @@ type NodeData struct {
 	FaultNode        *CourseFaultNode     `json:"faultNode"`
 	FaultNode        *CourseFaultNode     `json:"faultNode"`
 	VoiceNode        *CourseVoiceNode     `json:"voiceNode"`
 	VoiceNode        *CourseVoiceNode     `json:"voiceNode"`
 	NodeTrigger      *CourseNodeTrigger   `json:"nodeTrigger"`
 	NodeTrigger      *CourseNodeTrigger   `json:"nodeTrigger"`
+	NodeName         string               `json:"nodeName"`
 	NodeID           int                  `json:"nodeId"`
 	NodeID           int                  `json:"nodeId"`
 	BindRole         int                  `json:"bindRole"`
 	BindRole         int                  `json:"bindRole"`
 	NodeDetail       string               `json:"nodeDetail"`
 	NodeDetail       string               `json:"nodeDetail"`

+ 27 - 4
Tech/routers/router.go

@@ -47,16 +47,20 @@ func init() {
 	beego.Router("/eva/add", &controllers.EvaController{}, "post:Add")
 	beego.Router("/eva/add", &controllers.EvaController{}, "post:Add")
 	beego.Router("/eva/delete", &controllers.EvaController{}, "post:Delete")
 	beego.Router("/eva/delete", &controllers.EvaController{}, "post:Delete")
 	beego.Router("/eva/update", &controllers.EvaController{}, "post:Update")
 	beego.Router("/eva/update", &controllers.EvaController{}, "post:Update")
+	// /eva/orderupdate 评价排序更新
 
 
-	beego.Router("/eva/record/list", &controllers.EvaController{}, "post:EvaRecordList")
-	beego.Router("/eva/setscore", &controllers.EvaController{}, "post:SetScore")
+	beego.Router("/eva/orderupdate", &controllers.EvaController{}, "post:Orderupdate")
 
 
 	//电调
 	//电调
-	beego.Router("/courserun/eqpmtstatus", &controllers.EDispatchController{}, "post:Eqpmtstatus")
+	beego.Router("/courserun/eqpmtvalue", &controllers.EDispatchController{}, "post:Eqpmtvalue")
 	beego.Router("/courserun/add_ctrl_log", &controllers.EDispatchController{}, "post:Addctrllog")
 	beego.Router("/courserun/add_ctrl_log", &controllers.EDispatchController{}, "post:Addctrllog")
 
 
-	//获取设备状态 UI->Server->电调
+	//设置设备状态 UI->Server->电调
+	beego.Router("/serverctrl/seteqpmtoper", &controllers.EDispatchController{}, "post:Seteqpmtoper")
+	///设置设备故障状态 UI->Server->电调
+	beego.Router("/serverctrl/seteqpmtfault", &controllers.EDispatchController{}, "post:Seteqpmtfault")
 
 
+	//获取设备状态 UI->Server->电调
 	beego.Router("/serverctrl/subsysstatus", &controllers.EDispatchController{}, "post:SubSysStatus")
 	beego.Router("/serverctrl/subsysstatus", &controllers.EDispatchController{}, "post:SubSysStatus")
 	beego.Router("/serverctrl/alleqpmtList", &controllers.EDispatchController{}, "post:AllEqpmtList")
 	beego.Router("/serverctrl/alleqpmtList", &controllers.EDispatchController{}, "post:AllEqpmtList")
 
 
@@ -65,7 +69,26 @@ func init() {
 	//运行记录
 	//运行记录
 	beego.Router("/runrecord/list ", &controllers.CourseRunController{}, "post:RunRecordList")
 	beego.Router("/runrecord/list ", &controllers.CourseRunController{}, "post:RunRecordList")
 	beego.Router("/runrecord/delete ", &controllers.CourseRunController{}, "post:RunRecordDelete")
 	beego.Router("/runrecord/delete ", &controllers.CourseRunController{}, "post:RunRecordDelete")
+	beego.Router("/runrecord/listone ", &controllers.CourseRunController{}, "post:RunRecordListOne")
 
 
 	//操作日志
 	//操作日志
 	beego.Router("oper/runrecord/list ", &controllers.CourseRunController{}, "post:OperRunRecordList")
 	beego.Router("oper/runrecord/list ", &controllers.CourseRunController{}, "post:OperRunRecordList")
+
+	// /evalog/add 添加课程评价记录
+	// /evalog/delete 删除课程评价记录
+	// /evalog/update 更新课程评价记录
+	// /evalog/orderupdate 评价记录排序更新
+	beego.Router("/evalog/add", &controllers.EvaLogController{}, "post:Add")
+	beego.Router("/evalog/delete", &controllers.EvaLogController{}, "post:Delete")
+	beego.Router("/evalog/update", &controllers.EvaLogController{}, "post:Update")
+	beego.Router("/evalog/orderupdate", &controllers.EvaLogController{}, "post:Orderupdate")
+
+	// /eva/record/list 获取课程评价记录
+	beego.Router("/eva/record/list", &controllers.EvaLogController{}, "post:EvaRecordList")
+
+	//设置操作是否操作
+	beego.Router("/eva/setoperated", &controllers.EvaLogController{}, "post:Setoperated")
+
+	// /evalog/export 导出课程评价记录
+	beego.Router("/evalog/export", &controllers.EvaLogController{}, "post:Export")
 }
 }

BIN
Tech/static/fonts/NotoSansSC-Regular.ttf


+ 158 - 212
Tech/test.json

@@ -1,267 +1,213 @@
 {
 {
-    "nodeId": 425930,
+    "nodeId": "935741",
     "nodeName": "开始",
     "nodeName": "开始",
     "nodeType": "start",
     "nodeType": "start",
     "nodeData": {},
     "nodeData": {},
     "childNode": {
     "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": "330600",
+        "nodeName": "语音交互",
+        "nodeType": "voice",
+        "nodeData": {
+            "nodeID": 330600,
+            "nodeName": "2222",
+            "bindRole": 104,
+            "nodeDetail": "",
+            "delaySkip": 0,
+            "loseItem": 1,
+            "virtualOperation": 0,
+            "nodeTrigger": {
+                "nodeID": 330600,
+                "triggerMode": 0,
+                "textParam1": "",
+                "textParam2": "",
+                "event": "",
+                "triggerDelay": 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
-                                    }
-                                }
-                            }
-                        }
-                    ]
-                }
+            "voiceNode": {
+                "templateID": 3002,
+                "categoryName": "目标分类",
+                "subCategoryName": "远端人员",
+                "bindRole": 102,
+                "voiceContent": "222",
+                "evalContent": "333"
             }
             }
-        ],
+        },
         "childNode": {
         "childNode": {
-            "nodeId": 301942,
+            "nodeId": "390371",
             "nodeName": "基本操作",
             "nodeName": "基本操作",
             "nodeType": "operation",
             "nodeType": "operation",
             "nodeData": {
             "nodeData": {
-                "name": "111",
-                "role": 102,
-                "templateID": 1002,
-                "categoryName": "电力设备控制",
-                "subCategoryName": "分合闸",
-                "param1Type": "2",
-                "param1Desc": "111",
-                "param2Type": "1",
-                "param2Desc": "111",
-                "nodeId": 301942,
+                "nodeID": 390371,
+                "nodeName": "名称",
+                "bindRole": 102,
                 "nodeDetail": "",
                 "nodeDetail": "",
-                "bindRole": 101,
                 "delaySkip": 0,
                 "delaySkip": 0,
                 "loseItem": 1,
                 "loseItem": 1,
                 "virtualOperation": 0,
                 "virtualOperation": 0,
                 "nodeTrigger": {
                 "nodeTrigger": {
+                    "nodeID": 390371,
                     "triggerMode": 0,
                     "triggerMode": 0,
+                    "textParam1": "",
+                    "textParam2": "",
+                    "event": "",
                     "triggerDelay": 0
                     "triggerDelay": 0
                 },
                 },
-                "nodeID": 301942,
                 "operationNode": {
                 "operationNode": {
                     "templateID": 1002,
                     "templateID": 1002,
                     "categoryName": "电力设备控制",
                     "categoryName": "电力设备控制",
                     "subCategoryName": "分合闸",
                     "subCategoryName": "分合闸",
-                    "param1Type": "2",
+                    "param1Type": 2,
+                    "param2Type": 2,
+                    "param3Type": 2,
+                    "param4Type": 2,
+                    "param5Type": 2,
                     "param1Desc": "111",
                     "param1Desc": "111",
-                    "param2Type": "1",
-                    "param2Desc": "111",
-                    "score": 0,
+                    "param2Desc": "222",
+                    "param3Desc": "",
+                    "param4Desc": "",
+                    "param5Desc": "",
+                    "score": 10,
                     "deduction": 0
                     "deduction": 0
                 }
                 }
             },
             },
             "childNode": {
             "childNode": {
-                "nodeId": 221487,
+                "nodeId": "918257",
                 "nodeName": "语音交互",
                 "nodeName": "语音交互",
                 "nodeType": "voice",
                 "nodeType": "voice",
                 "nodeData": {
                 "nodeData": {
-                    "name": "222",
-                    "role": 103,
-                    "templateID": 3003,
-                    "categoryName": "目标分类",
-                    "subCategoryName": "就地人员",
-                    "voiceContent": "2222",
-                    "nodeId": 221487,
+                    "nodeID": 918257,
+                    "name": "根据工作票向路局供电调度申请准许作业命令",
+                    "bindRole": 103,
                     "nodeDetail": "",
                     "nodeDetail": "",
-                    "bindRole": 102,
                     "delaySkip": 0,
                     "delaySkip": 0,
                     "loseItem": 1,
                     "loseItem": 1,
                     "virtualOperation": 0,
                     "virtualOperation": 0,
                     "nodeTrigger": {
                     "nodeTrigger": {
+                        "nodeID": 918257,
                         "triggerMode": 0,
                         "triggerMode": 0,
+                        "textParam1": "",
+                        "textParam2": "",
+                        "event": "",
                         "triggerDelay": 0
                         "triggerDelay": 0
                     },
                     },
-                    "nodeID": 221487,
                     "voiceNode": {
                     "voiceNode": {
-                        "templateID": 3003,
+                        "templateID": 3001,
                         "categoryName": "目标分类",
                         "categoryName": "目标分类",
-                        "subCategoryName": "就地人员",
-                        "voiceContent": "2222"
-                    }
+                        "subCategoryName": "远端人员",
+                        "bindRole": 101,
+                        "voiceContent": "供电调度请求批准准许作业",
+                        "evalContent": "准许作业"
+                    },
+                    "nodeName": "111"
                 },
                 },
                 "childNode": {
                 "childNode": {
-                    "nodeId": "466193",
-                    "nodeName": "故障触发",
-                    "nodeType": "fault",
+                    "nodeId": "534140",
+                    "nodeName": "基本操作",
+                    "nodeType": "operation",
                     "nodeData": {
                     "nodeData": {
-                        "name": "222",
-                        "role": 102,
-                        "templateID": 2002,
-                        "categoryName": "设备故障",
-                        "subCategoryName": "设备类型1",
-                        "nodeId": 466193,
+                        "nodeID": 534140,
+                        "name": "根据申请远方操作断开供电臂互供的两变(配)电所对应馈出柜的断路器及隔离开关",
+                        "bindRole": 101,
                         "nodeDetail": "",
                         "nodeDetail": "",
-                        "bindRole": 104,
                         "delaySkip": 0,
                         "delaySkip": 0,
                         "loseItem": 1,
                         "loseItem": 1,
                         "virtualOperation": 0,
                         "virtualOperation": 0,
                         "nodeTrigger": {
                         "nodeTrigger": {
+                            "nodeID": 534140,
                             "triggerMode": 0,
                             "triggerMode": 0,
+                            "textParam1": "",
+                            "textParam2": "",
+                            "event": "",
                             "triggerDelay": 0
                             "triggerDelay": 0
                         },
                         },
-                        "nodeID": 466193,
-                        "faultNode": {
-                            "templateID": 2002,
-                            "categoryName": "设备故障",
-                            "subCategoryName": "设备类型1"
+                        "operationNode": {
+                            "templateID": 1001,
+                            "categoryName": "电力设备控制",
+                            "subCategoryName": "分合闸",
+                            "param1Type": 2,
+                            "param2Type": 2,
+                            "param3Type": 2,
+                            "param4Type": 2,
+                            "param5Type": 2,
+                            "param1Desc": "34234324",
+                            "param2Desc": "324324",
+                            "param3Desc": "",
+                            "param4Desc": "",
+                            "param5Desc": "",
+                            "score": 10,
+                            "deduction": 0
+                        },
+                        "nodeName": "222"
+                    },
+                    "childNode": {
+                        "nodeId": "405697",
+                        "nodeName": "语音交互",
+                        "nodeType": "voice",
+                        "nodeData": {
+                            "nodeID": 405697,
+                            "name": "确认停电后,路局供电调度下令相邻两个变配电所将已停电高压柜“远方/就地”开关打到“就地”位,确认",
+                            "bindRole": 101,
+                            "nodeDetail": "",
+                            "delaySkip": 0,
+                            "loseItem": 1,
+                            "virtualOperation": 0,
+                            "nodeTrigger": {
+                                "nodeID": 405697,
+                                "triggerMode": 0,
+                                "textParam1": "",
+                                "textParam2": "",
+                                "event": "",
+                                "triggerDelay": 0
+                            },
+                            "voiceNode": {
+                                "templateID": 3002,
+                                "categoryName": "目标分类",
+                                "subCategoryName": "远端人员",
+                                "bindRole": 102,
+                                "voiceContent": "将变配电所将已停电高压柜“远方/就地”开关打到“就地”位",
+                                "evalContent": "“远方/就地”,就地”位"
+                            },
+                            "nodeName": "333"
+                        },
+                        "childNode": {
+                            "nodeId": "134762",
+                            "nodeName": "基本操作",
+                            "nodeType": "operation",
+                            "nodeData": {
+                                "nodeID": 134762,
+                                "name": "验明无电,开锁,合上相邻两个变配电所停电高压柜的接地开关,确认,加锁;",
+                                "bindRole": 102,
+                                "nodeDetail": "",
+                                "delaySkip": 0,
+                                "loseItem": 1,
+                                "virtualOperation": 0,
+                                "nodeTrigger": {
+                                    "nodeID": 134762,
+                                    "triggerMode": 0,
+                                    "textParam1": "",
+                                    "textParam2": "",
+                                    "event": "",
+                                    "triggerDelay": 0
+                                },
+                                "operationNode": {
+                                    "templateID": 1012,
+                                    "categoryName": "电力设备控制",
+                                    "subCategoryName": "权限控制",
+                                    "param1Type": 2,
+                                    "param2Type": 2,
+                                    "param3Type": 2,
+                                    "param4Type": 2,
+                                    "param5Type": 2,
+                                    "param1Desc": "423423",
+                                    "param2Desc": "",
+                                    "param3Desc": "",
+                                    "param4Desc": "",
+                                    "param5Desc": "",
+                                    "score": 15,
+                                    "deduction": 0
+                                },
+                                "nodeName": "4444111111"
+                            }
                         }
                         }
                     }
                     }
                 }
                 }