瀏覽代碼

新增端子导入接口

liling 1 年之前
父節點
當前提交
b34c1135ff

+ 1 - 1
service/conf/app.conf

@@ -1,7 +1,7 @@
 appname=SCD检测工具
 appid=scd_check_tools
 copyrequestbody = true
-appport=9527
+appport=19527
 runmode=dev
 unittest=true
 loglevel=5

+ 91 - 0
service/controllers/excelController.go

@@ -14,8 +14,10 @@ import (
 	"errors"
 	"fmt"
 	"os"
+	"path"
 	"scd_check_tools/excel"
 	"scd_check_tools/global"
+	"scd_check_tools/logger"
 	"scd_check_tools/models/bo"
 	"scd_check_tools/tools"
 	"strings"
@@ -186,3 +188,92 @@ func (c *ApiController) ExpTableData() {
 	}
 	c.ServeJSON()
 }
+
+//公用数据导入方法
+// @Summary      将Excel数据导入到指定模块
+// @Description  将Excel数据导入到指定模块
+// @Tags         api
+// @Accept       x-www-form-urlencoded
+// @Produce      json
+// @Param        code   		query     string  true  "业务数据类别,由系统定义。当前支持:ied_func_fcda"
+// @Param        file   	query     file  true  "文件流参数名"
+// @Param        ...paras   	query     string  false  "根据业务查询需求,提供相应的参数"
+// @Success      200    	{object}  ApiOK|ApiError   服务访问成功
+// @Failure 	 401 		status  认证未通过,一般是未指定token或token已失效
+// @Failure 	 500 		status  服务器|后台发生错误
+//	@router impData [post]
+func (c *ExcelController) UploadExcelFile() {
+	code := c.GetString("code", "") //业务数据类别,由系统定义
+	if code == "" {
+		c.Data["json"] = c.ResultError("导入的业务数据类别不能为空")
+		c.ServeJSON()
+		return
+	}
+	_, h, _ := c.GetFile("file")
+	ext := path.Ext(h.Filename)
+	if strings.Index(".csv,.xlsx", ext) == -1 {
+		c.Data["json"] = c.WarpError("不支持的文件格式")
+		c.ServeJSON()
+		return
+	}
+	param := tools.ParseFormParam(c.Ctx.Request.Form)
+	tmmpDir := os.TempDir() + string(os.PathSeparator) + h.Filename
+	c.SaveToFile("file", tmmpDir)
+	if ext == ".csv" {
+		opt := map[string]string{"delimiter": c.GetString("delimiter", "\"")}
+		opt["separator"] = c.GetString("separator", ",")
+		csvData, err0 := excel.ImpCsv(tmmpDir, opt)
+		os.Remove(tmmpDir)
+		if err0 != nil {
+			c.Data["json"] = c.WarpError(err0.Error())
+			c.ServeJSON()
+			return
+		}
+		param["datalist"] = csvData
+	} else {
+		dataList, err0 := excel.ImpExcel(tmmpDir)
+		os.Remove(tmmpDir)
+		if err0 != nil {
+			c.Data["json"] = c.WarpError(err0.Error())
+			c.ServeJSON()
+			return
+		}
+		param["datalist"] = dataList
+	}
+	if len(param["datalist"].([]map[int]string)) == 0 {
+		c.Data["json"] = c.WarpError("文件中没有可导入的数据,请检查后重试")
+		c.ServeJSON()
+		return
+	}
+	var err error
+	var data interface{}
+	//param为excel解析结果
+	//以下为你的逻辑处理
+	//....
+	//siteDataObj := new(bo.SiteData)
+	//data, err := siteDataObj.ExpData(GetCurrentUser(c.Ctx), param)
+	switch code {
+	case "ied_func_fcda":
+		dataOptSrv := new(bo.SysCheckModelIedFuncMgr)
+		dataOptSrv.SetUserInfo(c.GetCurrentUserInfo())
+		_, err = dataOptSrv.Imp(param)
+		break
+	/*
+		case "optimize_deletion_fillrule":
+			dataOptSrv := new(service.DataoptimizeService)
+			dataOptSrv.UserInfo = c.GetCurrentUserInfo_rt()
+			err = dataOptSrv.ImpDeletionExcel(param)
+			break
+	*/
+	default:
+		err = errors.New("未定义的导入业务类型code")
+		break
+	}
+	if err != nil {
+		logger.Logger.Info(fmt.Sprintf("导入源数据:%+v", param))
+		c.Data["json"] = c.WarpError(err.Error())
+	} else {
+		c.Data["json"] = c.WarpOK(data)
+	}
+	c.ServeJSON()
+}

+ 88 - 1
service/excel/export.go

@@ -1,10 +1,15 @@
 package excel
 
 import (
-	"scd_check_tools/tools"
+	"encoding/csv"
+	"encoding/json"
 	"errors"
 	"fmt"
+	"io"
 	"os"
+	"regexp"
+	"scd_check_tools/logger"
+	"scd_check_tools/tools"
 	"strconv"
 	"strings"
 
@@ -173,3 +178,85 @@ func ImportRecord(path string, title string, fieldMapping map[string]string) ([]
 	}
 	return result, nil
 }
+
+func ImpExcel(path string) (data []map[int]string, err error) {
+	xlFile, err := xlsx.OpenFile(path)
+	if err != nil {
+		return nil, err
+	}
+	var sheet = xlFile.Sheets[0]
+	var result = []map[int]string{}
+	reg := regexp.MustCompile(`\r\n\t`)
+	logger.Logger.Debug(fmt.Sprintf("当前导入文件%s数据总行数:%d", path, len(sheet.Rows)))
+	for i, row := range sheet.Rows {
+		if i == 0 || i == 1 {
+			continue
+		}
+		rowdata := map[int]string{}
+		//判断当前是否所有行都为空
+		isallEmt := true
+		for j, cell := range row.Cells {
+			rowdata[j] = reg.ReplaceAllString(strings.Trim(cell.String(), " "), "")
+			if rowdata[j] != "" {
+				isallEmt = false
+			}
+		}
+		if isallEmt {
+			//空行直接跳过
+			continue
+		}
+		result = append(result, rowdata)
+	}
+	//tools.Log(result)
+	return result, nil
+}
+
+func ImpCsv(path string, opts ...map[string]string) (data []map[int]string, err error) {
+	fileHanlder, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer fileHanlder.Close()
+	reader := csv.NewReader(fileHanlder)
+	if reader == nil {
+		return nil, errors.New("文件读取失败!")
+	}
+	if opts != nil {
+		p1 := opts[0]
+		if separator, has := p1["separator"]; has {
+			reader.Comma = []rune(separator)[0]
+		}
+	}
+	reader.TrimLeadingSpace = true
+	rowindex := 0
+	var csvData = []map[int]string{}
+	errList := []string{}
+	for {
+		txt, readerr := reader.Read()
+		if readerr == io.EOF {
+			break
+		}
+		if readerr != nil {
+			rowindex++
+			tools.Log(readerr)
+			errList = append(errList, readerr.Error())
+			continue
+		}
+		reg := regexp.MustCompile(`\r\n\t`)
+		if rowindex == 0 {
+			rowindex++
+			continue
+		}
+		rowdata := map[int]string{}
+		for j, cell := range txt {
+			rowdata[j] = reg.ReplaceAllString(strings.Trim(cell, " "), "")
+		}
+		csvData = append(csvData, rowdata)
+		rowindex++
+	}
+	if len(errList) > 0 {
+		errstr, _ := json.Marshal(errList)
+		return nil, errors.New(string(errstr))
+	}
+	return csvData, nil
+}

+ 82 - 11
service/models/bo/check_sysmodel_ied_func.go

@@ -51,15 +51,21 @@ func (c *SysCheckModelIedFuncMgr) Save() (err error) {
 	if err != nil {
 		return err
 	}
-	if hasName {
-		return errors.New("功能名称已存在")
-	}
+
 	db.Begin()
 	if c.Model.Id > 0 {
 		//编辑
+		if hasName > 0 && c.Model.Id != hasName {
+			db.Rollback()
+			return errors.New("功能名称已存在")
+		}
 		_, err = db.Update(&c.Model)
 	} else {
 		//新增
+		if hasName > 0 {
+			db.Rollback()
+			return errors.New("功能名称已存在")
+		}
 		newid, err2 := db.Insert(&c.Model)
 		err = err2
 		c.Model.Id = int(newid)
@@ -91,21 +97,29 @@ func (c *SysCheckModelIedFuncMgr) Save() (err error) {
 	return err
 }
 
-func (c *SysCheckModelIedFuncMgr) Exist() (bool, error) {
+func (c *SysCheckModelIedFuncMgr) Exist() (int, error) {
 	db := orm.NewOrm()
 	if c.Model.FuncName == "" {
-		return false, errors.New("功能名称不能为空")
+		return 0, errors.New("功能名称不能为空")
 	}
 	rowset := []orm.Params{}
 	_, err := db.Raw("select id from t_data_model_func_def where model_id=? and ied_type=? and func_name=?", c.Model.ModelId, c.Model.IedType, c.Model.FuncName).Values(&rowset)
 	if len(rowset) > 0 {
-		if c.Model.Id > 0 && tools.IsEmpty(c.Model.Id) != tools.IsEmpty(rowset[0]["id"]) {
-			return true, nil
-		} else {
-			return false, nil
-		}
+		id, _ := strconv.Atoi(tools.IsEmpty(rowset[0]["id"]))
+		return id, nil
 	}
-	return false, err
+	return 0, err
+}
+
+func (c *SysCheckModelIedFuncMgr) GetFuncId(modid int, iedtpye, name string) (int, error) {
+	rowset := []orm.Params{}
+	db := orm.NewOrm()
+	_, err := db.Raw("select id from t_data_model_func_def where model_id=? and ied_type=? and func_name=?", modid, iedtpye, name).Values(&rowset)
+	if len(rowset) > 0 {
+		id, _ := strconv.Atoi(tools.IsEmpty(rowset[0]["id"]))
+		return id, nil
+	}
+	return 0, err
 }
 
 func (c *SysCheckModelIedFuncMgr) Copy(oldModelid, newModelId int) error {
@@ -199,3 +213,60 @@ func (c *SysCheckModelIedFuncMgr) GetList(modelid int, iedType string) ([]orm.Pa
 	}
 	return rowset, err
 }
+
+//从excel中导入
+func (c *SysCheckModelIedFuncMgr) Imp(param map[string]interface{}) (bool, error) {
+	modelId, _ := strconv.Atoi(tools.IsEmpty(param["model_id"]))
+	if modelId == 0 {
+		return false, errors.New("模型编号不能为空")
+	}
+	datalist := param["datalist"].([]map[int]string)
+	logObj := new(SystemLog)
+	logObj.SetUserInfo(c.GetUserInfo())
+	logObj.Audittype = enum.AuditType_check_model
+	logObj.Eventtype = enum.OptEventType_Bus
+	logObj.Eventlevel = enum.OptEventLevel_Hight
+	logObj.Logtype = enum.LogType_imp
+	logObj.Description = "装置功能及端子导入"
+	i := 2
+	func_id := 0
+	fcda_id := 0
+	funcMap := map[string]int{} //已处理的功能
+	for _, row := range datalist {
+		ied_type := tools.IsEmpty(row[2])
+		if ied_type == "" {
+			return false, errors.New(fmt.Sprintf("第%d行:装置类型编码不能为空", i))
+		}
+		func_name := tools.IsEmpty(row[3])
+		if func_name == "" {
+			return false, errors.New(fmt.Sprintf("第%d行:功能名称不能为空", i))
+		}
+		fcda_name := tools.IsEmpty(row[4])
+		if fcda_name == "" {
+			return false, errors.New(fmt.Sprintf("第%d行:端子设计名称不能为空", i))
+		}
+		fcda_match_exp := tools.IsEmpty(row[5])
+		if fcda_match_exp == "" {
+			return false, errors.New(fmt.Sprintf("第%d行:端子关键词不能为空", i))
+		}
+		if funcMap[func_name] == 0 {
+			//获取功能id
+			func_id, _ = c.GetFuncId(modelId, ied_type, func_name)
+			funcMap[func_name] = func_id
+		}
+		mod := T_data_model_func_def{}
+		mod.Id = func_id
+		mod.ModelId = modelId
+		mod.IedType = ied_type
+		mod.FuncFcdaId = fcda_id
+		mod.FuncName = func_name
+		mod.FcdaName = fcda_name
+		mod.FcdaMatchExp = fcda_match_exp
+		err := c.Save()
+		if err != nil {
+			return false, err
+		}
+		i = i + 1
+	}
+	return true, nil
+}

+ 3 - 2
service/models/bo/check_sysmodel_ied_func_fcda.go

@@ -79,9 +79,10 @@ func (c *SysCheckModelIedFuncFcdaMgr) Exist() (bool, error) {
 	_, err := db.Raw("select id from t_data_model_func_fcda where model_id=? and func_id=? and fcda_name=?", c.Model.ModelId, c.Model.FuncId, c.Model.FcdaName).Values(&rowset)
 	if len(rowset) > 0 {
 		if tools.IsEmpty(c.Model.Id) != tools.IsEmpty(rowset[0]["id"]) {
-			return false, nil
-		} else {
+			//端子名称重复
 			return true, nil
+		} else {
+			return false, nil
 		}
 	}
 	return false, err

+ 20 - 41
service/models/bo/checktools_area.go

@@ -403,31 +403,6 @@ func (c *CheckAreaMgr) CheckAreaIedRelation() error {
 			return errors.New(fmt.Sprintf("间隔%s未发现任何装置", tools.IsEmpty(row["area_name"])))
 		}
 		area_ieds[area_id] = s1
-		/*
-			curIeds := map[string]string{}
-			for _, row1 := range s1 {
-				iedname := strings.Trim(tools.IsEmpty(row1["ied_name"]), " ")
-				iedParts := scdParseMgr.ParseIedName(iedname)
-				iedtype := iedParts[0] + iedParts[1] + iedParts[2]
-				curIeds[iedtype] = iedname
-			}
-			for k, _ := range hasIeds {
-				iedname := curIeds[k]
-				if iedname == "" {
-					parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, k)
-					r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
-					//检查未通过
-					scdNodeRule.AppendPaseResult(r)
-				} else {
-					//判断装置是否存在
-					if scdNode.GetIed(scdXmlObj, "", iedname) == nil {
-						parse_result := fmt.Sprintf("间隔%s内装置%s未定义", area_name, iedname)
-						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
-						//检查未通过
-						scdNodeRule.AppendPaseResult(r)
-					}
-				}
-			}*/
 	}
 	//装置关联关系分析
 	//先分析母联间隔,如果没有选择母联间隔时,主变间隔中不包含母联终端装置
@@ -638,7 +613,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 								parse_result := fmt.Sprintf("间隔%s的装置%s缺失虚端子%s", area_name, iedname, fcda_name)
 								r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 								//检查未通过
-								scdNodeRule.AppendPaseResult(r)
+								scdNodeRule.AppendFcdaCheckResult(r)
 							}
 						}
 					}
@@ -646,7 +621,7 @@ func (c *CheckAreaMgr) CheckIedFcda() error {
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失功能%s", area_name, iedname, tools.IsEmpty(row3["func_name"]))
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 				}
 			}
@@ -757,6 +732,10 @@ func (c *CheckAreaMgr) pT(modelid int, iedtypes string, ieds map[string]orm.Para
 		volMap["middle"] = volRows[1]["vol"].(string)           //中压电压等级
 		volMap["low"] = volRows[len(volRows)-1]["vol"].(string) //低压电压等级
 	}
+	//判断是否将各电压等级的保护装置合并还是分开的间隔
+	//如果存在高中低压的保护装置,则说明是分开的主变间隔
+	//isMarge := true // 默认为合并的主变间隔
+
 	for _, row := range ieds {
 		if tools.IsEmpty(row["ied_type"]) != "P" || tools.IsEmpty(row["p_type"]) != "T" {
 			continue
@@ -1129,7 +1108,7 @@ func (c *CheckAreaMgr) cJ(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 					dealFromIed[findIedName] = 1
 				}
@@ -1145,7 +1124,7 @@ func (c *CheckAreaMgr) cJ(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 			parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
 			r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 			//检查未通过
-			scdNodeRule.AppendPaseResult(r, masterIed)
+			scdNodeRule.AppendFcdaCheckResult(r)
 			continue
 		}
 		toIedname := ""
@@ -1175,7 +1154,7 @@ func (c *CheckAreaMgr) cJ(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r, masterIed)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 				}
 			}
@@ -1183,7 +1162,7 @@ func (c *CheckAreaMgr) cJ(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 				parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
 				r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 				//检查未通过
-				scdNodeRule.AppendPaseResult(r, masterIed)
+				scdNodeRule.AppendFcdaCheckResult(r)
 			}
 		}
 	}
@@ -1222,7 +1201,7 @@ func (c *CheckAreaMgr) cL(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 					dealFromIed[findIedName] = 1
 				}
@@ -1238,7 +1217,7 @@ func (c *CheckAreaMgr) cL(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 			parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
 			r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 			//检查未通过
-			scdNodeRule.AppendPaseResult(r, masterIed)
+			scdNodeRule.AppendFcdaCheckResult(r)
 			continue
 		}
 		toIedname := ""
@@ -1268,7 +1247,7 @@ func (c *CheckAreaMgr) cL(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r, masterIed)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 				}
 			}
@@ -1276,7 +1255,7 @@ func (c *CheckAreaMgr) cL(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 				parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
 				r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 				//检查未通过
-				scdNodeRule.AppendPaseResult(r, masterIed)
+				scdNodeRule.AppendFcdaCheckResult(r)
 			}
 		}
 	}
@@ -1317,7 +1296,7 @@ func (c *CheckAreaMgr) cT(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失", area_name, findIedName)
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 					dealFromIed[findIedName] = 1
 				}
@@ -1331,10 +1310,10 @@ func (c *CheckAreaMgr) cT(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 		}
 		if len(tmpToAreaIeds) == 0 {
 			logger.Logger.Debug(fmt.Sprintf("缺失类型关联装置 :%+v", row))
-			parse_result := fmt.Sprintf("间隔%s缺失类型为%s的装置", area_name, toiedtype)
+			parse_result := fmt.Sprintf("间隔%s缺失类型为%s的%s信号装置", area_name, toiedtype, reftype)
 			r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 			//检查未通过
-			scdNodeRule.AppendPaseResult(r, masterIed)
+			scdNodeRule.AppendFcdaCheckResult(r)
 			continue
 		}
 		toIedname := ""
@@ -1378,7 +1357,7 @@ func (c *CheckAreaMgr) cT(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 						parse_result := fmt.Sprintf("间隔%s的装置%s缺失与装置%s的%s信号关联", area_name, findIedName, toIedname, reftype)
 						r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 						//检查未通过
-						scdNodeRule.AppendPaseResult(r, masterIed)
+						scdNodeRule.AppendFcdaCheckResult(r)
 					}
 				}
 				if hasSameVolIed {
@@ -1390,12 +1369,12 @@ func (c *CheckAreaMgr) cT(scdXmlObj *node_attr.SCL, scdNodeMgr *ScdNode, scdNode
 					parse_result := fmt.Sprintf("间隔%s的装置%s缺失同电压等级的关联类型%s装置", area_name, findIedName, toiedtype)
 					r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 					//检查未通过
-					scdNodeRule.AppendPaseResult(r, masterIed)
+					scdNodeRule.AppendFcdaCheckResult(r)
 				} else if !hasToIed {
 					parse_result := fmt.Sprintf("间隔%s的装置%s缺失关联装置%s", area_name, findIedName, toIedname)
 					r := map[string]interface{}{"scdid": c.ScdId, "lineno": 0, "ruleid": area_ruleid, "nodeid": 0, "parse_result": parse_result}
 					//检查未通过
-					scdNodeRule.AppendPaseResult(r, masterIed)
+					scdNodeRule.AppendFcdaCheckResult(r)
 				}
 			}
 		}

+ 2 - 0
service/models/bo/scd_file_parse.go

@@ -747,6 +747,8 @@ func (c *ScdParse) XmlIEDParse(stationid, scdPath, scdName string) (scdid string
 			dataMsg, _ := json.Marshal(data)
 			mqtt.PublishMessage(fmt.Sprintf("/jujutong/scd_check_tools/parse/%s", stationid), string(dataMsg))
 			new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_Loading.Code(), 2)
+			//默认为已解析
+			new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_Parse.Code(), 2)
 			return scdid, nil
 		} else {
 			//判断是否有解析完成的持久化文件

+ 34 - 1
service/models/bo/scd_node_rule.go

@@ -2586,6 +2586,14 @@ func (c *ScdNodeRule) AppendPaseResult(r map[string]interface{}, ied ...*node_at
 	//go mqtt.PublishMessage("/jujutong/scd_check_tools/ruleparse/"+fmt.Sprintf("%d", c.ScdID), r["parse_result"].(string))
 }
 
+//添加端子检查结果
+func (c *ScdNodeRule) AppendFcdaCheckResult(r map[string]interface{}) {
+	r["check_type"] = "fcda"
+	c.checkFailListLock.Lock()
+	c.CheckFailList = append(c.CheckFailList, r)
+	c.checkFailListLock.Unlock()
+}
+
 func (c *ScdNodeRule) CheckFinish() {
 	c.isRun = 2
 }
@@ -2623,10 +2631,17 @@ func (c *ScdNodeRule) writeNodeDB() {
 	db := orm.NewOrm()
 	s1 := time.Now().Unix()
 	nodeCols := "(scd_id,node_id,line_no,rule_target,rule_id,parse_result,ied_name,ied_desc)"
+	fcdaCols := "(scd_id,ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,rule_id,parse_result,error_type)"
 	loadedRec := 0
 	nodeSqlValuesAry := []string{}
+	fcdaSqlValuesAry := []string{}
 	for _, m := range c.CheckFailList {
-		nodeSqlValuesAry = append(nodeSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+","+tools.IsEmpty(m["nodeid"], "0")+","+tools.IsEmpty(m["lineno"], "0")+",'"+tools.IsEmpty(m["rule_target"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"','"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"')")
+		check_type := tools.IsEmpty(m["check_type"]) // fcda检查结果写入t_scd_fcda_check_result
+		if check_type == "fcda" {
+			fcdaSqlValuesAry = append(fcdaSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+",'"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"','"+tools.IsEmpty(m["fcda_desc"])+"','"+tools.IsEmpty(m["fcda_addr"])+"','"+tools.IsEmpty(m["out_ied_name"])+"','"+tools.IsEmpty(m["out_ied_desc"])+"','"+tools.IsEmpty(m["out_fcda_desc"])+"','"+tools.IsEmpty(m["out_fcda_addr"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"',"+tools.IsEmpty(m["error_type"])+")")
+		} else {
+			nodeSqlValuesAry = append(nodeSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+","+tools.IsEmpty(m["nodeid"], "0")+","+tools.IsEmpty(m["lineno"], "0")+",'"+tools.IsEmpty(m["rule_target"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"','"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"')")
+		}
 		if len(nodeSqlValuesAry) == 5000 {
 			sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
 			_, err := db.Raw(sql).Exec()
@@ -2637,6 +2652,16 @@ func (c *ScdNodeRule) writeNodeDB() {
 			nodeSqlValuesAry = nil
 			nodeSqlValuesAry = []string{}
 		}
+		if len(fcdaSqlValuesAry) == 5000 {
+			sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(nodeSqlValuesAry, ",")
+			_, err := db.Raw(sql).Exec()
+			if err != nil {
+				log.Println(err)
+			}
+			loadedRec = loadedRec + 5000
+			fcdaSqlValuesAry = nil
+			fcdaSqlValuesAry = []string{}
+		}
 	}
 	if len(nodeSqlValuesAry) > 0 {
 		sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
@@ -2646,6 +2671,14 @@ func (c *ScdNodeRule) writeNodeDB() {
 		}
 		nodeSqlValuesAry = nil
 	}
+	if len(fcdaSqlValuesAry) > 0 {
+		sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(nodeSqlValuesAry, ",")
+		_, err := db.Raw(sql).Exec()
+		if err != nil {
+			log.Println(err)
+		}
+		fcdaSqlValuesAry = nil
+	}
 	c.CheckFailList = nil
 	runtime.GC()
 	s2 := time.Now().Unix()

+ 2 - 3
service/models/bo/task.go

@@ -160,8 +160,6 @@ func (c *TaskMgr) start(task T_data_task) error {
 				}
 			}
 		}
-		//检测结束
-		c.SetActive(2)
 	}()
 	return err
 }
@@ -205,7 +203,8 @@ func (c *TaskMgr) SetStep(scdid string, stepcode string, state int, msg ...strin
 		logger.Logger.Error(err)
 		return
 	}
-	if len(hasStep) == 0 {
+	if len(hasStep) == 0 || tools.IsEmpty(hasStep[0]["cnt"]) == "0" {
+		// 全部步骤检测完成,更改任务检测状态为已完成
 		db.Raw("update t_data_task set state=2 where id=?", taskid).Exec()
 	}
 }

+ 15 - 3
service/models/bo/task_report.go

@@ -55,6 +55,11 @@ func (c *TaskReportMgr) Make() (reprid int, err error) {
 	dblog.Logtype = enum.LogType_Insert
 	dblog.Eventtype = enum.OptEventType_Bus
 	dblog.Eventlevel = enum.OptEventLevel_Hight
+	//判断报告 是否已生成
+	tmp, _ := c.One(c.Model.TaskId)
+	if tmp.Id > 0 {
+		c.Model.Id = tmp.Id
+	}
 	db := orm.NewOrm()
 	c.Model.Name = taskinfo.Name
 	c.Model.Code = taskinfo.Code
@@ -123,6 +128,11 @@ func (c *TaskReportMgr) List(pageno, pagesize int) ([]orm.Params, int, error) {
 func (c *TaskReportMgr) One(taskid int) (T_data_task_report, error) {
 	o := orm.NewOrm()
 	tmp := T_data_task_report{}
+	if c.Model.Id > 0 {
+		tmp.Id = c.Model.Id
+		err := o.Read(&tmp)
+		return tmp, err
+	}
 	rowset := []orm.Params{}
 	o.Raw("select * from t_data_task_report where task_id=?", taskid).Values(&rowset)
 	if len(rowset) == 0 {
@@ -185,6 +195,7 @@ func (c *TaskReportMgr) ToWord(taskinfo T_data_task) (path string, err error) {
 	reportPath := strings.Join([]string{".", "static", "download", "report"}, string(os.PathSeparator))
 	os.MkdirAll(reportPath, fs.ModePerm)
 	reportFN := reportPath + string(os.PathSeparator) + fmt.Sprintf("%s.%s", c.Model.Code, "xlsx")
+	logger.Logger.Debug(fmt.Sprintf("正在生成检测报告文件:%s", reportFN))
 	/*
 		err = os.Rename(fileinfo.SavePath, reportFN)
 		if err != nil {
@@ -194,7 +205,8 @@ func (c *TaskReportMgr) ToWord(taskinfo T_data_task) (path string, err error) {
 	scdRuleResult := new(ScdNodeRule)
 	scdRuleResult.ScdID = taskinfo.ScdId
 	result, _, err := scdRuleResult.ResultList("", "", "", "", "", "", 1, 1000000)
-	if err == nil {
+	if err != nil {
+		logger.Logger.Error(err)
 		return "", err
 	}
 	//生成报告数据
@@ -238,7 +250,7 @@ func (c *TaskReportMgr) ToWord(taskinfo T_data_task) (path string, err error) {
 			c.addCellValue(sheet_other, []string{
 				fmt.Sprintf("%d", rowInd),
 				tools.IsEmpty(row["line_no"]),
-				tools.IsEmpty(row["alart_level"]),
+				tools.IsEmpty(row["alert_level"]),
 				tools.IsEmpty(row["parse_result"]),
 				tools.IsEmpty(row["apply_standard"]),
 				tools.IsEmpty(row["apply_standard_no"]),
@@ -293,7 +305,7 @@ func (c *TaskReportMgr) ToWord(taskinfo T_data_task) (path string, err error) {
 			c.addCellValue(sheetObj, []string{
 				tools.IsEmpty(rowInd),
 				tools.IsEmpty(r["line_no"]),
-				tools.IsEmpty(r["alart_level"]),
+				tools.IsEmpty(r["alert_level"]),
 				tools.IsEmpty(r["parse_result"]),
 				tools.IsEmpty(r["apply_standard"]),
 				tools.IsEmpty(r["apply_standard_no"]),

+ 18 - 0
service/routers/commentsRouter_____________ME_GoProject_src_scd_check_tools_controllers.go

@@ -718,6 +718,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["scd_check_tools/controllers:ExcelController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:ExcelController"],
+        beego.ControllerComments{
+            Method: "UploadExcelFile",
+            Router: "impData",
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["scd_check_tools/controllers:FlowController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:FlowController"],
         beego.ControllerComments{
             Method: "DeleteFlowCnf_NodeUser",
@@ -1386,6 +1395,15 @@ func init() {
 
     beego.GlobalControllerRouter["scd_check_tools/controllers:TaskController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:TaskController"],
         beego.ControllerComments{
+            Method: "ReSetTaskActive",
+            Router: "/task/reset",
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["scd_check_tools/controllers:TaskController"] = append(beego.GlobalControllerRouter["scd_check_tools/controllers:TaskController"],
+        beego.ControllerComments{
             Method: "SaveTaskInfo",
             Router: "/task/save",
             AllowHTTPMethods: []string{"post"},

+ 49 - 0
service/static/swagger/swagger.json

@@ -6285,9 +6285,58 @@
                     }
                 }
             }
+        },
+        "impData": {
+            "post": {
+                "tags": [
+                    "scd_check_tools/controllersExcelController"
+                ],
+                "summary": "将Excel数据导入到指定模块",
+                "description": "将Excel数据导入到指定模块",
+                "parameters": [
+                    {
+                        "in": "query",
+                        "name": "code",
+                        "description": "业务数据类别,由系统定义。当前支持:ied_func_fcda",
+                        "required": true,
+                        "type": "string"
+                    },
+                    {
+                        "in": "query",
+                        "name": "file",
+                        "description": "文件流参数名",
+                        "required": true,
+                        "type": "file"
+                    },
+                    {
+                        "in": "query",
+                        "name": "...paras",
+                        "description": "根据业务查询需求,提供相应的参数",
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "服务访问成功",
+                        "schema": {
+                            "$ref": "#/definitions/ApiOK|ApiError"
+                        }
+                    },
+                    "401": {
+                        "description": "status  认证未通过,一般是未指定token或token已失效"
+                    },
+                    "500": {
+                        "description": "status  服务器|后台发生错误"
+                    }
+                }
+            }
         }
     },
     "definitions": {
+        "ApiOK|ApiError": {
+            "title": "ApiOK|ApiError",
+            "type": "object"
+        },
         "ResultError": {
             "title": "ResultError",
             "type": "object"

+ 33 - 0
service/static/swagger/swagger.yml

@@ -4264,7 +4264,40 @@ paths:
             $ref: '#/definitions/ResultOK'
         "500":
           description: '{object} ResultError  失败'
+  impData:
+    post:
+      tags:
+      - scd_check_tools/controllersExcelController
+      summary: 将Excel数据导入到指定模块
+      description: 将Excel数据导入到指定模块
+      parameters:
+      - in: query
+        name: code
+        description: 业务数据类别,由系统定义。当前支持:ied_func_fcda
+        required: true
+        type: string
+      - in: query
+        name: file
+        description: 文件流参数名
+        required: true
+        type: file
+      - in: query
+        name: '...paras'
+        description: 根据业务查询需求,提供相应的参数
+        type: string
+      responses:
+        "200":
+          description: 服务访问成功
+          schema:
+            $ref: '#/definitions/ApiOK|ApiError'
+        "401":
+          description: status  认证未通过,一般是未指定token或token已失效
+        "500":
+          description: status  服务器|后台发生错误
 definitions:
+  ApiOK|ApiError:
+    title: ApiOK|ApiError
+    type: object
   ResultError:
     title: ResultError
     type: object

+ 49 - 0
service/swagger/swagger.json

@@ -6285,9 +6285,58 @@
                     }
                 }
             }
+        },
+        "impData": {
+            "post": {
+                "tags": [
+                    "scd_check_tools/controllersExcelController"
+                ],
+                "summary": "将Excel数据导入到指定模块",
+                "description": "将Excel数据导入到指定模块",
+                "parameters": [
+                    {
+                        "in": "query",
+                        "name": "code",
+                        "description": "业务数据类别,由系统定义。当前支持:ied_func_fcda",
+                        "required": true,
+                        "type": "string"
+                    },
+                    {
+                        "in": "query",
+                        "name": "file",
+                        "description": "文件流参数名",
+                        "required": true,
+                        "type": "file"
+                    },
+                    {
+                        "in": "query",
+                        "name": "...paras",
+                        "description": "根据业务查询需求,提供相应的参数",
+                        "type": "string"
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "服务访问成功",
+                        "schema": {
+                            "$ref": "#/definitions/ApiOK|ApiError"
+                        }
+                    },
+                    "401": {
+                        "description": "status  认证未通过,一般是未指定token或token已失效"
+                    },
+                    "500": {
+                        "description": "status  服务器|后台发生错误"
+                    }
+                }
+            }
         }
     },
     "definitions": {
+        "ApiOK|ApiError": {
+            "title": "ApiOK|ApiError",
+            "type": "object"
+        },
         "ResultError": {
             "title": "ResultError",
             "type": "object"

+ 33 - 0
service/swagger/swagger.yml

@@ -4264,7 +4264,40 @@ paths:
             $ref: '#/definitions/ResultOK'
         "500":
           description: '{object} ResultError  失败'
+  impData:
+    post:
+      tags:
+      - scd_check_tools/controllersExcelController
+      summary: 将Excel数据导入到指定模块
+      description: 将Excel数据导入到指定模块
+      parameters:
+      - in: query
+        name: code
+        description: 业务数据类别,由系统定义。当前支持:ied_func_fcda
+        required: true
+        type: string
+      - in: query
+        name: file
+        description: 文件流参数名
+        required: true
+        type: file
+      - in: query
+        name: '...paras'
+        description: 根据业务查询需求,提供相应的参数
+        type: string
+      responses:
+        "200":
+          description: 服务访问成功
+          schema:
+            $ref: '#/definitions/ApiOK|ApiError'
+        "401":
+          description: status  认证未通过,一般是未指定token或token已失效
+        "500":
+          description: status  服务器|后台发生错误
 definitions:
+  ApiOK|ApiError:
+    title: ApiOK|ApiError
+    type: object
   ResultError:
     title: ResultError
     type: object

+ 1 - 0
service/test/test.go

@@ -214,6 +214,7 @@ func (t *UnitTest) Test18() {
 }
 
 func (t *UnitTest) Test19() {
+	return
 	logger.Logger.Println(fmt.Sprintf("=============正在测试生成报告"))
 	appport := conf.GlobalConfig["appport"]
 	url := "http://127.0.0.1:" + appport + "/api/report/make"