This commit is contained in:
2025-07-07 20:11:59 +08:00
parent ab0fdbc447
commit 06e3aa2eb3
2009 changed files with 193082 additions and 0 deletions

View File

@ -0,0 +1,807 @@
// ==========================================================================
// GFast自动生成logic操作代码。
// 生成日期2023-11-01 17:33:04
// 生成路径: internal/app/system/logic/bus_question_save.go
// 生成人gfast
// desc:用户试卷存储
// company:云南奇讯科技有限公司
// ==========================================================================
package logic
import (
"context"
"errors"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/jung-kurt/gofpdf"
"github.com/tiger1103/gfast/v3/api/v1/common/coryCommon"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
wxModel "github.com/tiger1103/gfast/v3/internal/app/wxApplet/model"
"github.com/tiger1103/gfast/v3/library/liberr"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
)
func init() {
service.RegisterBusQuestionSave(New())
}
func New() *sBusQuestionSave {
return &sBusQuestionSave{}
}
type sBusQuestionSave struct{}
//func (s *sBusQuestionSave) WeChatPdfWoFunc(ctx context.Context, req *system.WeChatPdfWoReq) (listRes *system.WeChatPdfWoRes, err error) {
// listRes = new(system.WeChatPdfWoRes)
// err = g.Try(ctx, func(ctx context.Context) {
// mp := make(map[string]*model.ModelWeChatPdfWoRes)
// //0、获取配置信息
// var configurationEntity *model.BusQuestionsConfigurationInfoRes
// err = dao.BusQuestionsConfiguration.Ctx(ctx).Limit(1).Scan(&configurationEntity)
// liberr.ErrIsNil(ctx, err, "查询失败")
// leftjion := ""
// if req.ProjectId > 0 && req.TeamId == 0 { //查项目
// leftjion = "b.openid = a.openid and b.project_id = '" + strconv.FormatInt(req.ProjectId, 10) + "' and b.deleted_at is null"
// }
// if req.ProjectId > 0 && req.TeamId > 0 { //查项目+班组
// leftjion = "b.openid = a.openid and b.project_id = '" + strconv.FormatInt(req.ProjectId, 10) + "' and team_id = '" + strconv.FormatInt(req.TeamId, 10) + "' and b.deleted_at is null"
// }
// //1、获取线上的试卷信息
// var mwor []*model.ModelWeChatPdfWoRes
// m := dao.BusQuestionSave.Ctx(ctx).As("a").Fields(`a.openid,
// b.user_name as userName,
// a.pass,
// (select sum( score ) from bus_question_save WHERE correct = 1 and openid = a.openid) as sumScore,
// c.path,
// a.time_out as timeOut,
// a.take_time as takeTime,
// a.created_at as createdAt`).
// RightJoin("bus_construction_user", "b", leftjion).
// LeftJoin("bus_question_save_pdf", "c", "c.openid = b.openid").
// Where(`a.pass is not null`)
// //if strings.EqualFold(req.IsPaging, "YES") {
// array, err := m.Array()
// listRes.Total = len(array)
// if err != nil {
// liberr.ErrIsNil(ctx, err, "获取总行数失败")
// return
// }
// if req.PageNum == 0 {
// req.PageNum = 1
// }
// listRes.CurrentPage = req.PageNum
// if req.PageSize == 0 {
// req.PageSize = consts.PageSize
// }
// m = m.Page(req.PageNum, req.PageSize)
// //}
// order := "a.created_at"
// if req.OrderBy != "" {
// order = req.OrderBy
// }
// err = m.Order(order).Scan(&mwor)
// for i := range mwor {
// mwor[i].TakeTimeStr = formatTime(mwor[i].TakeTime)
// mwor[i].TimeOutStr = formatTime(mwor[i].TimeOut * 60)
// mwor[i].Type = "1" //pdf
// mp[mwor[i].Openid] = mwor[i]
// }
// //2、获取线下的试卷信息
// var tj = "b.openid = a.openid and b.project_id = '" + strconv.FormatInt(req.ProjectId, 10) + "'"
// if req.TeamId != 0 {
// tj = tj + " and team_id = '" + strconv.FormatInt(req.TeamId, 10) + "'"
// }
// tj = tj + " and b.deleted_at is null"
// var offlineEnitnty []*model.ModelWeChatPdfWoRes
// err = g.DB().Model("bus_question_offline").As("a").
// Fields(
// "a.openid,"+
// "b.user_name as userName,"+
// "concat_ws( ',',a.pass,a.full_mark ) as pass,"+
// "a.score as sumScore,"+
// "a.img as path,").
// LeftJoin("bus_construction_user", "b", tj).Scan(&offlineEnitnty)
// //3、数据信息合并同一个人选取最大分数的试卷信息
// for i := range offlineEnitnty {
// //如果发现有重复的openid那么就选取得分最大的
// mpdata, ok := mp[offlineEnitnty[i].Openid]
// if ok {
// mpdataSplit := strings.Split(mpdata.Pass, ",")
// mpdataFloat, _ := strconv.ParseFloat(mpdataSplit[1], 64)
// mpdataScore, _ := strconv.ParseFloat(mpdata.SumScore, 64)
// mpdataScoreOne := 100.00 / mpdataFloat * mpdataScore
// offlineSplit := strings.Split(offlineEnitnty[i].Pass, ",")
// offlineFloat, _ := strconv.ParseFloat(offlineSplit[1], 64)
// offlineScore, _ := strconv.ParseFloat(offlineEnitnty[i].SumScore, 64)
// offlineScoreTwo := 100.00 / offlineFloat * offlineScore
// if mpdataScoreOne < offlineScoreTwo {
// offlineEnitnty[i].Type = "2" //图片
// mp[offlineEnitnty[i].Openid] = offlineEnitnty[i]
// }
// } else { //没有重复的就直接给
// if offlineEnitnty[i].UserName != "" {
// offlineEnitnty[i].Type = "2" //图片
// mp[offlineEnitnty[i].Openid] = offlineEnitnty[i]
// }
// }
// }
// var r []*model.ModelWeChatPdfWoRes
// for _, v := range mp {
// r = append(r, v)
// }
// listRes.List = r
// liberr.ErrIsNil(ctx, err, "获取数据失败")
// })
// return
//}
func (s *sBusQuestionSave) WeChatPdfWoFunc(ctx context.Context, req *system.WeChatPdfWoReq) (listRes *system.WeChatPdfWoRes, err error) {
listRes = new(system.WeChatPdfWoRes)
err = g.Try(ctx, func(ctx context.Context) {
r, err := WeChatPdfWo(ctx, req)
liberr.ErrIsNil(ctx, err, "获取数据失败")
//排序然后进行代码分页
sortByNames(r)
lenI := len(r)
listRes.Total = lenI
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
var num = req.PageNum*req.PageSize - req.PageSize
var mun = req.PageSize + num
if mun > lenI {
mun = lenI
} else {
mun = req.PageSize + num
}
if req.Name != "" { //有查询条件就从第0个走
r = r[0:mun]
} else {
r = r[num:mun]
}
listRes.List = r
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
func WeChatPdfWo(ctx context.Context, req *system.WeChatPdfWoReq) (r []*model.ModelWeChatPdfWoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
mp := make(map[string]*model.ModelWeChatPdfWoRes)
//0、获取配置信息
var configurationEntity *model.BusQuestionsConfigurationInfoRes
err = dao.BusQuestionsConfiguration.Ctx(ctx).Limit(1).Scan(&configurationEntity)
liberr.ErrIsNil(ctx, err, "查询失败")
//1、获取线上的试卷信息
leftjion := ""
if req.ProjectId > 0 && req.TeamId == 0 { //查项目
leftjion = "a.project_id = '" + strconv.FormatInt(req.ProjectId, 10) + "' and b.user_name like '%" + req.Name + "%'"
}
if req.ProjectId > 0 && req.TeamId > 0 { //查项目+班组
leftjion = "a.project_id = '" + strconv.FormatInt(req.ProjectId, 10) + "' and b.team_id = '" + strconv.FormatInt(req.TeamId, 10) + "' and b.user_name like '%" + req.Name + "%'"
}
//2、获取线下的试卷信息
var tj = "a.project_id = '" + strconv.FormatInt(req.ProjectId, 10) + "' and b.user_name like '%" + req.Name + "%'"
if req.TeamId != 0 {
tj = tj + " and b.team_id = '" + strconv.FormatInt(req.TeamId, 10) + "'"
}
//3、数据合并
var mwor []*model.ModelWeChatPdfWoRes
sql := `SELECT
openid,
user_name AS userName,
pass,
sumScore,
path,
timeOut,
takeTime,
createdAt,
oto
FROM
(
SELECT
a.openid,
b.user_name,
a.pass,
(
SELECT
SUM(score)
FROM
bus_question_save
WHERE
correct = 1
AND openid = a.openid
) AS sumScore,
c.path,
a.time_out AS timeOut,
a.take_time AS takeTime,
a.created_at AS createdAt,
'1' as oto
FROM
bus_question_save AS a
RIGHT JOIN bus_construction_user AS b ON (` + "b.openid = a.openid and b.deleted_at is null" + `)
LEFT JOIN bus_question_save_pdf AS c ON (c.openid = b.openid)
WHERE
` + leftjion + `
AND a.pass IS NOT NULL
AND a.deleted_at IS NULL
AND b.deleted_at IS NULL
UNION ALL
SELECT
a.openid,
b.user_name,
CONCAT_WS(',', a.pass, a.full_mark) AS pass,
a.score AS sumScore,
a.img AS path,
NULL AS timeOut,
NULL AS takeTime,
a.created_at AS createdAt,
'2' as oto
FROM
bus_question_offline AS a
LEFT JOIN bus_construction_user AS b ON (` + "b.openid = a.openid and b.deleted_at is null" + `)
WHERE
` + tj + `
AND b.deleted_at IS NULL
) AS merged_data;`
err := g.DB().Raw(sql).Scan(&mwor)
liberr.ErrIsNil(ctx, err, "获取数据失败")
for i := range mwor {
mwor[i].TakeTimeStr = formatTime(mwor[i].TakeTime)
mwor[i].TimeOutStr = formatTime(mwor[i].TimeOut * 60)
mwor[i].Type = "1" //pdf
mp[mwor[i].Openid] = mwor[i]
}
//3、数据信息合并同一个人选取最大分数的试卷信息
for i := range mwor {
//如果发现有重复的openid那么就选取得分最大的
mpdata, ok := mp[mwor[i].Openid]
if ok {
//mp里面的分数
mpdataSplit := strings.Split(mpdata.Pass, ",")
mpdataFloat, _ := strconv.ParseFloat(mpdataSplit[1], 64)
mpdataScore, _ := strconv.ParseFloat(mpdata.SumScore, 64)
mpdataScoreOne := 100.00 / mpdataFloat * mpdataScore
//当前分数
offlineSplit := strings.Split(mwor[i].Pass, ",")
offlineFloat, _ := strconv.ParseFloat(offlineSplit[1], 64)
offlineScore, _ := strconv.ParseFloat(mwor[i].SumScore, 64)
offlineScoreTwo := 100.00 / offlineFloat * offlineScore
if mpdataScoreOne < offlineScoreTwo {
mwor[i].Type = "2" //图片
mp[mwor[i].Openid] = mwor[i]
}
}
//else { //没有重复的就直接给
// if offlineEnitnty[i].UserName != "" {
// offlineEnitnty[i].Type = "2" //图片
// mp[offlineEnitnty[i].Openid] = offlineEnitnty[i]
// }
//}
}
for _, v := range mp {
if v.UserName != "" {
r = append(r, v)
}
}
})
return
}
// 定义排序函数
func sortByNames(slice []*model.ModelWeChatPdfWoRes) {
// 使用 sort.Slice 函数进行排序
sort.Slice(slice, func(i, j int) bool {
return slice[i].UserName < slice[j].UserName // 按照 name 字段升序排序
})
}
func formatTime(seconds int64) string {
hours := seconds / 3600 // 计算小时数
minutes := (seconds % 3600) / 60 // 计算分钟数
seconds = seconds % 60 // 计算剩余的秒数
var result = ""
if minutes == 0 {
result = fmt.Sprintf("%02d秒", seconds)
} else if hours == 0 {
result = fmt.Sprintf("%02d分%02d秒", minutes, seconds)
} else {
result = fmt.Sprintf("%02d时%02d分%02d秒", hours, minutes, seconds)
}
return result
}
func (s *sBusQuestionSave) PassOrNotFunc(ctx context.Context, openid string) (res *system.PassOrNotRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
res = new(system.PassOrNotRes)
bqs := dao.BusQuestionSave.Ctx(ctx).Where("openid", openid).Safe()
//1、查询及格分和满分
value1, err := bqs.Fields("pass").Value()
if value1 == nil {
res.IsPass = "3"
return
}
liberr.ErrIsNil(ctx, err, "获取信息失败")
//2、查询用户所答对的分数
value2, err := bqs.Fields("sum(score) as sumScore").Where("correct", "1").Value()
liberr.ErrIsNil(ctx, err, "获取信息失败")
//2.5、获取线下考试分数、计算得到最终及格线分数
var offlineEnitnty *model.ModelWeChatPdfWoRes
err = g.DB().Model("bus_question_offline").As("a").
Fields(
"a.openid,"+
"b.user_name as userName,"+
"concat_ws(a.pass,',',a.full_mark) asc pass,"+
"a.score as sumScore,"+
"a.img as path,").
RightJoin(
"bus_construction_user",
"b",
"b.openid = a.openid and b.deleted_at is null").
Where("a.openid", openid).
Scan(&offlineEnitnty)
liberr.ErrIsNil(ctx, err, "获取信息失败")
var scoreOne float64
if offlineEnitnty != nil {
offlineSplit := strings.Split(offlineEnitnty.Pass, ",")
offlineFloat, _ := strconv.ParseFloat(offlineSplit[1], 64)
offlineScore, _ := strconv.ParseFloat(offlineEnitnty.SumScore, 64)
scoreOne = 100.00 / offlineFloat * offlineScore
}
//3、计算上次分数是否及格
split := strings.Split(value1.String(), ",")
fullMark, _ := strconv.ParseFloat(split[1], 64)
passingGrade, _ := strconv.ParseFloat(split[0], 64)
score := 100.00 / fullMark * value2.Float64()
if scoreOne > score {
if scoreOne >= passingGrade {
res.IsPass = "1"
} else {
res.IsPass = "2"
}
res.PdfStr = offlineEnitnty.Path
res.Type = "2" //图片
liberr.ErrIsNil(ctx, err, "获取信息失败")
} else {
if score >= passingGrade {
res.IsPass = "1"
} else {
res.IsPass = "2"
}
//4、返回上传试卷的pdf 供查看
value3, err := g.DB().Model("bus_question_save_pdf").Ctx(ctx).Where("openid", openid).Fields("path").Value()
res.PdfStr = value3.String()
res.Type = "1" //pdf
liberr.ErrIsNil(ctx, err, "获取信息失败")
}
return
})
return
}
func (s *sBusQuestionSave) List(ctx context.Context, req *system.BusQuestionSaveSearchReq) (listRes *system.BusQuestionSaveSearchRes, err error) {
listRes = new(system.BusQuestionSaveSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
m := dao.BusQuestionSave.Ctx(ctx).WithAll()
if req.Id != "" {
m = m.Where(dao.BusQuestionSave.Columns().Id+" = ?", req.Id)
}
if req.Openid != "" {
m = m.Where(dao.BusQuestionSave.Columns().Openid+" = ?", req.Openid)
}
if req.BankId != "" {
m = m.Where(dao.BusQuestionSave.Columns().BankId+" = ?", gconv.Int64(req.BankId))
}
if req.Answer != "" {
m = m.Where(dao.BusQuestionSave.Columns().Answer+" = ?", req.Answer)
}
if req.Correct != "" {
m = m.Where(dao.BusQuestionSave.Columns().Correct+" = ?", req.Correct)
}
if req.Sign != "" {
m = m.Where(dao.BusQuestionSave.Columns().Sign+" = ?", req.Sign)
}
if req.TakeTime != "" {
m = m.Where(dao.BusQuestionSave.Columns().TakeTime+" = ?", gconv.Int64(req.TakeTime))
}
if req.TimeOut != "" {
m = m.Where(dao.BusQuestionSave.Columns().TimeOut+" = ?", gconv.Int(req.TimeOut))
}
if req.Pass != "" {
m = m.Where(dao.BusQuestionSave.Columns().Pass+" = ?", req.Pass)
}
if len(req.DateRange) != 0 {
m = m.Where(dao.BusQuestionSave.Columns().CreatedAt+" >=? AND "+dao.BusQuestionSave.Columns().CreatedAt+" <=?", req.DateRange[0], req.DateRange[1])
}
listRes.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
order := "id desc"
if req.OrderBy != "" {
order = req.OrderBy
}
var res []*model.BusQuestionSaveInfoRes
err = m.Fields(system.BusQuestionSaveSearchRes{}).Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
listRes.List = make([]*model.BusQuestionSaveListRes, len(res))
for k, v := range res {
listRes.List[k] = &model.BusQuestionSaveListRes{
Id: v.Id,
Openid: v.Openid,
BankId: v.BankId,
Answer: v.Answer,
Correct: v.Correct,
Score: v.Score,
Sign: v.Sign,
TakeTime: v.TakeTime,
TimeOut: v.TimeOut,
Pass: v.Pass,
CreatedAt: v.CreatedAt,
}
}
})
return
}
func (s *sBusQuestionSave) GetById(ctx context.Context, id int64) (res *model.BusQuestionSaveInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.BusQuestionSave.Ctx(ctx).WithAll().Where(dao.BusQuestionSave.Columns().Id, id).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取信息失败")
})
return
}
func (s *sBusQuestionSave) Add(ctx context.Context, req *system.BusQuestionSaveAddReq) (res *system.BusQuestionSaveAddRes, err error) {
res = new(system.BusQuestionSaveAddRes)
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
err = g.Try(ctx, func(ctx context.Context) {
// 获取当前用户所在的项目,将试卷与项目进行绑定(复制人员迁移将试卷也带到另外一个项目)
project, projectErr := dao.BusConstructionUser.Ctx(ctx).Where(dao.BusConstructionUser.Columns().Openid, req.Openid).Fields("project_id").Value()
if projectErr != nil {
liberr.ErrIsNil(ctx, errors.New("无法确认当前用户所在项目!"))
return
}
/**
第零部分:获取分数进行判断,判断是否存储此次试卷
*/
var scoreOne = 0.00 //第一次分数
var scoreTwo = 0.00 //当前考试的分数
type spEntity struct {
SumScore float64 `p:"sumScore"`
Pass string `p:"pass"`
Sign string `p:"sign"`
}
var sp *spEntity
err = dao.BusQuestionSave.Ctx(ctx).Fields("sum( score ) AS sumScore,"+
"( SELECT pass FROM bus_question_save WHERE openid = '"+req.Openid+"' AND deleted_at IS NULL ORDER BY id asc LIMIT 1) as pass,"+"( SELECT sign FROM bus_question_save WHERE openid = '"+req.Openid+"' AND deleted_at IS NULL ORDER BY id asc LIMIT 1) as sign").
Where("correct", "1").
Where("openid", req.Openid).Scan(&sp)
if err == nil {
if sp.Pass != "" {
split := strings.Split(sp.Pass, ",")
float1, _ := strconv.ParseFloat(split[1], 64)
scoreOne = 100.00 / float1 * sp.SumScore
}
} else {
return
}
/**
第一部分:计算分数、存储
*/
//1、获取配置信息
var configurationEntity *model.BusQuestionsConfigurationInfoRes
err = dao.BusQuestionsConfiguration.Ctx(ctx).Limit(1).Scan(&configurationEntity)
liberr.ErrIsNil(ctx, err, "添加失败")
////3、图片上传
//str, err := coryCommon.UploadFile(ctx, req.Sign, coryCommon.Helmet)
//3、获取当前openid的签名如果没有就提示“未查询到签名信息”
var signature *wxModel.BusConstructiomUserSignatureRes
err := g.DB().Model("bus_constructiom_user_signature").Where("openid", req.Openid).Scan(&signature)
liberr.ErrIsNil(ctx, err, "添加失败")
if signature == nil {
err = errors.New("未查询到签名信息")
liberr.ErrIsNil(ctx, err)
return
}
//4、存储用户答题信息
var bqs []*do.BusQuestionSave
var fenshu = 0.0
var number = 0
for iii, data := range req.List {
var correct = ""
var pass = ""
//获取题库的正确答案,然后和用户的答案作对比
var bqb *model.BusQuestionBankInfoRes
err = dao.BusQuestionBank.Ctx(ctx).WherePri(data.BankId).Scan(&bqb)
if err != nil {
err = errors.New("您的试卷被外星人卷走了!")
liberr.ErrIsNil(ctx, err)
return
} else {
if data.Answer == "" {
err = errors.New("您还有题未答完!")
liberr.ErrIsNil(ctx, err)
return
}
if strings.Contains(strings.ToLower(bqb.CorrectAnswer), strings.ToLower(data.Answer)) {
//if bqb.CorrectAnswer == data.Answer {
correct = "1"
fenshu = fenshu + data.Score
number = number + 1
} else {
correct = "2"
}
}
//记录这次的及格线和总分
float1 := strconv.FormatFloat(configurationEntity.PassingScore, 'f', -1, 64)
float2 := strconv.FormatFloat(configurationEntity.FullMark, 'f', -1, 64)
pass = float1 + "," + float2
var bqsTwo = &do.BusQuestionSave{
Openid: req.Openid,
BankId: data.BankId,
Answer: data.Answer,
Correct: correct,
Score: data.Score,
ProjectId: project,
}
if iii == 0 { //这几条数据只在每张试卷的第一条数据中存储(重复的没必要每条都存储)
//bqsTwo.Sign = str
bqsTwo.TakeTime = req.TakeTime
bqsTwo.TimeOut = configurationEntity.AnswerTime
bqsTwo.Pass = pass
}
bqs = append(bqs, bqsTwo)
}
scoreTwo = 100.00 / configurationEntity.FullMark * fenshu
//6、返回数据
res.AnswerTime = configurationEntity.AnswerTime
res.TakeTime = req.TakeTime
res.FullMark = configurationEntity.FullMark
res.PassingScore = configurationEntity.PassingScore
res.Score = fenshu
res.Number = number
//7、两次卷子的分数对比,第一次的分数比第二次大那么第二次只返回结果;第二次的分数比第一次大那么删除第一次的数据再重新插入
if scoreOne > scoreTwo {
return
} else {
//上面是比对
//2、先查询当前用户是否有答题有就把之前的删除(真删)
value, _ := g.DB().Model("bus_question_save_pdf").Ctx(ctx).Where("openid", req.Openid).Limit(1).Fields("path").Value()
if value != nil {
//os.Remove(coryCommon.GetCWD() + "/" + sp.Sign) //删除签名
coryCommon.BatchFile(strings.Split(value.String(), ",")) //删除pdf
_, err = g.DB().Model("bus_question_save_pdf").Ctx(ctx).Where("openid", req.Openid).Delete()
_, err = dao.BusQuestionSave.Ctx(ctx).Unscoped().Where("openid", req.Openid).Delete()
}
_, err = dao.BusQuestionSave.Ctx(ctx).Insert(bqs)
}
/**
第二部分生成pdf试卷
*/
//1、组装数据
var we []*model.WoEntity
//获取 单选、多选、判断
err = dao.BusQuestionSave.Ctx(ctx).As("a").Fields(`
c.question_type,
c.question_text,
c.options,
a.answer,
c.correct_answer,
a.correct,
a.score,
a.sign,
a.id,
a.pass,
b.user_name`).
LeftJoin(`(SELECT openid,user_name from bus_construction_user where deleted_at is null) as b on a.openid = CONVERT(b.openid USING utf8)`).
LeftJoin(`(SELECT id,question_type,question_text,options,correct_answer from bus_question_bank ) as c on a.bank_id = c.id`).
Where("a.openid", req.Openid).OrderAsc("a.id").Scan(&we)
if len(we) > 0 {
value, _ := dao.BusQuestionSave.Ctx(ctx).Where("openid", req.Openid).Where("correct", "1").Fields("sum(score)").Value()
s := configurationEntity.SingleChoice
m := configurationEntity.MultipleChoice
e := configurationEntity.Estimate
var rs *model.ExaminationPaperRes
rs = &model.ExaminationPaperRes{
UserName: we[0].UserName,
Pass: we[0].Pass,
SumScore: value.String(),
Sign: signature.Signature,
Openid: req.Openid,
}
var one = new(model.ExaminationPaperOne)
var two = new(model.ExaminationPaperOne)
var three = new(model.ExaminationPaperOne)
one.Topic = "一、单选题,共" + strconv.Itoa(s) + "道题,每小题" + strconv.FormatFloat(configurationEntity.SingleScore, 'f', -1, 64) + "分,共计" + strconv.FormatFloat(float64(s)*configurationEntity.SingleScore, 'f', -1, 64) + "分"
two.Topic = "二、多选题,共" + strconv.Itoa(m) + "道题,每小题" + strconv.FormatFloat(configurationEntity.MultipleScore, 'f', -1, 64) + "分,共计" + strconv.FormatFloat(float64(m)*configurationEntity.MultipleScore, 'f', -1, 64) + "分"
three.Topic = "三、判断题,共" + strconv.Itoa(e) + "道题,每小题" + strconv.FormatFloat(configurationEntity.EstimateScore, 'f', -1, 64) + "分,共计" + strconv.FormatFloat(float64(e)*configurationEntity.EstimateScore, 'f', -1, 64) + "分"
var sEntity []*model.ExaminationPaperTwo
var mEntity []*model.ExaminationPaperTwo
var eEntity []*model.ExaminationPaperTwo
for _, data := range we {
var sy *model.ExaminationPaperTwo
sy = &model.ExaminationPaperTwo{
QuestionText: data.QuestionText,
Options: data.Options,
Answer: data.Answer,
CorrectAnswer: data.CorrectAnswer,
Correct: data.Correct,
Score: data.Score,
}
if data.QuestionType == "1" {
sEntity = append(sEntity, sy)
} else if data.QuestionType == "2" {
mEntity = append(mEntity, sy)
} else if data.QuestionType == "3" {
eEntity = append(eEntity, sy)
}
}
one.List = sEntity
two.List = mEntity
three.List = eEntity
rs.Single = one
rs.Multiple = two
rs.Estimate = three
path, errPath := Wo(rs)
if errPath != nil {
errPath = errors.New("生成PDF试卷出现了意外请重新提交")
liberr.ErrIsNil(ctx, errPath)
return
} else {
path = strings.Replace(path, "resource/public", "/wxfile", 1)
_, err = g.DB().Insert(ctx, "bus_question_save_pdf", gdb.Map{
"openid": req.Openid,
"path": path,
})
res.PdfStr = path
}
}
liberr.ErrIsNil(ctx, err, "添加失败")
})
return err
})
return
}
func (s *sBusQuestionSave) Delete(ctx context.Context, ids []int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.BusQuestionSave.Ctx(ctx).Delete(dao.BusQuestionSave.Columns().Id+" in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}
func DeleteFunc(ctx context.Context, openidArr []string) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
//1、查询需要删除的pdf
value, _ := g.DB().Model("bus_question_save_pdf").Ctx(ctx).Where("openid in (?)", openidArr).Fields("path").Array()
for i := range value {
coryCommon.BatchFile(strings.Split(value[i].String(), ",")) //删除pdf
}
//2、删除存储pdf的数据信息
_, err = g.DB().Model("bus_question_save_pdf").Ctx(ctx).Where("openid in (?)", openidArr).Delete()
liberr.ErrIsNil(ctx, err, "安全考试-删除pdf试卷失败")
//3、删除用户存储的试卷信息
_, err = dao.BusQuestionSave.Ctx(ctx).Unscoped().Where("openid in (?)", openidArr).Delete()
liberr.ErrIsNil(ctx, err, "安全考试-删除用户试卷信息失败")
//4、删除线下安全考试的用户信息
_, err := g.DB().Model("bus_question_offline").Where("openid in (?)", openidArr).Delete()
liberr.ErrIsNil(ctx, err, "安全考试-线下数据删除失败")
})
return
}
// Wo 导出试卷PDF
func Wo(rs *model.ExaminationPaperRes) (path string, err error) {
//1、创建pdf 并新增pdf页
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
//2、设置字体 分别为不加粗和加粗
//fontStr := coryCommon.GetCWD() + "/resource/font/simhei.ttf"
fontStr := "/resource/font/simhei.ttf"
pdf.AddUTF8Font("simhei", "", fontStr)
pdf.AddUTF8Font("simheiB", "B", fontStr)
// 标题居中加粗
pdf.SetFont("simheiB", "B", 36)
pdf.CellFormat(190, 10, "中煤科工安全考试A卷", "0", 1, "C", false, 0, "")
pdf.Ln(10)
// 姓名、总分、实际得分
pdf.SetFont("simhei", "", 16)
pdf.CellFormat(63, 10, "姓名: "+rs.UserName, "0", 0, "L", false, 0, "")
pdf.CellFormat(63, 10, "及格线/总分: "+rs.Pass, "0", 0, "L", false, 0, "")
pdf.CellFormat(63, 10, "实际得分: "+rs.SumScore, "0", 1, "L", false, 0, "")
pdf.Ln(6)
//内容
for i := 1; i <= 3; i++ {
var ep = new(model.ExaminationPaperOne)
if i == 1 {
ep = rs.Single
} else if i == 2 {
ep = rs.Multiple
} else if i == 3 {
ep = rs.Estimate
}
//大题 单选、多选、判断
pdf.SetFont("simhei", "", 20)
pdf.CellFormat(190, 10, ep.Topic, "0", 1, "L", false, 0, "")
pdf.SetFont("simhei", "", 12)
for iTwo, data := range ep.List {
//小题
if i == 3 {
pdf.MultiCell(0, 5, strconv.Itoa(iTwo+1)+"、"+data.QuestionText+" "+data.Answer+" ", "", "", false)
} else {
pdf.MultiCell(0, 5, strconv.Itoa(iTwo+1)+"、"+Bracket(data.QuestionText, data.Answer), "", "", false)
}
split := strings.Split(data.Options, "@")
num := len(split)
for j, dataTwo := range split {
//选项
pdf.SetX(20)
pdf.MultiCell(0, 5, dataTwo, "", "", false)
if j == num-1 {
if data.Correct == "2" {
pdf.SetTextColor(255, 0, 0) // 设置文字颜色为红色
pdf.SetX(20)
pdf.CellFormat(190, 10, "正确答案为:"+data.CorrectAnswer, "0", 1, "L", false, 0, "")
pdf.SetTextColor(35, 35, 35) // 设置文字颜色为红色
}
pdf.Ln(3)
}
}
}
}
//签字
pdf.Ln(20)
pdf.SetX(120)
pdf.SetFont("simheiB", "B", 16)
pdf.CellFormat(15, 10, "签字:", "0", 0, "L", false, 0, "")
//嵌入图片
pdf.TransformBegin()
pdf.TransformRotate(90, pdf.GetX(), pdf.GetY()) // 逆时针旋转 45 度
imageOptions := gofpdf.ImageOptions{ImageType: "png", ReadDpi: false}
getwd, err := os.Getwd()
getwd = filepath.ToSlash(getwd)
pathSign := getwd + "/" + rs.Sign
pdf.ImageOptions(pathSign, pdf.GetX()-10, pdf.GetY(), 24, 0, true, imageOptions, 0, "")
pdf.TransformEnd()
//导出pdf
fn := coryCommon.FileName("pdf")
str := coryCommon.Ynr(coryCommon.Helmet)
path = filepath.ToSlash(str + fn + ".pdf")
err = pdf.OutputFileAndClose(getwd + "/" + path)
return
}
func Bracket(str string, replace string) (rn string) {
rn = ""
// 定义正则表达式模式,匹配不同的括号格式
re := regexp.MustCompile(`\s*\s*\s*`)
// 使用正则表达式替换所有匹配的括号格式为"abc"
rn = re.ReplaceAllString(str, " "+replace+" ")
return
}