123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670 |
- package handler
- import (
- webServerEntity "cicv-data-closedloop/amd64/web_server/entity"
- "cicv-data-closedloop/common/config/c_db"
- "cicv-data-closedloop/common/config/c_log"
- commonEntity "cicv-data-closedloop/common/entity"
- "cicv-data-closedloop/common/util"
- "fmt"
- "github.com/gin-gonic/gin"
- "github.com/signintech/gopdf"
- "io"
- "log"
- "math"
- "net/http"
- "os"
- "strconv"
- "sync"
- "time"
- )
- var (
- defaultTime = time.Date(2006, time.January, 2, 15, 4, 5, 0, time.Local)
- cacheMutex sync.Mutex
- cacheTeamName = make(map[string]time.Time)
- heartBeatTimeThreshold = 5 * time.Second // 心跳时间
- InitialPositionX = 456292.00 // todo 需要比赛确认起点
- InitialPositionY = 4397957.00 // todo 需要比赛确认起点
- // todo 比赛阶段
- trialBegin = time.Date(2024, time.June, 16, 13, 00, 00, 0, time.Local)
- trialEnd = time.Date(2024, time.June, 19, 23, 59, 59, 0, time.Local)
- )
- // 考试心跳
- func Tick(c *gin.Context) {
- param := new(webServerEntity.ExamPao)
- // 映射到结构体
- if err := c.ShouldBindJSON(¶m); err != nil {
- c_log.GlobalLogger.Error("请求体解析失败,错误信息为:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "请求体解析失败。",
- })
- return
- }
- teamName := param.TeamName
- positionX, _ := strconv.ParseFloat(param.PositionX, 64)
- var positionY float64
- numStr := param.PositionY
- _, _ = fmt.Sscanf(numStr, "%e", &positionY)
- if !util.ContainsKey(cacheTeamName, teamName) && math.Abs(positionX-InitialPositionX) < 5.00 && math.Abs(positionY-InitialPositionY) < 5.00 { // (在起点开始)
- sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-insert-begin_time-and-topic-by-team_name.sql"])
- stage := "表演赛"
- if time.Now().After(trialBegin) && time.Now().Before(trialEnd) {
- stage = "预赛"
- } else {
- stage = "决赛"
- }
- competitionBegin := time.Now()
- cacheTeamName[teamName] = competitionBegin
- c_log.GlobalLogger.Infof("当前比赛阶段为 %v ,队伍 %v 在起始点范围内第一次启动,保存新一条比赛记录的开始时间 %v", stage, teamName, competitionBegin)
- if err := c_db.DoTx(sqlTemplate, []any{param.TeamName, stage, competitionBegin}); err != nil {
- c_log.GlobalLogger.Error("保存比赛开始时间报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{Code: 500, Msg: "保存比赛开始时间报错。"})
- return
- }
- } else if !util.ContainsKey(cacheTeamName, teamName) && math.Abs(positionX-InitialPositionX) > 5.00 || math.Abs(positionY-InitialPositionY) > 5.00 { // 不在起点(开始)
- // 车辆不是在起点启动的自动驾驶模式
- selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-latest-by-team_name.sql"])
- if err != nil {
- c_log.GlobalLogger.Error("读取sql文件报错:", err)
- return
- }
- // 可以传参数
- var result []webServerEntity.ExamPo
- if err = c_db.MysqlDb.Select(&result, selectSql, teamName); err != nil {
- c_log.GlobalLogger.Error("数据库查询报错:", err)
- return
- }
- if len(result) == 1 {
- c_log.GlobalLogger.Info("上一条数据记录为:", result[0])
- }
- // 添加队伍名到缓存中
- cacheTeamName[teamName] = time.Now()
- // 更新记录结束时间为默认时间
- sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-update-end_time-by-team_name.sql"])
- if err = c_db.DoTx(sqlTemplate, []any{
- defaultTime,
- teamName,
- }); err != nil {
- c_log.GlobalLogger.Error("插入数据报错:", err)
- return
- }
- c_log.GlobalLogger.Infof("队伍 %v 的考试在中途中断后重新开始。", teamName)
- } else if util.ContainsKey(cacheTeamName, teamName) { // 进行中
- cacheTeamName[teamName] = time.Now()
- } else {
- c_log.GlobalLogger.Errorf("接收到心跳信息但考试并未开始,队伍名字为 %s,x坐标为 %.f,y坐标为 %.f ", teamName, positionX, positionY)
- }
- c.JSON(http.StatusOK, commonEntity.Response{
- Code: 200,
- Msg: "心跳接收成功。",
- })
- }
- func ExamEndTicker() {
- // 创建一个定时器,每隔一秒触发一次
- ticker := time.NewTicker(1 * time.Second)
- for {
- select {
- // 定时器触发时执行的代码
- case <-ticker.C:
- cacheMutex.Lock()
- {
- var keysToDelete []string
- for teamName, heartBeatTime := range cacheTeamName {
- if time.Since(heartBeatTime) > heartBeatTimeThreshold { // 检查缓存中的队名,如果超过心跳时间,则代表考试结束,删除缓存中的队名
- keysToDelete = append(keysToDelete, teamName)
- }
- }
- for _, teamName := range keysToDelete { // 检查缓存中的队名,如果超过心跳时间,则代表考试结束,删除缓存中的队名
- delete(cacheTeamName, teamName)
- // 1 查询指定队伍的开始时间最新的考试是否有结束时间,如果有则不在处理,如果没有则更新
- var result []webServerEntity.ExamPo
- selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-latest-by-team_name.sql"])
- if err != nil {
- c_log.GlobalLogger.Error("读取sql文件报错:", err)
- return
- }
- // 可以传参数
- if err = c_db.MysqlDb.Select(&result, selectSql, teamName); err != nil {
- c_log.GlobalLogger.Error("数据库查询报错:", err)
- return
- }
- c_log.GlobalLogger.Info("数据库查询成功:", result)
- if !result[0].EndTime.Equal(defaultTime) {
- c_log.GlobalLogger.Error("赛队", teamName, "考试已结束!")
- return
- }
- // 更新到数据库
- sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-update-end_time-by-team_name.sql"])
- if err := c_db.DoTx(sqlTemplate, []any{
- time.Now(),
- teamName,
- }); err != nil {
- c_log.GlobalLogger.Error("插入数据报错:", err)
- return
- }
- c_log.GlobalLogger.Infof("队伍 %v 的考试结束。", teamName)
- }
- }
- cacheMutex.Unlock()
- }
- }
- }
- // 考试开始时间
- func Begin(c *gin.Context) {
- param := new(webServerEntity.ExamPao)
- // 映射到结构体
- if err := c.ShouldBindJSON(¶m); err != nil {
- c_log.GlobalLogger.Error("项目启动接收请求参数报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "请求体解析失败。",
- })
- return
- }
- // 插入到数据库
- sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-insert-begin_time-by-team_name.sql"])
- c_log.GlobalLogger.Info("插入比赛开始时间", sqlTemplate)
- if err := c_db.DoTx(sqlTemplate, []any{
- param.TeamName,
- time.Now(),
- }); err != nil {
- c_log.GlobalLogger.Error("插入数据报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "插入数据报错。",
- })
- return
- }
- c.JSON(http.StatusOK, commonEntity.Response{
- Code: 200,
- Msg: "插入数据成功。",
- })
- }
- // 考试结束时间
- func End(c *gin.Context) {
- param := new(webServerEntity.ExamPao)
- // 映射到结构体
- if err := c.ShouldBindJSON(¶m); err != nil {
- c_log.GlobalLogger.Error("项目启动接收请求参数报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "请求体解析失败。",
- })
- return
- }
- // 1 查询指定队伍的开始时间最新的考试是否有结束时间,如果有则不在处理,如果没有则更新
- var result []webServerEntity.ExamPo
- selectSql, err := util.ReadFile(c_db.SqlFilesMap["exam-select-latest-by-team_name.sql"])
- if err != nil {
- c_log.GlobalLogger.Error("读取sql文件报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "读取sql文件报错。",
- })
- return
- }
- // 可以传参数
- if err = c_db.MysqlDb.Select(&result, selectSql, param.TeamName); err != nil {
- c_log.GlobalLogger.Error("数据库查询报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "数据库查询报错。",
- })
- return
- }
- c_log.GlobalLogger.Info("数据库查询成功:", result)
- if !result[0].EndTime.Equal(defaultTime) {
- c_log.GlobalLogger.Error("赛队", param.TeamName, "重复请求考试结束接口!")
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "重复请求。",
- })
- return
- }
- // 更新到数据库
- sqlTemplate, _ := util.ReadFile(c_db.SqlFilesMap["exam-update-end_time-by-team_name.sql"])
- if err := c_db.DoTx(sqlTemplate, []any{
- time.Now(),
- param.TeamName,
- }); err != nil {
- c_log.GlobalLogger.Error("插入数据报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "插入数据报错。",
- })
- return
- }
- c.JSON(http.StatusOK, commonEntity.Response{
- Code: 200,
- Msg: "插入数据成功。",
- })
- }
- // 分页查询
- // todo 如果日期为默认值,则返回空""
- func Page(c *gin.Context) {
- param := new(webServerEntity.ExamPagePao)
- _ = c.ShouldBindJSON(¶m)
- var resultPos []webServerEntity.ExamPo
- var resultPosTotal []int
- var pageSql string
- var totalSql string
- offset := (param.CurrentPage - 1) * param.PageSize
- size := param.PageSize
- if param.TeamName == "" && param.Topic == "" {
- pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page.sql"])
- totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total.sql"])
- err := c_db.MysqlDb.Select(&resultPos, pageSql, offset, size)
- if err != nil {
- c_log.GlobalLogger.Error(err)
- }
- err = c_db.MysqlDb.Select(&resultPosTotal, totalSql)
- if err != nil {
- c_log.GlobalLogger.Error(err)
- }
- }
- if param.TeamName != "" && param.Topic == "" {
- pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page-by-team_name.sql"])
- totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total-by-team_name.sql"])
- _ = c_db.MysqlDb.Select(&resultPos, pageSql, "%"+param.TeamName+"%", offset, size)
- _ = c_db.MysqlDb.Select(&resultPosTotal, totalSql, "%"+param.TeamName+"%")
- }
- if param.TeamName == "" && param.Topic != "" {
- pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page-by-topic.sql"])
- totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total-by-topic.sql"])
- _ = c_db.MysqlDb.Select(&resultPos, pageSql, "%"+param.Topic+"%", offset, size)
- _ = c_db.MysqlDb.Select(&resultPosTotal, totalSql, "%"+param.Topic+"%")
- }
- if param.TeamName != "" && param.Topic != "" {
- pageSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-page-by-team_name-and-topic.sql"])
- totalSql, _ = util.ReadFile(c_db.SqlFilesMap["exam-select-total-by-team_name-and-topic.sql"])
- _ = c_db.MysqlDb.Select(&resultPos, pageSql, "%"+param.TeamName+"%", "%"+param.Topic+"%", offset, size)
- _ = c_db.MysqlDb.Select(&resultPosTotal, totalSql, "%"+param.TeamName+"%", "%"+param.Topic+"%")
- }
- var resultVos []webServerEntity.ExamVo
- for _, po := range resultPos {
- resultVos = append(resultVos, webServerEntity.ExamVo{
- Id: po.Id,
- TeamName: po.TeamName,
- Topic: po.Topic,
- BeginTime: util.GetTimeString(po.BeginTime),
- EndTime: util.GetTimeString(po.EndTime),
- ScoreOnline: po.ScoreOnline,
- ScoreOffline: po.ScoreOffline,
- ScoreFinal: po.ScoreFinal,
- Details: po.Details,
- ScoreReportPath: po.ScoreReportPath,
- })
- }
- c.JSON(http.StatusOK, commonEntity.Response{
- Code: 200,
- Msg: "分页查询成功!",
- Data: resultVos,
- Total: resultPosTotal[0],
- })
- }
- // 评分报告pdf下载
- func Report(c *gin.Context) {
- param := new(webServerEntity.ExamReportPao)
- // 映射到结构体
- if err := c.ShouldBindJSON(¶m); err != nil {
- c_log.GlobalLogger.Error("接收请求参数报错:", err)
- c.JSON(http.StatusBadRequest, commonEntity.Response{
- Code: 500,
- Msg: "请求体解析失败。",
- })
- return
- }
- layout := "2006-01-02 15:04:05"
- beginTime, _ := time.Parse(layout, param.BeginTime)
- endTime, _ := time.Parse(layout, param.EndTime)
- // 1 根据ID查询数据
- // 2 根据数据生成pdf
- // 3 创建pdf文件
- {
- // 初始化 pdf 对象
- pdf := gopdf.GoPdf{}
- pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
- // 添加字体文件到pdf
- err := pdf.AddTTFFont("simfang", "D:\\code\\cicv-data-closedloop\\amd64\\web_server\\simfang.ttf")
- if err != nil {
- log.Print(err.Error())
- return
- }
- leftMargin := 70.0
- topMargin := 100.0
- lineHeight := 25.0
- tableWidth := 450.0
- pdf.SetLeftMargin(leftMargin) // 设置左边距
- alignOptionText := gopdf.CellOption{Align: gopdf.Left | gopdf.Middle}
- //alignOptionText2 := gopdf.CellOption{Align: gopdf.Center | gopdf.Middle}
- alignOptionTable := gopdf.CellOption{Align: gopdf.Center | gopdf.Middle, Border: gopdf.Left | gopdf.Right | gopdf.Bottom | gopdf.Top}
- alignOptionTable2 := gopdf.CellOption{Align: gopdf.Left | gopdf.Middle}
- // ------- 封面页 -------
- pdf.AddPage()
- {
- err = pdf.SetFont("simfang", "", 36)
- err = pdf.Image("D:\\code\\cicv-data-closedloop\\amd64\\web_server\\background.png", 0, 0, nil) // 背景图片
- err = pdf.Image("D:\\code\\cicv-data-closedloop\\amd64\\web_server\\logo.png", 20, 20, &gopdf.Rect{W: 320, H: 100})
- {
- pdf.SetXY(100, 250)
- _ = pdf.Text("车路云一体化算法挑战赛")
- }
- {
- pdf.SetXY(220, 315) // 200
- _ = pdf.Text("评分报告")
- }
- _ = pdf.SetFont("simfang", "", 14)
- currentLine := 0.0
- tableCellWidth := 100.0
- tableLeftMartin := 190.0
- tableTopMartin := 500.0
- {
- {
- pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "赛队编号:", alignOptionTable2)
- }
- {
- pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, param.TeamName, alignOptionTable2)
- }
- currentLine++
- }
- {
- {
- pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "评测车型:", alignOptionTable2)
- }
- {
- pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "多功能车平台", alignOptionTable2)
- }
- currentLine++
- }
- {
- {
- pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "评测地点:", alignOptionTable2)
- }
- {
- pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "天津生态城", alignOptionTable2)
- }
- currentLine++
- }
- {
- {
- pdf.SetXY(tableLeftMartin, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, "报告时间:", alignOptionTable2)
- }
- {
- pdf.SetXY(tableLeftMartin+1.0*tableCellWidth, tableTopMartin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: 100, H: lineHeight}, time.Now().Format("2006年01月02日"), alignOptionTable2)
- }
- currentLine++
- }
- {
- pdf.SetXY(165, 775)
- _ = pdf.Cell(nil, "国汽(北京)智能网联汽车研究院有限公司")
- }
- }
- // todo 先不要目录页
- //// ------- 目录页 -------
- //{
- // pdf.AddPage()
- // currentLine := 0.0
- // {
- // err = pdf.SetFont("simfang", "", 18)
- // pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- // _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "目录", alignOptionText2)
- // currentLine++
- // currentLine++
- // }
- // {
- // err = pdf.SetFont("simfang", "", 14)
- // pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- // currentLine++
- // _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "1. 总体情况 ............................... 1", alignOptionText)
- // }
- //}
- // ------- 详情页 第一页 -------
- {
- pdf.AddPage()
- currentLine := 0.0
- // 1. 总体分数情况
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "1. 总体分数情况", alignOptionText)
- currentLine++
- }
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "整体得分:"+util.ToString(param.ScoreFinal), alignOptionText)
- currentLine++
- }
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "线上得分:"+util.ToString(param.ScoreFinal), alignOptionText)
- currentLine++
- }
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "线下得分:", alignOptionText)
- currentLine++
- }
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "整体耗时:"+endTime.Sub(beginTime).String(), alignOptionText)
- currentLine++
- }
- }
- // 2. 分数详情
- {
- columnNumber := 4.0 // 列数
- tableCellWidth := tableWidth / columnNumber // 单元格宽度
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "2. 分数详情", alignOptionText)
- currentLine++
- }
- // 分数详情表格
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "序号", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "场景名称", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "线上得分", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+3.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "线下得分", alignOptionTable)
- }
- currentLine++
- }
- for i := 0; i < 10; i++ {
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, util.ToString(i+1), alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+3.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- currentLine++
- }
- }
- }
- }
- // ------- 详情页 第二页 -------
- {
- pdf.AddPage()
- currentLine := 0.0
- // 3. 线上扣分详情
- {
- columnNumber := 3.0 // 列数
- tableCellWidth := tableWidth / columnNumber // 单元格宽度
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "3. 线上扣分详情", alignOptionText)
- currentLine++
- }
- for i := 0; i < 5; i++ {
- // 场景1
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "("+util.ToString(i+1)+")xxxx场景", alignOptionText)
- currentLine++
- }
- // 场景1 表格
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "序号", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分点", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分说明", alignOptionTable)
- }
- currentLine++
- }
- for j := 0; j < 2; j++ {
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, util.ToString(j+1), alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- currentLine++
- }
- }
- }
- }
- }
- }
- // ------- 详情页 第三页 -------
- size := 10
- if size > 5 {
- pdf.AddPage()
- currentLine := 0.0
- // 3. 线上扣分详情
- {
- columnNumber := 3.0 // 列数
- tableCellWidth := tableWidth / columnNumber // 单元格宽度
- for i := 5; i < 10; i++ {
- // 场景1
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "("+util.ToString(i+1)+")xxxx场景", alignOptionText)
- currentLine++
- }
- // 场景1 表格
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "序号", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分点", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "扣分说明", alignOptionTable)
- }
- currentLine++
- }
- for j := 0; j < 2; j++ {
- {
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, util.ToString(j+1), alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+1.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- {
- pdf.SetXY(leftMargin+2.0*tableCellWidth, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableCellWidth, H: lineHeight}, "xxx", alignOptionTable)
- }
- currentLine++
- }
- }
- }
- }
- }
- // 4 作品优化建议
- {
- pdf.SetXY(leftMargin, topMargin+currentLine*lineHeight)
- _ = pdf.CellWithOption(&gopdf.Rect{W: tableWidth, H: lineHeight}, "4. 作品优化建议", alignOptionText)
- currentLine++
- }
- }
- // ------- 附录页 -------
- pdf.AddPage()
- {
- pdf.SetXY(leftMargin, topMargin)
- _ = pdf.Text("附件:评分规则")
- pdf.AddExternalLink("https://www.baidu.com/", leftMargin, topMargin-lineHeight, 6*14, lineHeight)
- }
- // 写入本地
- pdf.WritePdf("D:\\hello.pdf")
- }
- // 打开要发送的文件
- file, err := os.Open("D:\\hello.pdf")
- if err != nil {
- c.String(http.StatusNotFound, "文件未找到")
- return
- }
- defer file.Close()
- // 将文件复制到响应主体
- _, err = io.Copy(c.Writer, file)
- if err != nil {
- c.String(http.StatusInternalServerError, "无法复制文件到响应体")
- return
- }
- }
|