mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-05 07:50:23 +08:00
104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
package global
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"strconv"
|
|
|
|
sql "github.com/FloatTech/sqlite"
|
|
"github.com/fumiama/go-docx"
|
|
)
|
|
|
|
var (
|
|
ErrInvalidGenerateConfig = errors.New("invalid generate config")
|
|
ErrMajorTooLarge = errors.New("major too large")
|
|
ErrNoEnoughQuestionToMatchRequire = errors.New("no enough question to match require")
|
|
ErrRateLimitExceeded = errors.New("rate limit exceeded")
|
|
)
|
|
|
|
// GenerateConfig 试卷生成配置
|
|
type GenerateConfig struct {
|
|
Distribution map[string]uint // Distribution is map[majorname]subcount
|
|
RateLimit float64 // RateLimit 重复率上限
|
|
YearStart StudyYear // YearStart 起始年份(空则直到最旧)
|
|
YearEnd StudyYear // YearEnd 截止年份(空则直到最新)
|
|
TypeMask PaperType // TypeMask & File.Type != 0 则匹配
|
|
}
|
|
|
|
// GenerateFile 用一些限定条件生成新试卷, 云端不保存
|
|
func (f *FileDatabase) GenerateFile(config *GenerateConfig) (*docx.Docx, error) {
|
|
if config == nil || config.Distribution == nil || len(config.Distribution) == 0 {
|
|
return nil, ErrInvalidGenerateConfig
|
|
}
|
|
if len(config.Distribution) > 10 {
|
|
return nil, ErrMajorTooLarge
|
|
}
|
|
docf := docx.NewA4()
|
|
f.mu.RLock()
|
|
defer f.mu.RUnlock()
|
|
for n, c := range config.Distribution {
|
|
if c == 0 {
|
|
continue
|
|
}
|
|
docf.AddParagraph().AddText(string([]rune("一二三四五六七八九十")[c]) + "、" + n).Size("44").Bold()
|
|
cond := " WHERE"
|
|
hasfront := false
|
|
if config.YearStart > 0 {
|
|
cond += " Year>=" + strconv.Itoa(int(config.YearStart))
|
|
hasfront = true
|
|
}
|
|
if config.YearEnd > 0 {
|
|
if hasfront {
|
|
cond += " AND"
|
|
}
|
|
cond += " Year<=" + strconv.Itoa(int(config.YearStart))
|
|
hasfront = true
|
|
}
|
|
if hasfront {
|
|
cond += " AND"
|
|
}
|
|
cond += " (Type&" + strconv.Itoa(int(config.TypeMask)) + ")!=0"
|
|
ques, err := sql.QueryAll[Question](&f.db,
|
|
"SELECT * FROM "+FileTableQuestion+
|
|
" WHERE FileID IN (SELECT FileID FROM "+
|
|
FileTableFile+cond+
|
|
") ORDER BY RANDOM() limit "+strconv.Itoa(int(c))+";",
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(ques) != int(c) {
|
|
return nil, ErrNoEnoughQuestionToMatchRequire
|
|
}
|
|
rate := 0.0
|
|
for _, q := range ques {
|
|
rate += q.MaxDuplicateRate()
|
|
}
|
|
rate /= float64(len(ques))
|
|
if rate > config.RateLimit {
|
|
return nil, ErrRateLimitExceeded
|
|
}
|
|
for i, q := range ques {
|
|
lst, err := sql.Find[List](&f.db, FileTableFile, "WHERE ID="+strconv.Itoa(q.ListID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
quesfile, err := os.Open(q.Path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stat, err := quesfile.Stat()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
docq, err := docx.Parse(quesfile, stat.Size())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
docf.AddParagraph().AddText(strconv.Itoa(i+1) + ". (" + lst.Desc + ")")
|
|
docf.AppendFile(docq)
|
|
}
|
|
}
|
|
return docf, nil
|
|
}
|