package bo import ( "encoding/json" "fmt" "io/fs" "os" "scd_check_tools/logger" "scd_check_tools/models/enum" "scd_check_tools/tools" "strconv" "strings" "github.com/astaxie/beego/orm" "github.com/tealeg/xlsx" ) //检测任务报告模型 type T_data_task_report struct { Id int `orm:"pk"` Name string // '报告名称' , Code string // '报告编号' , TaskId int // '所属检测任务' , State int // '生成状态;1 生成中 2生成结束' , Doc string //'下载路径' , Cr int // '创建人' , Ct string `orm:"-"` // '创建时间' , Ur int // '更新人' , Ut string `orm:"-"` // '更新时间' } //检测任务管理对象 type TaskReportMgr struct { Model T_data_task_report DeviceBaseModel } var modelDesc3 = "检测报告" func init() { orm.RegisterModel(new(T_data_task_report)) } //生成报告 func (c *TaskReportMgr) Make() (reprid int, err error) { taskMgr := new(TaskMgr) taskMgr.Model = T_data_task{Id: c.Model.TaskId} taskinfo, e := taskMgr.One() if e != nil { return 0, e } dblog := new(SystemLog) dblog.SetUserInfo(c.GetUserInfo()) dblog.Audittype = enum.AuditType_check_task 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 if c.Model.Id == 0 { c.Model.Cr, _ = strconv.Atoi(c.GetUserId()) newid, err2 := db.Insert(&c.Model) err = err2 c.Model.Id = int(newid) } else { c.Model.Ur, _ = strconv.Atoi(c.GetUserId()) _, err = db.Update(&c.Model) } if err != nil { logger.Logger.Error(err) dblog.Description = fmt.Sprintf("生成%s失败:%s,操作数据:%+v", modelDesc3, err.Error(), c.Model) dblog.Fail2() } else { //根据模板生成报告 wordpath, err := c.ToWord(taskinfo) if err != nil { c.Delete() return 0, err } c.Model.Doc = wordpath c.Model.State = 2 _, err = db.Update(&c.Model) dblog.Description = fmt.Sprintf("生成%s成功,操作数据:%+v", modelDesc3, c.Model) dblog.Success2() } return c.Model.Id, err } func (c *TaskReportMgr) List(pageno, pagesize int) ([]orm.Params, int, error) { o := orm.NewOrm() rowset := []orm.Params{} sqlParams := []interface{}{} sql := "select t.name,t.code,t.scd_id,a.scd_name,t1.id report_id, t1.doc,t1.state report_state from t_data_task t left join t_data_task_report t1 on t.id=t1.task_id left join t_scd_scl a on t.scd_id=a.id where t.state=2 " if c.Model.TaskId > 0 { sql = sql + " and t.id=?" sqlParams = append(sqlParams, c.Model.TaskId) } if c.Model.Name != "" { sql = sql + " and t.name like ?" sqlParams = append(sqlParams, "%"+c.Model.Name+"%") } if c.Model.Code != "" { sql = sql + " and t.code like ?" sqlParams = append(sqlParams, "%"+c.Model.Code+"%") } limit := fmt.Sprintf(" order by t.ct desc limit %d,%d", (pageno-1)*pagesize, pagesize) _, err := o.Raw(sql+limit, sqlParams).Values(&rowset) total := []orm.Params{} _, err = o.Raw(strings.Replace(sql, "*", "count(1) cnt", 1), sqlParams).Values(&total) if err != nil { logger.Logger.Error(err) return nil, 0, err } totalCnt := 0 if len(total) > 0 { totalCnt, _ = strconv.Atoi(tools.IsEmpty(total[0]["cnt"])) } return rowset, totalCnt, err } 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 { return tmp, nil } tmp.Id, _ = strconv.Atoi(tools.IsEmpty(rowset[0]["id"])) tmp.Code = tools.IsEmpty(rowset[0]["code"]) tmp.Name = tools.IsEmpty(rowset[0]["name"]) tmp.TaskId = taskid tmp.Doc = tools.IsEmpty(rowset[0]["doc"]) tmp.State, _ = strconv.Atoi(tools.IsEmpty(rowset[0]["state"])) return tmp, nil } //根据model中指定的id删除检测任务报告 func (c *TaskReportMgr) Delete() (err error) { dblog := new(SystemLog) dblog.SetUserInfo(c.GetUserInfo()) dblog.Audittype = enum.AuditType_check_task dblog.Logtype = enum.LogType_Delete dblog.Eventtype = enum.OptEventType_Bus dblog.Eventlevel = enum.OptEventLevel_Hight db := orm.NewOrm() doc := "" if c.Model.Id > 0 { err = db.Read(&c.Model) if err != nil { return err } doc = c.Model.Doc _, err = db.Delete(&c.Model) } if c.Model.TaskId > 0 { lst := []orm.Params{} db.Raw("select * from t_data_task_report where task_id=?", c.Model.TaskId).Values(&lst) if len(lst) > 0 { doc = tools.IsEmpty(lst[0]["doc"]) } else { return nil } _, err = db.Raw("delete from t_data_task_report where task_id=?", c.Model.TaskId).Exec() } if err != nil { logger.Logger.Error(err) dblog.Description = fmt.Sprintf("删除%s%d失败:%s", modelDesc3, c.Model.TaskId, err.Error()) dblog.Fail2() } else { if doc != "" { os.Remove("./" + doc) } dblog.Description = fmt.Sprintf("删除%s%d成功", modelDesc3, c.Model.TaskId) dblog.Success2() } return err } func (c *TaskReportMgr) ToWord(taskinfo T_data_task) (path string, err error) { /* fileMgr := new(AttachmentMgr) fileMgr.Model = T_sys_attachment{Id: int32(taskinfo.ReportId)} fileinfo, err := fileMgr.One() if err != nil { return "", err } */ scdmgr := new(ScdMgr) scdParse := new(ScdParse) scdinfo, _ := scdmgr.One(tools.IsEmpty(taskinfo.ScdId)) scdName := tools.IsEmpty(scdinfo["scd_name"]) sdcXmlObj, _ := scdParse.GetScdXmlObjectBySCDID(tools.IsEmpty(taskinfo.ScdId)) 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 { return "", err } */ scdRuleResult := new(ScdNodeRule) scdRuleResult.ScdID = taskinfo.ScdId result, _, err := scdRuleResult.ResultList("", "", "", "", "", "", 1, 1000000) if err != nil { logger.Logger.Error(err) return "", err } //生成报告数据 var file *xlsx.File file = xlsx.NewFile() sheet_fcda, err := file.AddSheet("虚端子关系") if err != nil { logger.Logger.Error(err) return "", err } sheet_c, err := file.AddSheet("测控装置") if err != nil { logger.Logger.Error(err) return "", err } sheet_p, err := file.AddSheet("保护装置") if err != nil { logger.Logger.Error(err) return "", err } sheet_i, err := file.AddSheet("智能终端") if err != nil { logger.Logger.Error(err) return "", err } sheet_m, err := file.AddSheet("合并单元") if err != nil { logger.Logger.Error(err) return "", err } sheet_other, err := file.AddSheet("schema语法和数据模板") if err != nil { logger.Logger.Error(err) return "", err } c.setCaption(sheet_other, fmt.Sprintf("%-%", scdName, "语法校验结果")) //生成标题行 c.addCellValue(sheet_other, []string{"序号", "行号", "等级", "校验结果内容", "应用标准", "标准条款"}) //生成报表数据 iedResultMap := map[string][]orm.Params{} rowInd := 1 for _, row := range result { ied_name := tools.IsEmpty(row["ied_name"]) if ied_name == "" { //生成数据行 c.addCellValue(sheet_other, []string{ fmt.Sprintf("%d", rowInd), tools.IsEmpty(row["line_no"]), tools.IsEmpty(row["alert_level"]), tools.IsEmpty(row["parse_result"]), tools.IsEmpty(row["apply_standard"]), tools.IsEmpty(row["apply_standard_no"]), }) rowInd = rowInd + 1 } else { iedResultMap[ied_name] = append(iedResultMap[ied_name], row) } } crcFilePath := fmt.Sprintf(strings.Join([]string{".", "static", "upload", ""}, string(os.PathSeparator))+"%d.scd.crc", taskinfo.ScdId) crctext, _ := os.ReadFile(crcFilePath) crcMap := map[string]string{} json.Unmarshal(crctext, &crcMap) scdNodeMgr := new(ScdNode) for ied_name, lst := range iedResultMap { iedObj := scdNodeMgr.GetIed(sdcXmlObj, tools.IsEmpty(taskinfo.ScdId), ied_name) sheetObj := new(xlsx.Sheet) //生成装置标题行 switch strings.ToUpper(ied_name[0:1]) { case "C": sheetObj = sheet_c c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name)) c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"}) c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "测控", crcMap[ied_name]}) break case "P": sheetObj = sheet_p c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name)) c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"}) c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "保护装置", crcMap[ied_name]}) break case "I": sheetObj = sheet_i c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name)) c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"}) c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "智能终端", crcMap[ied_name]}) break case "M": sheetObj = sheet_m c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name)) c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"}) c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "合并单元", crcMap[ied_name]}) break default: continue } //装置信息行 c.addCellValue(sheetObj, []string{"序号", "行号", "等级", "校验结果内容", "应用标准", "标准条款"}) //数据行 rowInd := 1 for _, r := range lst { c.addCellValue(sheetObj, []string{ tools.IsEmpty(rowInd), tools.IsEmpty(r["line_no"]), tools.IsEmpty(r["alert_level"]), tools.IsEmpty(r["parse_result"]), tools.IsEmpty(r["apply_standard"]), tools.IsEmpty(r["apply_standard_no"]), }) rowInd = rowInd + 1 } } result = nil iedResultMap = nil //生成端子关系检查结果 checkAreaRe := new(CheckAreaMgr) result, err = checkAreaRe.GetCheckResult(taskinfo.ScdId) if err != nil { logger.Logger.Error(err) return "", err } c.setCaption(sheet_fcda, fmt.Sprintf("%s-端子校验结果", scdName), 6) //汇总结果 scdFileName := "" if sdcXmlObj.Header != nil { scdFileName = sdcXmlObj.Header.Id } scdVerion := "" scdMakeDt := "" //scd文件生成日期 scdCrc := "" //scd全站crc if sdcXmlObj.Header != nil { if sdcXmlObj.Header.History != nil { hitem := sdcXmlObj.Header.History.Hitem if len(hitem) > 0 { lastHitem := hitem[len(hitem)-1] scdVerion = lastHitem.Version + "." + lastHitem.Revision scdMakeDt = strings.ReplaceAll(lastHitem.When, "T", "") } } } if len(sdcXmlObj.Private) > 0 { for _, r := range sdcXmlObj.Private { if r.Type == "Substation virtual terminal conection CRC" { scdCrc = r.InnerText break } } } c.addCellValue(sheet_fcda, []string{"SCD文件名称", scdFileName, "SCD文件版本", scdVerion}) c.addCellValue(sheet_fcda, []string{"SCD文件生成时间", scdMakeDt, "全站虚连接CRC", scdCrc}) totalIed := len(sdcXmlObj.IED) //总ied数 checkIeds, _ := checkAreaRe.GetIedList(taskinfo.ScdId, 0) checkIedMap := map[string]int{} for _, r := range checkIeds { checkIedMap[tools.IsEmpty(r["ied_name"])] = 1 } c.addCellValue(sheet_fcda, []string{"总IED数目", fmt.Sprintf("%d", totalIed), "参与校核IED数目", fmt.Sprintf("%d", len(checkIeds))}) totalExtrefs := 0 //总虚连接数目 checkExtrefs := 0 //参与校核虚连接数目 for _, r := range sdcXmlObj.IED { if r.AccessPoint == nil { continue } for _, r1 := range r.AccessPoint { if r1.Server == nil { continue } for _, r2 := range r1.Server.LDevice { if r2.LN0 != nil && r2.LN0.Inputs != nil { totalExtrefs = totalExtrefs + len(r2.LN0.Inputs.ExtRef) if checkIedMap[r.Name] == 1 { checkExtrefs = checkExtrefs + len(r2.LN0.Inputs.ExtRef) } } for _, r3 := range r2.LN { if r3.Inputs != nil { totalExtrefs = totalExtrefs + len(r3.Inputs.ExtRef) if checkIedMap[r.Name] == 1 { checkExtrefs = checkExtrefs + len(r3.Inputs.ExtRef) } } } } } } errortype1 := 0 // 多余虚端子 errortype2 := 1 //错误虚端子 errortype3 := 2 //缺失端子 for _, row := range result { switch tools.IsEmpty(row["error_type"]) { case "1": errortype1 = errortype1 + 1 break case "2": errortype2 = errortype2 + 1 break case "3": errortype3 = errortype3 + 1 break } } c.addCellValue(sheet_fcda, []string{"总虚连接数目", fmt.Sprintf("%d", totalExtrefs), "参与校核虚连接数目", fmt.Sprintf("%d", checkExtrefs)}) c.addCellValue(sheet_fcda, []string{"未校核虚连接数目", fmt.Sprintf("%d", totalExtrefs-checkExtrefs), "正确虚连接数目", fmt.Sprintf("%d", checkExtrefs-errortype1-errortype2-errortype3)}) c.addCellValue(sheet_fcda, []string{"多余虚连接数目", fmt.Sprintf("%d", errortype1), "缺失虚连接数目", fmt.Sprintf("%d", errortype3)}) c.addCellValue(sheet_fcda, []string{"错误虚连接数目", fmt.Sprintf("%d", errortype2), "不规范虚连接数目", fmt.Sprintf("%d", 0)}) c.addCellValue(sheet_fcda, []string{"严重问题", fmt.Sprintf("%d", 0), "规范性问题", fmt.Sprintf("%d", 0)}) c.addCellValue(sheet_fcda, []string{"一般问题", fmt.Sprintf("%d", 0), "套别错误虚连接数目", fmt.Sprintf("%d", 0)}) c.addCellValue(sheet_fcda, []string{"跨间隔错误虚连接数目", fmt.Sprintf("%d", 0), "母差支路错误虚连接数目", fmt.Sprintf("%d", 0)}) checkIeds = nil lastIedName := "" cellNo := 1 for _, row := range result { nowIedName := fmt.Sprintf("%s:%s", tools.IsEmpty(row["ied_name"]), tools.IsEmpty(row["ied_desc"])) if lastIedName == "" || lastIedName != nowIedName { lastIedName = nowIedName c.setCaption(sheet_fcda, lastIedName, 6) c.addCellValue(sheet_fcda, []string{"序号", "外部IED", "发送信号", "本IED", "接收信号", "结论"}) cellNo = 1 } c.addCellValue(sheet_fcda, []string{ fmt.Sprintf("%d", cellNo), fmt.Sprintf("%s:%s", tools.IsEmpty(row["out_ied_name"]), tools.IsEmpty(row["out_ied_desc"])), fmt.Sprintf("%s\n%s", tools.IsEmpty(row["out_fcda_desc"]), tools.IsEmpty(row["out_fcda_addr"])), fmt.Sprintf("%s:%s", tools.IsEmpty(row["ied_name"]), tools.IsEmpty(row["ied_desc"])), fmt.Sprintf("%s\n%s", tools.IsEmpty(row["fcda_desc"]), tools.IsEmpty(row["fcda_addr"])), tools.IsEmpty(row["error_type_desc"]), }) cellNo = cellNo + 1 } err = file.Save(reportFN) if err != nil { logger.Logger.Error(err) return "", err } return reportFN[1:], err } func (c *TaskReportMgr) setCaption(sheet *xlsx.Sheet, caption string, margeNum ...int) *xlsx.Cell { row := sheet.AddRow() cell := row.AddCell() if len(margeNum) > 0 { cell.HMerge = margeNum[0] } else { cell.HMerge = 5 //合并单元格数 } cell.Value = caption style := xlsx.NewStyle() style.Alignment.Horizontal = "center" cell.SetStyle(style) return cell } func (c *TaskReportMgr) addCellValue(sheet *xlsx.Sheet, vs []string) { row := sheet.AddRow() for _, r := range vs { cell := row.AddCell() cell.Value = r style := xlsx.NewStyle() style.Alignment.Horizontal = "left" style.Alignment.WrapText = true cell.SetStyle(style) } }