task_report.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. package bo
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/fs"
  6. "os"
  7. "scd_check_tools/logger"
  8. "scd_check_tools/models/enum"
  9. "scd_check_tools/tools"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "github.com/astaxie/beego/orm"
  14. "github.com/tealeg/xlsx"
  15. )
  16. //检测任务报告模型
  17. type T_data_task_report struct {
  18. Id int `orm:"pk"`
  19. Name string // '报告名称' ,
  20. Code string // '报告编号' ,
  21. TaskId int // '所属检测任务' ,
  22. State int // '生成状态;1 生成中 2生成结束' ,
  23. Doc string //'下载路径' ,
  24. Cr int // '创建人' ,
  25. Ct string `orm:"-"` // '创建时间' ,
  26. Ur int // '更新人' ,
  27. Ut string `orm:"-"` // '更新时间'
  28. }
  29. //检测任务管理对象
  30. type TaskReportMgr struct {
  31. Model T_data_task_report
  32. DeviceBaseModel
  33. }
  34. var modelDesc3 = "检测报告"
  35. func init() {
  36. orm.RegisterModel(new(T_data_task_report))
  37. }
  38. //生成报告
  39. func (c *TaskReportMgr) Make() (reprid int, err error) {
  40. taskMgr := new(TaskMgr)
  41. taskMgr.Model = T_data_task{Id: c.Model.TaskId}
  42. taskinfo, e := taskMgr.One()
  43. if e != nil {
  44. return 0, e
  45. }
  46. dblog := new(SystemLog)
  47. dblog.SetUserInfo(c.GetUserInfo())
  48. dblog.Audittype = enum.AuditType_check_task
  49. dblog.Logtype = enum.LogType_Insert
  50. dblog.Eventtype = enum.OptEventType_Bus
  51. dblog.Eventlevel = enum.OptEventLevel_Hight
  52. //判断报告 是否已生成
  53. tmp, _ := c.One(c.Model.TaskId)
  54. if tmp.Id > 0 {
  55. c.Model.Id = tmp.Id
  56. }
  57. db := orm.NewOrm()
  58. c.Model.Name = taskinfo.Name
  59. c.Model.Code = taskinfo.Code
  60. if c.Model.Id == 0 {
  61. c.Model.Cr, _ = strconv.Atoi(c.GetUserId())
  62. newid, err2 := db.Insert(&c.Model)
  63. err = err2
  64. c.Model.Id = int(newid)
  65. } else {
  66. c.Model.Ur, _ = strconv.Atoi(c.GetUserId())
  67. _, err = db.Update(&c.Model)
  68. }
  69. if err != nil {
  70. logger.Logger.Error(err)
  71. dblog.Description = fmt.Sprintf("生成%s失败:%s,操作数据:%+v", modelDesc3, err.Error(), c.Model)
  72. dblog.Fail2()
  73. } else {
  74. //根据模板生成报告
  75. wordpath, err := c.ToWord(taskinfo)
  76. if err != nil {
  77. c.Delete()
  78. return 0, err
  79. }
  80. c.Model.Doc = wordpath
  81. c.Model.State = 2
  82. _, err = db.Update(&c.Model)
  83. dblog.Description = fmt.Sprintf("生成%s成功,操作数据:%+v", modelDesc3, c.Model)
  84. dblog.Success2()
  85. }
  86. return c.Model.Id, err
  87. }
  88. func (c *TaskReportMgr) List(pageno, pagesize int) ([]orm.Params, int, error) {
  89. o := orm.NewOrm()
  90. rowset := []orm.Params{}
  91. sqlParams := []interface{}{}
  92. 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 "
  93. if c.Model.TaskId > 0 {
  94. sql = sql + " and t.id=?"
  95. sqlParams = append(sqlParams, c.Model.TaskId)
  96. }
  97. if c.Model.Name != "" {
  98. sql = sql + " and t.name like ?"
  99. sqlParams = append(sqlParams, "%"+c.Model.Name+"%")
  100. }
  101. if c.Model.Code != "" {
  102. sql = sql + " and t.code like ?"
  103. sqlParams = append(sqlParams, "%"+c.Model.Code+"%")
  104. }
  105. limit := fmt.Sprintf(" order by t.ct desc limit %d,%d", (pageno-1)*pagesize, pagesize)
  106. _, err := o.Raw(sql+limit, sqlParams).Values(&rowset)
  107. total := []orm.Params{}
  108. _, err = o.Raw(strings.Replace(sql, "*", "count(1) cnt", 1), sqlParams).Values(&total)
  109. if err != nil {
  110. logger.Logger.Error(err)
  111. return nil, 0, err
  112. }
  113. totalCnt := 0
  114. if len(total) > 0 {
  115. totalCnt, _ = strconv.Atoi(tools.IsEmpty(total[0]["cnt"]))
  116. }
  117. return rowset, totalCnt, err
  118. }
  119. func (c *TaskReportMgr) One(taskid int) (T_data_task_report, error) {
  120. o := orm.NewOrm()
  121. tmp := T_data_task_report{}
  122. if c.Model.Id > 0 {
  123. tmp.Id = c.Model.Id
  124. err := o.Read(&tmp)
  125. return tmp, err
  126. }
  127. rowset := []orm.Params{}
  128. o.Raw("select * from t_data_task_report where task_id=?", taskid).Values(&rowset)
  129. if len(rowset) == 0 {
  130. return tmp, nil
  131. }
  132. tmp.Id, _ = strconv.Atoi(tools.IsEmpty(rowset[0]["id"]))
  133. tmp.Code = tools.IsEmpty(rowset[0]["code"])
  134. tmp.Name = tools.IsEmpty(rowset[0]["name"])
  135. tmp.TaskId = taskid
  136. tmp.Doc = tools.IsEmpty(rowset[0]["doc"])
  137. tmp.State, _ = strconv.Atoi(tools.IsEmpty(rowset[0]["state"]))
  138. return tmp, nil
  139. }
  140. //根据model中指定的id删除检测任务报告
  141. func (c *TaskReportMgr) Delete() (err error) {
  142. dblog := new(SystemLog)
  143. dblog.SetUserInfo(c.GetUserInfo())
  144. dblog.Audittype = enum.AuditType_check_task
  145. dblog.Logtype = enum.LogType_Delete
  146. dblog.Eventtype = enum.OptEventType_Bus
  147. dblog.Eventlevel = enum.OptEventLevel_Hight
  148. db := orm.NewOrm()
  149. doc := ""
  150. if c.Model.Id > 0 {
  151. err = db.Read(&c.Model)
  152. if err != nil {
  153. return err
  154. }
  155. doc = c.Model.Doc
  156. _, err = db.Delete(&c.Model)
  157. }
  158. if c.Model.TaskId > 0 {
  159. lst := []orm.Params{}
  160. db.Raw("select * from t_data_task_report where task_id=?", c.Model.TaskId).Values(&lst)
  161. if len(lst) > 0 {
  162. doc = tools.IsEmpty(lst[0]["doc"])
  163. } else {
  164. return nil
  165. }
  166. _, err = db.Raw("delete from t_data_task_report where task_id=?", c.Model.TaskId).Exec()
  167. }
  168. if err != nil {
  169. logger.Logger.Error(err)
  170. dblog.Description = fmt.Sprintf("删除%s%d失败:%s", modelDesc3, c.Model.TaskId, err.Error())
  171. dblog.Fail2()
  172. } else {
  173. if doc != "" {
  174. os.Remove("./" + doc)
  175. }
  176. dblog.Description = fmt.Sprintf("删除%s%d成功", modelDesc3, c.Model.TaskId)
  177. dblog.Success2()
  178. }
  179. return err
  180. }
  181. func (c *TaskReportMgr) ToWord(taskinfo T_data_task) (path string, err error) {
  182. /*
  183. fileMgr := new(AttachmentMgr)
  184. fileMgr.Model = T_sys_attachment{Id: int32(taskinfo.ReportId)}
  185. fileinfo, err := fileMgr.One()
  186. if err != nil {
  187. return "", err
  188. }
  189. */
  190. scdmgr := new(ScdMgr)
  191. scdParse := new(ScdParse)
  192. scdinfo, _ := scdmgr.One(tools.IsEmpty(taskinfo.ScdId))
  193. scdName := tools.IsEmpty(scdinfo["scd_name"])
  194. sdcXmlObj, _ := scdParse.GetScdXmlObjectBySCDID(tools.IsEmpty(taskinfo.ScdId))
  195. reportPath := strings.Join([]string{".", "static", "download", "report"}, string(os.PathSeparator))
  196. os.MkdirAll(reportPath, fs.ModePerm)
  197. reportFN := reportPath + string(os.PathSeparator) + fmt.Sprintf("%s_%s.%s", c.Model.Code, time.Now().Format("150405"), "xlsx")
  198. logger.Logger.Debug(fmt.Sprintf("正在生成检测报告文件:%s", reportFN))
  199. /*
  200. err = os.Rename(fileinfo.SavePath, reportFN)
  201. if err != nil {
  202. return "", err
  203. }
  204. */
  205. scdRuleResult := new(ScdNodeRule)
  206. scdRuleResult.ScdID = taskinfo.ScdId
  207. result, _, err := scdRuleResult.ResultList("", "", "", "", "", "", 1, 1000000)
  208. if err != nil {
  209. logger.Logger.Error(err)
  210. return "", err
  211. }
  212. //生成报告数据
  213. var file *xlsx.File
  214. file = xlsx.NewFile()
  215. sheet_fcda, err := file.AddSheet("虚端子关系")
  216. if err != nil {
  217. logger.Logger.Error(err)
  218. return "", err
  219. }
  220. sheet_c, err := file.AddSheet("测控装置")
  221. if err != nil {
  222. logger.Logger.Error(err)
  223. return "", err
  224. }
  225. sheet_c.SetColWidth(1, 1, 30)
  226. sheet_c.SetColWidth(3, 3, 80)
  227. sheet_c.SetColWidth(4, 5, 30)
  228. sheet_p, err := file.AddSheet("保护装置")
  229. if err != nil {
  230. logger.Logger.Error(err)
  231. return "", err
  232. }
  233. sheet_p.SetColWidth(1, 1, 30)
  234. sheet_p.SetColWidth(3, 3, 80)
  235. sheet_p.SetColWidth(4, 5, 30)
  236. sheet_i, err := file.AddSheet("智能终端")
  237. if err != nil {
  238. logger.Logger.Error(err)
  239. return "", err
  240. }
  241. sheet_i.SetColWidth(1, 1, 30)
  242. sheet_i.SetColWidth(3, 3, 80)
  243. sheet_i.SetColWidth(4, 5, 30)
  244. sheet_m, err := file.AddSheet("合并单元")
  245. if err != nil {
  246. logger.Logger.Error(err)
  247. return "", err
  248. }
  249. sheet_m.SetColWidth(1, 1, 30)
  250. sheet_m.SetColWidth(3, 3, 80)
  251. sheet_m.SetColWidth(4, 5, 30)
  252. sheet_other, err := file.AddSheet("schema语法和数据模板")
  253. if err != nil {
  254. logger.Logger.Error(err)
  255. return "", err
  256. }
  257. c.setCaption(sheet_other, fmt.Sprintf("%-%", scdName, "语法校验结果"))
  258. //生成标题行
  259. c.addCellValue(sheet_other, []string{"序号", "行号", "等级", "校验结果内容", "应用标准", "标准条款"})
  260. sheet_other.SetColWidth(3, 3, 80)
  261. sheet_other.SetColWidth(4, 5, 30)
  262. //生成报表数据
  263. iedResultMap := map[string][]orm.Params{}
  264. rowInd := 1
  265. for _, row := range result {
  266. ied_name := tools.IsEmpty(row["ied_name"])
  267. if ied_name == "" {
  268. //生成数据行
  269. c.addCellValue(sheet_other, []string{
  270. fmt.Sprintf("%d", rowInd),
  271. tools.IsEmpty(row["line_no"]),
  272. tools.IsEmpty(row["alert_level"]),
  273. tools.IsEmpty(row["parse_result"]),
  274. tools.IsEmpty(row["apply_standard"]),
  275. tools.IsEmpty(row["apply_standard_no"]),
  276. })
  277. rowInd = rowInd + 1
  278. } else {
  279. iedResultMap[ied_name] = append(iedResultMap[ied_name], row)
  280. }
  281. }
  282. crcFilePath := fmt.Sprintf(strings.Join([]string{".", "static", "upload", ""}, string(os.PathSeparator))+"%d.scd.crc", taskinfo.ScdId)
  283. crctext, _ := os.ReadFile(crcFilePath)
  284. crcMap := map[string]string{}
  285. json.Unmarshal(crctext, &crcMap)
  286. scdNodeMgr := new(ScdNode)
  287. for ied_name, lst := range iedResultMap {
  288. iedObj := scdNodeMgr.GetIed(sdcXmlObj, tools.IsEmpty(taskinfo.ScdId), ied_name)
  289. sheetObj := new(xlsx.Sheet)
  290. //生成装置标题行
  291. switch strings.ToUpper(ied_name[0:1]) {
  292. case "C":
  293. sheetObj = sheet_c
  294. c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name))
  295. c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"})
  296. c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "测控", crcMap[ied_name]})
  297. break
  298. case "P":
  299. sheetObj = sheet_p
  300. c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name))
  301. c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"})
  302. c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "保护装置", crcMap[ied_name]})
  303. break
  304. case "I":
  305. sheetObj = sheet_i
  306. c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name))
  307. c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"})
  308. c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "智能终端", crcMap[ied_name]})
  309. break
  310. case "M":
  311. sheetObj = sheet_m
  312. c.setCaption(sheetObj, fmt.Sprintf("%s-装置(%s)校验结果", scdName, ied_name))
  313. c.addCellValue(sheetObj, []string{"装置编号", "装置名称", "厂家", "型号", "类型", "校验码"})
  314. c.addCellValue(sheetObj, []string{ied_name, iedObj.Desc, iedObj.Manufacturer, iedObj.Type, "合并单元", crcMap[ied_name]})
  315. break
  316. default:
  317. continue
  318. }
  319. //装置信息行
  320. c.addCellValue(sheetObj, []string{"序号", "行号", "等级", "校验结果内容", "应用标准", "标准条款"})
  321. //数据行
  322. rowInd := 1
  323. for _, r := range lst {
  324. c.addCellValue(sheetObj, []string{
  325. tools.IsEmpty(rowInd),
  326. tools.IsEmpty(r["line_no"]),
  327. tools.IsEmpty(r["alert_level"]),
  328. tools.IsEmpty(r["parse_result"]),
  329. tools.IsEmpty(r["apply_standard"]),
  330. tools.IsEmpty(r["apply_standard_no"]),
  331. })
  332. rowInd = rowInd + 1
  333. }
  334. }
  335. result = nil
  336. iedResultMap = nil
  337. //生成端子关系检查结果
  338. checkAreaRe := new(CheckAreaMgr)
  339. result, err = checkAreaRe.GetCheckResult(taskinfo.ScdId)
  340. if err != nil {
  341. logger.Logger.Error(err)
  342. return "", err
  343. }
  344. c.setCaption(sheet_fcda, fmt.Sprintf("%s-端子校验结果", scdName), 5)
  345. //汇总结果
  346. scdFileName := ""
  347. if sdcXmlObj.Header != nil {
  348. scdFileName = sdcXmlObj.Header.Id
  349. }
  350. scdVerion := ""
  351. scdMakeDt := "" //scd文件生成日期
  352. scdCrc := "" //scd全站crc
  353. if sdcXmlObj.Header != nil {
  354. if sdcXmlObj.Header.History != nil {
  355. hitem := sdcXmlObj.Header.History.Hitem
  356. if len(hitem) > 0 {
  357. lastHitem := hitem[len(hitem)-1]
  358. scdVerion = lastHitem.Version + "." + lastHitem.Revision
  359. scdMakeDt = strings.ReplaceAll(lastHitem.When, "T", "")
  360. }
  361. }
  362. }
  363. if len(sdcXmlObj.Private) > 0 {
  364. for _, r := range sdcXmlObj.Private {
  365. if r.Type == "Substation virtual terminal conection CRC" {
  366. scdCrc = r.InnerText
  367. break
  368. }
  369. }
  370. }
  371. c.addCellValue(sheet_fcda, []string{"SCD文件名称", scdFileName, "SCD文件版本", scdVerion})
  372. c.addCellValue(sheet_fcda, []string{"SCD文件生成时间", scdMakeDt, "全站虚连接CRC", scdCrc})
  373. totalIed := len(sdcXmlObj.IED) //总ied数
  374. checkIeds, _ := checkAreaRe.GetIedList(taskinfo.ScdId, 0)
  375. checkIedMap := map[string]int{}
  376. for _, r := range checkIeds {
  377. checkIedMap[tools.IsEmpty(r["ied_name"])] = 1
  378. }
  379. c.addCellValue(sheet_fcda, []string{"总IED数目", fmt.Sprintf("%d", totalIed), "参与校核IED数目", fmt.Sprintf("%d", len(checkIedMap))})
  380. totalExtrefs := 0 //总虚连接数目
  381. checkExtrefs := 0 //参与校核虚连接数目
  382. for _, r := range sdcXmlObj.IED {
  383. if r.AccessPoint == nil {
  384. continue
  385. }
  386. for _, r1 := range r.AccessPoint {
  387. if r1.Server == nil {
  388. continue
  389. }
  390. for _, r2 := range r1.Server.LDevice {
  391. if r2.LN0 != nil && r2.LN0.Inputs != nil {
  392. totalExtrefs = totalExtrefs + len(r2.LN0.Inputs.ExtRef)
  393. if checkIedMap[r.Name] == 1 {
  394. checkExtrefs = checkExtrefs + len(r2.LN0.Inputs.ExtRef)
  395. }
  396. }
  397. for _, r3 := range r2.LN {
  398. if r3.Inputs != nil {
  399. totalExtrefs = totalExtrefs + len(r3.Inputs.ExtRef)
  400. if checkIedMap[r.Name] == 1 {
  401. checkExtrefs = checkExtrefs + len(r3.Inputs.ExtRef)
  402. }
  403. }
  404. }
  405. }
  406. }
  407. }
  408. errortype3 := 0 // 多余虚端子
  409. errortype1 := 0 //错误虚端子
  410. errortype2 := 0 //缺失端子
  411. for _, row := range result {
  412. switch tools.IsEmpty(row["error_type"]) {
  413. case "1": //错误
  414. errortype1 = errortype1 + 1
  415. break
  416. case "2": //缺失
  417. errortype2 = errortype2 + 1
  418. break
  419. case "3": //多余
  420. errortype3 = errortype3 + 1
  421. break
  422. }
  423. }
  424. c.addCellValue(sheet_fcda, []string{"总虚连接数目", fmt.Sprintf("%d", totalExtrefs), "参与校核虚连接数目", fmt.Sprintf("%d", checkExtrefs)})
  425. c.addCellValue(sheet_fcda, []string{"未校核虚连接数目", fmt.Sprintf("%d", totalExtrefs-checkExtrefs), "正确虚连接数目", fmt.Sprintf("%d", checkExtrefs-errortype1-errortype2)})
  426. c.addCellValue(sheet_fcda, []string{"多余虚连接数目", fmt.Sprintf("%d", errortype3), "缺失虚连接数目", fmt.Sprintf("%d", errortype2)})
  427. c.addCellValue(sheet_fcda, []string{"错误虚连接数目", fmt.Sprintf("%d", errortype1), "不规范虚连接数目", fmt.Sprintf("%s", "-")})
  428. c.addCellValue(sheet_fcda, []string{"严重问题", fmt.Sprintf("%s", "-"), "规范性问题", fmt.Sprintf("%s", "-")})
  429. c.addCellValue(sheet_fcda, []string{"一般问题", fmt.Sprintf("%s", "-"), "套别错误虚连接数目", fmt.Sprintf("%s", "-")})
  430. c.addCellValue(sheet_fcda, []string{"跨间隔错误虚连接数目", fmt.Sprintf("%s", "-"), "母差支路错误虚连接数目", fmt.Sprintf("%s", "-")})
  431. checkIeds = nil
  432. lastIedName := ""
  433. cellNo := 1
  434. for _, row := range result {
  435. if tools.IsEmpty(row["ied_name"]) == "" || tools.IsEmpty(row["error_type"]) == "9" {
  436. continue
  437. }
  438. nowIedName := fmt.Sprintf("%s", tools.IsEmpty(row["ied_name"]))
  439. if lastIedName == "" || lastIedName != nowIedName {
  440. lastIedName = nowIedName
  441. c.setCaption(sheet_fcda, lastIedName+":"+tools.IsEmpty(row["ied_desc"]), 5)
  442. c.addCellValue(sheet_fcda, []string{"序号", "外部IED", "发送信号", "本IED", "接收信号", "结论"})
  443. cellNo = 1
  444. }
  445. outied := tools.IsEmpty(row["out_ied_name"])
  446. if outied != "" {
  447. outied = fmt.Sprintf("%s:%s", tools.IsEmpty(row["out_ied_name"]), tools.IsEmpty(row["out_ied_desc"]))
  448. }
  449. c.addCellValue(sheet_fcda, []string{
  450. fmt.Sprintf("%d", cellNo),
  451. outied,
  452. fmt.Sprintf("%s\n%s", tools.IsEmpty(row["out_fcda_desc"]), tools.IsEmpty(row["out_fcda_addr"])),
  453. fmt.Sprintf("%s:%s", tools.IsEmpty(row["ied_name"]), tools.IsEmpty(row["ied_desc"])),
  454. fmt.Sprintf("%s\n%s", tools.IsEmpty(row["fcda_desc"]), tools.IsEmpty(row["fcda_addr"])),
  455. tools.IsEmpty(row["error_type_desc"]),
  456. })
  457. cellNo = cellNo + 1
  458. }
  459. sheet_fcda.SetColWidth(0, 1, 15) //单元格宽度
  460. sheet_fcda.SetColWidth(1, 4, 30) //单元格宽度
  461. err = file.Save(reportFN)
  462. if err != nil {
  463. logger.Logger.Error(err)
  464. return "", err
  465. }
  466. return reportFN[1:], err
  467. }
  468. func (c *TaskReportMgr) setCaption(sheet *xlsx.Sheet, caption string, margeNum ...int) *xlsx.Cell {
  469. row := sheet.AddRow()
  470. cell := row.AddCell()
  471. if len(margeNum) > 0 {
  472. cell.HMerge = margeNum[0]
  473. } else {
  474. cell.HMerge = 5 //合并单元格数
  475. }
  476. cell.Value = caption
  477. style := xlsx.NewStyle()
  478. style.Alignment.Horizontal = "center"
  479. style.Font.Bold = true
  480. style.Font.Size = 14
  481. style.Border.Bottom = "solid"
  482. //style.Border.Left = "solid"
  483. style.Border.Right = "solid"
  484. //style.Border.Top = "solid"
  485. cell.SetStyle(style)
  486. return cell
  487. }
  488. func (c *TaskReportMgr) addCellValue(sheet *xlsx.Sheet, vs []string) {
  489. row := sheet.AddRow()
  490. for _, r := range vs {
  491. cell := row.AddCell()
  492. cell.Value = r
  493. style := xlsx.NewStyle()
  494. border := xlsx.Border{
  495. Left: "thin",
  496. Right: "thin",
  497. Top: "thin",
  498. Bottom: "thin",
  499. }
  500. style.Border = border
  501. style.Alignment.Horizontal = "left"
  502. style.Alignment.WrapText = true
  503. style.Font.Size = 12
  504. cell.SetStyle(style)
  505. }
  506. }