mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-05 07:50:23 +08:00
finish getFileList getFilePercent and part of analyzeFile
This commit is contained in:
@@ -85,8 +85,8 @@ func init() {
|
|||||||
|
|
||||||
// File stores to paper/Class/2022-2023学年/第一学期/期末/A/xxx.docx
|
// File stores to paper/Class/2022-2023学年/第一学期/期末/A/xxx.docx
|
||||||
type File struct {
|
type File struct {
|
||||||
ID uint64 // ID is the first 8 bytes of the original file's md5
|
ID int64 // ID is the first 8 bytes of the original file's md5
|
||||||
ListID int // ListID is the foreign key to List(ID)
|
ListID int // ListID is the foreign key to List(ID)
|
||||||
Year StudyYear
|
Year StudyYear
|
||||||
Type PaperType
|
Type PaperType
|
||||||
Date uint32 // Date is the yyyymmdd of 考试日期
|
Date uint32 // Date is the yyyymmdd of 考试日期
|
||||||
@@ -115,6 +115,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
if !user.IsFileManager() && !istemp {
|
if !user.IsFileManager() && !istemp {
|
||||||
return nil, ErrInvalidRole
|
return nil, ErrInvalidRole
|
||||||
}
|
}
|
||||||
|
progress(1)
|
||||||
lst, err := sql.Find[List](&FileDB.db, FileTableList, "WHERE ID="+strconv.Itoa(lstid))
|
lst, err := sql.Find[List](&FileDB.db, FileTableList, "WHERE ID="+strconv.Itoa(lstid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -128,13 +129,14 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer docf.Close()
|
defer docf.Close()
|
||||||
|
progress(2)
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
_, err = io.Copy(h, docf)
|
_, err = io.Copy(h, docf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var buf [md5.Size]byte
|
var buf [md5.Size]byte
|
||||||
id := binary.LittleEndian.Uint64(h.Sum(buf[:0]))
|
id := int64(binary.LittleEndian.Uint64(h.Sum(buf[:0])))
|
||||||
_, err = docf.Seek(0, io.SeekStart)
|
_, err = docf.Seek(0, io.SeekStart)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -144,10 +146,12 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sz := stat.Size()
|
sz := stat.Size()
|
||||||
|
progress(3)
|
||||||
doc, err := docx.Parse(docf, sz)
|
doc, err := docx.Parse(docf, sz)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
progress(5)
|
||||||
doc.Document.Body.DropDrawingOf("NilPicture")
|
doc.Document.Body.DropDrawingOf("NilPicture")
|
||||||
majorre, err := regexp.Compile(reg.Major)
|
majorre, err := regexp.Compile(reg.Major)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -157,6 +161,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
if len(docs) < 2 {
|
if len(docs) < 2 {
|
||||||
return nil, ErrMajorSplitsTooShort
|
return nil, ErrMajorSplitsTooShort
|
||||||
}
|
}
|
||||||
|
progress(9)
|
||||||
// filling File struct
|
// filling File struct
|
||||||
file := &File{
|
file := &File{
|
||||||
ID: id,
|
ID: id,
|
||||||
@@ -186,6 +191,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
progress(10)
|
||||||
for _, it := range docs[0].Document.Body.Items {
|
for _, it := range docs[0].Document.Body.Items {
|
||||||
if p, ok := it.(*docx.Paragraph); ok {
|
if p, ok := it.(*docx.Paragraph); ok {
|
||||||
text := p.String()
|
text := p.String()
|
||||||
@@ -206,8 +212,8 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
class := classre.FindStringSubmatch(text)
|
class := classre.FindStringSubmatch(text)
|
||||||
if len(class) >= 2 {
|
if len(class) >= 3 {
|
||||||
file.Class = class[1]
|
file.Class = class[2]
|
||||||
}
|
}
|
||||||
opcl := opclre.FindStringSubmatch(text)
|
opcl := opclre.FindStringSubmatch(text)
|
||||||
if len(opcl) >= 2 {
|
if len(opcl) >= 2 {
|
||||||
@@ -216,7 +222,10 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
date := datere.FindStringSubmatch(text)
|
date := datere.FindStringSubmatch(text)
|
||||||
if len(date) >= 4 {
|
if len(date) >= 4 {
|
||||||
y, m, d := date[1], date[2], date[3]
|
y, m, d := date[1], date[2], date[3]
|
||||||
if y != "" && m != "" && d != "" {
|
if y != "" && m != "" {
|
||||||
|
if d == "" {
|
||||||
|
d = "1"
|
||||||
|
}
|
||||||
yyyy, err := strconv.ParseUint(y, 10, 64)
|
yyyy, err := strconv.ParseUint(y, 10, 64)
|
||||||
if err == nil && yyyy > 1600 {
|
if err == nil && yyyy > 1600 {
|
||||||
mm, err := strconv.ParseUint(m, 10, 64)
|
mm, err := strconv.ParseUint(m, 10, 64)
|
||||||
@@ -237,11 +246,12 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rate := ratere.FindStringSubmatch(text)
|
rate := ratere.FindStringSubmatch(text)
|
||||||
if len(rate) >= 2 {
|
if len(rate) >= 3 {
|
||||||
file.Rate = rate[1]
|
file.Rate = rate[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
progress(19)
|
||||||
if file.Class == "" || strings.Contains(file.Class, "..") {
|
if file.Class == "" || strings.Contains(file.Class, "..") {
|
||||||
return nil, ErrEmptyClass
|
return nil, ErrEmptyClass
|
||||||
}
|
}
|
||||||
@@ -250,12 +260,12 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
filebasepath = PaperFolder + "temp/" + strconv.Itoa(*user.ID) + "/"
|
filebasepath = PaperFolder + "temp/" + strconv.Itoa(*user.ID) + "/"
|
||||||
} else {
|
} else {
|
||||||
filebasepath = fmt.Sprintf(
|
filebasepath = fmt.Sprintf(
|
||||||
PaperFolder+file.Class+"/%v/%v/%v/%v/",
|
PaperFolder+file.Class+"/%v/%v/%v/%c/",
|
||||||
file.Year, file.Type.FirstSecond(), file.Type.MiddleFinal(), file.Type.AB(),
|
file.Year, file.Type.FirstSecond(), file.Type.MiddleFinal(), file.Type.AB(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
lst.Path = filebasepath
|
questionpath := filebasepath + "questions/"
|
||||||
err = os.MkdirAll(filebasepath, 0755)
|
err = os.MkdirAll(questionpath, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -266,7 +276,19 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
filequestions := make([]QuestionJSON, 0, len(docs))
|
filequestions := make([]QuestionJSON, 0, len(docs))
|
||||||
|
lst.QuesC = 0
|
||||||
|
progress(20)
|
||||||
|
p := uint(20)
|
||||||
|
delta := uint(70 / len(docs))
|
||||||
|
if delta == 0 {
|
||||||
|
delta = 1
|
||||||
|
}
|
||||||
for _, majordoc := range docs {
|
for _, majordoc := range docs {
|
||||||
|
p += delta
|
||||||
|
if p > 90 {
|
||||||
|
p = 90
|
||||||
|
}
|
||||||
|
progress(p)
|
||||||
majorq := QuestionJSON{}
|
majorq := QuestionJSON{}
|
||||||
for _, it := range majordoc.Document.Body.Items {
|
for _, it := range majordoc.Document.Body.Items {
|
||||||
if p, ok := it.(*docx.Paragraph); ok {
|
if p, ok := it.(*docx.Paragraph); ok {
|
||||||
@@ -280,6 +302,10 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
subdocs := majordoc.SplitByParagraph(docx.SplitDocxByPlainTextRegex(subre))
|
subdocs := majordoc.SplitByParagraph(docx.SplitDocxByPlainTextRegex(subre))
|
||||||
|
if len(subdocs) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
subdocs = subdocs[1:]
|
||||||
majorq.Sub = make([]QuestionJSON, 0, len(subdocs))
|
majorq.Sub = make([]QuestionJSON, 0, len(subdocs))
|
||||||
for _, subdoc := range subdocs {
|
for _, subdoc := range subdocs {
|
||||||
sb := bytes.NewBuffer(make([]byte, 0, 4096))
|
sb := bytes.NewBuffer(make([]byte, 0, 4096))
|
||||||
@@ -288,7 +314,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
}
|
}
|
||||||
m := md5.Sum(sb.Bytes())
|
m := md5.Sum(sb.Bytes())
|
||||||
que := &Question{
|
que := &Question{
|
||||||
ID: binary.LittleEndian.Uint64(m[:8]),
|
ID: int64(binary.LittleEndian.Uint64(m[:8])),
|
||||||
Plain: base14.BytesToString(sb.Bytes()),
|
Plain: base14.BytesToString(sb.Bytes()),
|
||||||
Images: func() []byte {
|
Images: func() []byte {
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
@@ -340,7 +366,9 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
}
|
}
|
||||||
v := make(map[string]uint8, len(words)*2)
|
v := make(map[string]uint8, len(words)*2)
|
||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
v[word]++
|
if word != "" && word != "\n" && word != " " {
|
||||||
|
v[word]++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(v)
|
data, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -361,7 +389,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var buf [8]byte
|
var buf [8]byte
|
||||||
binary.LittleEndian.PutUint64(buf[:], q.ID)
|
binary.LittleEndian.PutUint64(buf[:], uint64(q.ID))
|
||||||
dupmap[hex.EncodeToString(buf[:])] = r
|
dupmap[hex.EncodeToString(buf[:])] = r
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -372,11 +400,11 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
w := bytes.NewBuffer(make([]byte, 0, 65536))
|
w := bytes.NewBuffer(make([]byte, 0, 65536))
|
||||||
_, err = subdoc.WriteTo(w)
|
_, err = subdoc.WriteTo(w)
|
||||||
var buf [8]byte
|
var buf [8]byte
|
||||||
binary.LittleEndian.PutUint64(buf[:], que.ID)
|
binary.LittleEndian.PutUint64(buf[:], uint64(que.ID))
|
||||||
queidstr := hex.EncodeToString(buf[:])
|
queidstr := hex.EncodeToString(buf[:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
m5 := md5.Sum(w.Bytes())
|
m5 := md5.Sum(w.Bytes())
|
||||||
quepath := filebasepath + hex.EncodeToString(m5[:]) + ".docx"
|
quepath := questionpath + hex.EncodeToString(m5[:]) + ".docx"
|
||||||
f, err := os.Create(quepath)
|
f, err := os.Create(quepath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
_, _ = io.Copy(f, w)
|
_, _ = io.Copy(f, w)
|
||||||
@@ -420,9 +448,29 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
filequestions = append(filequestions, majorq)
|
filequestions = append(filequestions, majorq)
|
||||||
|
lst.QuesC += len(majorq.Sub)
|
||||||
}
|
}
|
||||||
|
progress(90)
|
||||||
file.Questions, _ = json.Marshal(filequestions)
|
file.Questions, _ = json.Marshal(filequestions)
|
||||||
lst.Path += file.Class + ".docx"
|
_, err = docf.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lst.Path = filebasepath + file.Class + ".docx"
|
||||||
|
lst.HasntAnalyzed = false
|
||||||
|
lst.Desc = fmt.Sprintf("%s%v%v%v%c卷",
|
||||||
|
file.Class, file.Year, file.Type.FirstSecond(), file.Type.MiddleFinal(), file.Type.AB(),
|
||||||
|
)
|
||||||
|
dstf, err := os.Create(lst.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer dstf.Close()
|
||||||
|
_, err = io.Copy(dstf, docf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
progress(95)
|
||||||
FileDB.mu.Lock()
|
FileDB.mu.Lock()
|
||||||
if istemp {
|
if istemp {
|
||||||
err = FileDB.db.Insert(FileTableTempFile, file)
|
err = FileDB.db.Insert(FileTableTempFile, file)
|
||||||
@@ -433,6 +481,7 @@ func (f *FileDatabase) AddFile(lstid int, reg *Regex, istemp bool, progress func
|
|||||||
}
|
}
|
||||||
_ = FileDB.db.Insert(FileTableList, &lst)
|
_ = FileDB.db.Insert(FileTableList, &lst)
|
||||||
FileDB.mu.Unlock()
|
FileDB.mu.Unlock()
|
||||||
|
progress(100)
|
||||||
return file, err
|
return file, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,7 +494,7 @@ type QuestionJSON struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Question struct {
|
type Question struct {
|
||||||
ID uint64 // ID is the first 8 bytes of the Plain's md5
|
ID int64 // ID is the first 8 bytes of the Plain's md5
|
||||||
Path string // Path is the question's docx position
|
Path string // Path is the question's docx position
|
||||||
Plain string // Plain is the plain text of the question (like markdown format)
|
Plain string // Plain is the plain text of the question (like markdown format)
|
||||||
Images []byte // Images is json of the image dhash in XML, ex. ['rId1': '1234567890abcdef', ...]
|
Images []byte // Images is json of the image dhash in XML, ex. ['rId1': '1234567890abcdef', ...]
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -15,17 +17,21 @@ var (
|
|||||||
|
|
||||||
// List of file path
|
// List of file path
|
||||||
type List struct {
|
type List struct {
|
||||||
ID *int // ID is self-inc
|
ID *int // ID is self-inc
|
||||||
Uploader int // Uploader is uid
|
Uploader int // Uploader is uid
|
||||||
UpTime int64 // UpTime is upload time (unix timestamp)
|
UpName string // UpName is uploader's name
|
||||||
Size int64 // Size of the original file
|
UpTime int64 // UpTime is upload time (unix timestamp)
|
||||||
IsTemp bool // IsTemp whether file is temp
|
Size int64 // Size of the original file
|
||||||
Path string // Path of file
|
QuesC int // QuesC 总小题数
|
||||||
|
HasntAnalyzed bool // HasntAnalyzed whether file has been analyzed
|
||||||
|
IsTemp bool // IsTemp whether file is temp
|
||||||
|
Path string `db:"Path,UNIQUE"` // Path of file, unique
|
||||||
|
Desc string // Desc is file's description
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveFileToTemp copy file to PaperFolder/tmp/uploader/name and add record into list.
|
// SaveFileToTemp copy file to PaperFolder/tmp/uploader/name and add record into list.
|
||||||
func (f *FileDatabase) SaveFileToTemp(uploader int, file io.Reader, name string) (err error) {
|
func (f *FileDatabase) SaveFileToTemp(uploader int, file io.Reader, name string) (id int, err error) {
|
||||||
_, err = UserDB.GetUserByID(uploader)
|
user, err := UserDB.GetUserByID(uploader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -38,12 +44,16 @@ func (f *FileDatabase) SaveFileToTemp(uploader int, file io.Reader, name string)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lst := List{
|
fpath := tmpdir + "/" + name
|
||||||
Uploader: uploader,
|
FileDB.mu.RLock()
|
||||||
UpTime: time.Now().Unix(),
|
lst, _ := sql.Find[List](&FileDB.db, FileTableList, "WHERE Path='"+fpath+"'")
|
||||||
IsTemp: true,
|
FileDB.mu.RUnlock()
|
||||||
Path: tmpdir + "/" + name,
|
lst.Uploader = uploader
|
||||||
}
|
lst.UpName = user.Name
|
||||||
|
lst.UpTime = time.Now().Unix()
|
||||||
|
lst.HasntAnalyzed = true
|
||||||
|
lst.IsTemp = true
|
||||||
|
lst.Path = fpath
|
||||||
ff, err := os.Create(lst.Path)
|
ff, err := os.Create(lst.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -58,5 +68,24 @@ func (f *FileDatabase) SaveFileToTemp(uploader int, file io.Reader, name string)
|
|||||||
FileDB.mu.Lock()
|
FileDB.mu.Lock()
|
||||||
err = FileDB.db.Insert(FileTableList, &lst)
|
err = FileDB.db.Insert(FileTableList, &lst)
|
||||||
FileDB.mu.Unlock()
|
FileDB.mu.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if lst.ID != nil {
|
||||||
|
id = *lst.ID
|
||||||
|
return
|
||||||
|
}
|
||||||
|
FileDB.mu.RLock()
|
||||||
|
err = FileDB.db.Find(FileTableList, &lst, "WHERE Path='"+fpath+"'")
|
||||||
|
FileDB.mu.RUnlock()
|
||||||
|
id = *lst.ID
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListUploadedFile will select all file that HasntAnalyzed && IsTemp or !HasntAnalyzed && !IsTemp
|
||||||
|
func (f *FileDatabase) ListUploadedFile() (lst []*List, err error) {
|
||||||
|
FileDB.mu.RLock()
|
||||||
|
lst, err = sql.FindAll[List](&FileDB.db, FileTableList, "WHERE (HasntAnalyzed AND IsTemp) OR (NOT HasntAnalyzed AND NOT IsTemp) ORDER BY UpTime DESC")
|
||||||
|
FileDB.mu.RUnlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ type Regex struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newRegex() (reg Regex) {
|
func newRegex() (reg Regex) {
|
||||||
reg.Title = `.*(\d{4})\s*-.*学年.*(\d?).*([中末]?).*([AB]?)\s*卷`
|
reg.Title = `.*(\d{4})\s*-.*学年.*(\d).*([中末]).*([AB]?)\s*卷`
|
||||||
reg.Class = `考试科目:\s*(\S+)\s*`
|
reg.Class = `(考试科目|课程名称):\s*(\S+)\s*`
|
||||||
reg.OpenCl = `考试形式:\s*(\S+)\s*`
|
reg.OpenCl = `考试形式:\s*(\S+)\s*`
|
||||||
reg.Date = `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d+)\s*日`
|
reg.Date = `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d*)\s*日`
|
||||||
reg.Time = `考试时长:\s*(\d+)\s*分钟`
|
reg.Time = `考试时长:\s*(\d+)\s*分钟`
|
||||||
reg.Rate = `成绩构成比例:\s*(.*%)\s*`
|
reg.Rate = `(成绩构成比例|课程成绩构成):\s*(.*%)\s*`
|
||||||
reg.Major = `([一二三四五六七八九十]+)、\s*(.*)\s*(.*([空题]?)\s*(\d*).*共\s*(\d+)\s*分.*)`
|
reg.Major = `([一二三四五六七八九十]+)、\s*(.*)\s*(.*([空题]?)\s*(\d*).*共\s*(\d+)\s*分.*)`
|
||||||
reg.Sub = `(\d+)、`
|
reg.Sub = `(\d+)、`
|
||||||
return
|
return
|
||||||
@@ -77,5 +77,6 @@ func (u *UserDatabase) GetUserRegex(id int) (*Regex, error) {
|
|||||||
u.mu.RLock()
|
u.mu.RLock()
|
||||||
_ = u.db.Find(UserTableRegex, ®, "WHERE ID="+strconv.Itoa(id))
|
_ = u.db.Find(UserTableRegex, ®, "WHERE ID="+strconv.Itoa(id))
|
||||||
u.mu.RUnlock()
|
u.mu.RUnlock()
|
||||||
|
reg.ID = *user.ID
|
||||||
return ®, nil
|
return ®, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ type User struct {
|
|||||||
Role UserRole
|
Role UserRole
|
||||||
Date int64 // Date is the creating date's unix timestamp
|
Date int64 // Date is the creating date's unix timestamp
|
||||||
Pswd string
|
Pswd string
|
||||||
Last int64 // Last is the last password reseting unix timestamp
|
Last int64 // Last is the last password reseting unix timestamp
|
||||||
Name string
|
Name string `db:"Name,UNIQUE"`
|
||||||
Nick string
|
Nick string
|
||||||
Avtr string // Avtr is the user's avatar, typically a image url
|
Avtr string // Avtr is the user's avatar, typically a image url
|
||||||
Cont string // Cont is the user's contact, ex. phone number
|
Cont string // Cont is the user's contact, ex. phone number
|
||||||
|
|||||||
145
backend/paper.go
145
backend/paper.go
@@ -1,13 +1,158 @@
|
|||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
|
"github.com/FloatTech/ttl"
|
||||||
"github.com/fumiama/paper-manager/backend/global"
|
"github.com/fumiama/paper-manager/backend/global"
|
||||||
"github.com/fumiama/paper-manager/backend/utils"
|
"github.com/fumiama/paper-manager/backend/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
chineseYYMMDDLayout = "2006年01月02日"
|
||||||
|
)
|
||||||
|
|
||||||
|
// analyzeper 分析进度缓存
|
||||||
|
var analyzeper = ttl.NewCache[int, uint](time.Hour)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNoAnalyzePermission = errors.New("no analyze permission")
|
||||||
|
)
|
||||||
|
|
||||||
|
type filelist struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Desc string `json:"description"`
|
||||||
|
Size float64 `json:"size"`
|
||||||
|
Ques int `json:"questions"`
|
||||||
|
Auth string `json:"author"`
|
||||||
|
Date string `json:"datetime"`
|
||||||
|
Per uint `json:"percent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
apimap["/api/getFileList"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
token := r.Header.Get("Authorization")
|
||||||
|
user := usertokens.Get(token)
|
||||||
|
if user == nil {
|
||||||
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
count := -1
|
||||||
|
var err error
|
||||||
|
countstr := r.URL.Query().Get("count")
|
||||||
|
if countstr != "" {
|
||||||
|
count, err = strconv.Atoi(countstr)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lst, err := global.FileDB.ListUploadedFile()
|
||||||
|
if err != nil && err != sql.ErrNullResult {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if count > 0 && len(lst) > count {
|
||||||
|
lst = lst[:count]
|
||||||
|
}
|
||||||
|
result := make([]filelist, len(lst))
|
||||||
|
for i, v := range lst {
|
||||||
|
result[i].ID = *v.ID
|
||||||
|
j := strings.LastIndex(v.Path, "/")
|
||||||
|
if j <= 0 {
|
||||||
|
result[i].Title = v.Path
|
||||||
|
} else {
|
||||||
|
result[i].Title = v.Path[j+1:]
|
||||||
|
}
|
||||||
|
result[i].Desc = v.Desc
|
||||||
|
result[i].Size = float64(v.Size) / 1024 / 1024 // MB
|
||||||
|
result[i].Ques = v.QuesC
|
||||||
|
result[i].Auth = v.UpName
|
||||||
|
result[i].Date = time.Unix(v.UpTime, 0).Format(chineseYYMMDDLayout)
|
||||||
|
if !v.HasntAnalyzed {
|
||||||
|
result[i].Per = 100
|
||||||
|
} else {
|
||||||
|
result[i].Per = analyzeper.Get(*v.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, &result, messageOk, typeSuccess)
|
||||||
|
}}
|
||||||
|
apimap["/api/getFilePercent"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
token := r.Header.Get("Authorization")
|
||||||
|
user := usertokens.Get(token)
|
||||||
|
if user == nil {
|
||||||
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
idstr := r.URL.Query().Get("id")
|
||||||
|
if idstr == "" {
|
||||||
|
writeresult(w, codeError, nil, "empty id", typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := strconv.Atoi(idstr)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, analyzeper.Get(id), messageOk, typeSuccess)
|
||||||
|
}}
|
||||||
|
apimap["/api/analyzeFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
token := r.Header.Get("Authorization")
|
||||||
|
user := usertokens.Get(token)
|
||||||
|
if user == nil {
|
||||||
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
istemp := r.URL.Query().Get("permanent") != "true"
|
||||||
|
if !user.IsFileManager() && !istemp {
|
||||||
|
writeresult(w, codeError, nil, errNoAnalyzePermission.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
idstr := r.URL.Query().Get("id")
|
||||||
|
if idstr == "" {
|
||||||
|
writeresult(w, codeError, nil, "empty id", typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id, err := strconv.Atoi(idstr)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reg, err := global.UserDB.GetUserRegex(*user.ID)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch := make(chan struct{}, 1)
|
||||||
|
type message struct {
|
||||||
|
M string `json:"msg"`
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
_, err = global.FileDB.AddFile(id, reg, istemp, func(u uint) { analyzeper.Set(id, u) })
|
||||||
|
ch <- struct{}{}
|
||||||
|
close(ch)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
writeresult(w, codeSuccess, &message{M: "正在分析, 请耐心等待..."}, messageOk, typeSuccess)
|
||||||
|
return
|
||||||
|
case <-ch:
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, &message{M: "分析完成"}, messageOk, typeSuccess)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
// PaperHandler serves protected contents in global.FileFolder
|
// PaperHandler serves protected contents in global.FileFolder
|
||||||
func PaperHandler(w http.ResponseWriter, r *http.Request) {
|
func PaperHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if !utils.IsMethod("GET", w, r) {
|
if !utils.IsMethod("GET", w, r) {
|
||||||
|
|||||||
@@ -114,12 +114,12 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeresult(w, codeError, nil, "invalid filename", typeError)
|
writeresult(w, codeError, nil, "invalid filename", typeError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = global.FileDB.SaveFileToTemp(*user.ID, ff, fn)
|
id, err := global.FileDB.SaveFileToTemp(*user.ID, ff, fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writeresult(w, codeError, nil, err.Error(), typeError)
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeresult(w, codeSuccess, "上传"+fn+"成功", messageOk, typeSuccess)
|
writeresult(w, codeSuccess, id, messageOk, typeSuccess)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != http.ErrMissingFile {
|
if err != http.ErrMissingFile {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { resultError, resultSuccess, getRequestToken, requestParams } from '../_
|
|||||||
|
|
||||||
const deletedIDs: number[] = []
|
const deletedIDs: number[] = []
|
||||||
|
|
||||||
const analyzingIDs: { id: number; per: number }[] = []
|
// const analyzingIDs: { id: number; per: number }[] = []
|
||||||
|
|
||||||
function createFileList() {
|
/*function createFileList() {
|
||||||
const lst: any[] = []
|
const lst: any[] = []
|
||||||
for (let i = 100; i > 0; i--) {
|
for (let i = 100; i > 0; i--) {
|
||||||
if (deletedIDs.includes(i)) continue
|
if (deletedIDs.includes(i)) continue
|
||||||
@@ -21,11 +21,11 @@ function createFileList() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return lst
|
return lst
|
||||||
}
|
}*/
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
// mock get filelist
|
// mock get filelist
|
||||||
{
|
/*{
|
||||||
url: '/api/getFileList',
|
url: '/api/getFileList',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -40,8 +40,8 @@ export default [
|
|||||||
}
|
}
|
||||||
return resultSuccess(fl)
|
return resultSuccess(fl)
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
{
|
/*{
|
||||||
url: '/api/getFilePercent',
|
url: '/api/getFilePercent',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -69,7 +69,7 @@ export default [
|
|||||||
percent: 100,
|
percent: 100,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
url: '/api/delFile',
|
url: '/api/delFile',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
@@ -85,7 +85,7 @@ export default [
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
/*{
|
||||||
url: '/api/analyzeFile',
|
url: '/api/analyzeFile',
|
||||||
timeout: 1000,
|
timeout: 1000,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -99,5 +99,5 @@ export default [
|
|||||||
msg: '正在分析' + id + ', 请耐心等待...',
|
msg: '正在分析' + id + ', 请耐心等待...',
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
] as MockMethod[]
|
] as MockMethod[]
|
||||||
|
|||||||
@@ -35,8 +35,11 @@ export const delFile = (id: number) => {
|
|||||||
/**
|
/**
|
||||||
* @description: Analyze file
|
* @description: Analyze file
|
||||||
*/
|
*/
|
||||||
export const analyzeFile = (id: number) => {
|
export const analyzeFile = (id: number, permanent: boolean) => {
|
||||||
return defHttp.get<AnalyzeFile>({ url: Api.AnalyzeFile, params: { id: id } })
|
return defHttp.get<AnalyzeFile>(
|
||||||
|
{ url: Api.AnalyzeFile, params: { id: id, permanent: permanent } },
|
||||||
|
{ errorMessageMode: 'none' },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface UploadApiResult {
|
export interface UploadApiResult {
|
||||||
message: string
|
message: string
|
||||||
code: number
|
code: number
|
||||||
url: string
|
result: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,6 @@
|
|||||||
{{ fileList.length }}
|
{{ fileList.length }}
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<a-button @click="openPreviewModal">
|
|
||||||
<Icon icon="bi:eye" />
|
|
||||||
<template v-if="fileList.length && showPreviewNumber">
|
|
||||||
{{ fileList.length }}
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Space>
|
</Space>
|
||||||
<UploadModal
|
<UploadModal
|
||||||
@@ -26,18 +20,10 @@
|
|||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
@delete="handleDelete"
|
@delete="handleDelete"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<UploadPreviewModal
|
|
||||||
:value="fileList"
|
|
||||||
@register="registerPreviewModal"
|
|
||||||
@list-change="handlePreviewChange"
|
|
||||||
@delete="handlePreviewDelete"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref, watch, unref, computed } from 'vue'
|
import { defineComponent, ref, watch, unref, computed } from 'vue'
|
||||||
import { Icon } from '/@/components/Icon'
|
|
||||||
import { Tooltip, Space } from 'ant-design-vue'
|
import { Tooltip, Space } from 'ant-design-vue'
|
||||||
import { useModal } from '/@/components/Modal'
|
import { useModal } from '/@/components/Modal'
|
||||||
import { uploadContainerProps } from './props'
|
import { uploadContainerProps } from './props'
|
||||||
@@ -45,10 +31,9 @@
|
|||||||
import { useI18n } from '/@/hooks/web/useI18n'
|
import { useI18n } from '/@/hooks/web/useI18n'
|
||||||
import { isArray } from '/@/utils/is'
|
import { isArray } from '/@/utils/is'
|
||||||
import UploadModal from './UploadModal.vue'
|
import UploadModal from './UploadModal.vue'
|
||||||
import UploadPreviewModal from './UploadPreviewModal.vue'
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicUpload',
|
name: 'BasicUpload',
|
||||||
components: { UploadModal, Space, UploadPreviewModal, Icon, Tooltip },
|
components: { UploadModal, Space, Tooltip },
|
||||||
props: uploadContainerProps,
|
props: uploadContainerProps,
|
||||||
emits: ['change', 'delete', 'preview-delete', 'update:value'],
|
emits: ['change', 'delete', 'preview-delete', 'update:value'],
|
||||||
setup(props, { emit, attrs }) {
|
setup(props, { emit, attrs }) {
|
||||||
@@ -80,12 +65,6 @@
|
|||||||
emit('update:value', fileList.value)
|
emit('update:value', fileList.value)
|
||||||
emit('change', fileList.value)
|
emit('change', fileList.value)
|
||||||
}
|
}
|
||||||
// 预览modal保存操作
|
|
||||||
function handlePreviewChange(urls: string[]) {
|
|
||||||
fileList.value = [...(urls || [])]
|
|
||||||
emit('update:value', fileList.value)
|
|
||||||
emit('change', fileList.value)
|
|
||||||
}
|
|
||||||
function handleDelete(record: Recordable) {
|
function handleDelete(record: Recordable) {
|
||||||
emit('delete', record)
|
emit('delete', record)
|
||||||
}
|
}
|
||||||
@@ -96,7 +75,6 @@
|
|||||||
registerUploadModal,
|
registerUploadModal,
|
||||||
openUploadModal,
|
openUploadModal,
|
||||||
handleChange,
|
handleChange,
|
||||||
handlePreviewChange,
|
|
||||||
registerPreviewModal,
|
registerPreviewModal,
|
||||||
openPreviewModal,
|
openPreviewModal,
|
||||||
fileList,
|
fileList,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<BasicModal
|
<BasicModal
|
||||||
width="800px"
|
width="800px"
|
||||||
:title="t('component.upload.upload')"
|
:title="t('component.upload.upload')"
|
||||||
:okText="t('component.upload.save')"
|
:okText="t('component.upload.complete')"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@register="register"
|
@register="register"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
@@ -236,11 +236,11 @@
|
|||||||
if (isUploadingRef.value) {
|
if (isUploadingRef.value) {
|
||||||
return createMessage.warning(t('component.upload.saveWarn'))
|
return createMessage.warning(t('component.upload.saveWarn'))
|
||||||
}
|
}
|
||||||
const fileList: string[] = []
|
const fileList: number[] = []
|
||||||
for (const item of fileListRef.value) {
|
for (const item of fileListRef.value) {
|
||||||
const { status, responseData } = item
|
const { status, responseData } = item
|
||||||
if (status === UploadResultStatus.SUCCESS && responseData) {
|
if (status === UploadResultStatus.SUCCESS && responseData) {
|
||||||
fileList.push(responseData.url)
|
fileList.push(responseData.result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 存在一个上传成功的即可保存
|
// 存在一个上传成功的即可保存
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ export default {
|
|||||||
},
|
},
|
||||||
upload: {
|
upload: {
|
||||||
save: '保存',
|
save: '保存',
|
||||||
|
complete: '完成',
|
||||||
upload: '上传',
|
upload: '上传',
|
||||||
imgUpload: '图片上传',
|
imgUpload: '图片上传',
|
||||||
uploaded: '已上传',
|
uploaded: '已上传',
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<BasicUpload
|
<BasicUpload
|
||||||
name="paper"
|
name="paper"
|
||||||
v-if="hasPermission([RoleEnum.SUPER, RoleEnum.FILE_MANAGER])"
|
v-if="hasPermission([RoleEnum.SUPER, RoleEnum.FILE_MANAGER])"
|
||||||
:maxSize="20"
|
:maxSize="64"
|
||||||
:maxNumber="10"
|
:maxNumber="16"
|
||||||
@change="handleChange"
|
|
||||||
:api="uploadApi"
|
:api="uploadApi"
|
||||||
|
@change="onChange"
|
||||||
:accept="['application/vnd.openxmlformats-officedocument.wordprocessingml.document']"
|
:accept="['application/vnd.openxmlformats-officedocument.wordprocessingml.document']"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8" :class="`${prefixCls}__top-col`">
|
<a-col :span="8" :class="`${prefixCls}__top-col`">
|
||||||
<div>占用空间</div>
|
<div>占用空间</div>
|
||||||
<p> {{ cardList._totalSize }}MB </p>
|
<p> {{ cardList._totalSize.toFixed(2) }}MB </p>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="8" :class="`${prefixCls}__top-col`">
|
<a-col :span="8" :class="`${prefixCls}__top-col`">
|
||||||
<div>总题目数</div>
|
<div>总题目数</div>
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
{{ item.description }}
|
{{ item.description }}
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div><span>文件大小</span>{{ item.size }}MB</div>
|
<div><span>文件大小</span>{{ item.size.toFixed(2) }}MB</div>
|
||||||
<div><span>上传用户</span>{{ item.author }}</div>
|
<div><span>上传用户</span>{{ item.author }}</div>
|
||||||
<div><span>上传时间</span>{{ item.datetime }}</div>
|
<div><span>上传时间</span>{{ item.datetime }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -109,6 +109,7 @@
|
|||||||
pagination,
|
pagination,
|
||||||
refreshFilePercent,
|
refreshFilePercent,
|
||||||
random,
|
random,
|
||||||
|
refreshCardList,
|
||||||
} from './data'
|
} from './data'
|
||||||
import { PageWrapper } from '/@/components/Page'
|
import { PageWrapper } from '/@/components/Page'
|
||||||
import { useMessage } from '/@/hooks/web/useMessage'
|
import { useMessage } from '/@/hooks/web/useMessage'
|
||||||
@@ -119,6 +120,7 @@
|
|||||||
import { useI18n } from '/@/hooks/web/useI18n'
|
import { useI18n } from '/@/hooks/web/useI18n'
|
||||||
import { delFile, analyzeFile } from '/@/api/page'
|
import { delFile, analyzeFile } from '/@/api/page'
|
||||||
import { useGo } from '/@/hooks/web/usePage'
|
import { useGo } from '/@/hooks/web/usePage'
|
||||||
|
import { useTabs } from '/@/hooks/web/useTabs'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { createMessage } = useMessage()
|
const { createMessage } = useMessage()
|
||||||
@@ -144,7 +146,7 @@
|
|||||||
|
|
||||||
async function analFile(item: any) {
|
async function analFile(item: any) {
|
||||||
try {
|
try {
|
||||||
const msg = await analyzeFile(item.id)
|
const msg = await analyzeFile(item.id, true)
|
||||||
if (msg) {
|
if (msg) {
|
||||||
createMessage.success(msg.msg)
|
createMessage.success(msg.msg)
|
||||||
if (!item.hassettimeout && item.percent == 0) {
|
if (!item.hassettimeout && item.percent == 0) {
|
||||||
@@ -171,18 +173,21 @@
|
|||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const { hasPermission } = usePermission()
|
const { hasPermission } = usePermission()
|
||||||
|
const { refreshPage } = useTabs()
|
||||||
const go = useGo()
|
const go = useGo()
|
||||||
|
|
||||||
function openFile(id: number) {
|
function openFile(id: number) {
|
||||||
go({ name: 'FilePage', params: { id } })
|
go({ name: 'FilePage', params: { id } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onChange(_: number[]) {
|
||||||
|
refreshCardList()
|
||||||
|
refreshPage()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
t,
|
t,
|
||||||
RoleEnum,
|
RoleEnum,
|
||||||
handleChange: (list: string[]) => {
|
|
||||||
createMessage.info(`已上传文件${JSON.stringify(list)}`)
|
|
||||||
},
|
|
||||||
uploadApi,
|
uploadApi,
|
||||||
hasPermission,
|
hasPermission,
|
||||||
prefixCls: 'list-basic',
|
prefixCls: 'list-basic',
|
||||||
@@ -192,6 +197,7 @@
|
|||||||
analyzeFile: analFile,
|
analyzeFile: analFile,
|
||||||
cardList,
|
cardList,
|
||||||
pagination,
|
pagination,
|
||||||
|
onChange,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -3,7 +3,7 @@ module github.com/fumiama/paper-manager
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/FloatTech/sqlite v1.6.1
|
github.com/FloatTech/sqlite v1.6.2
|
||||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||||
github.com/corona10/goimagehash v1.1.0
|
github.com/corona10/goimagehash v1.1.0
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -1,5 +1,5 @@
|
|||||||
github.com/FloatTech/sqlite v1.6.1 h1:FDQM8X4PtO5P3rP9r5f1qYPFI8YvHPmyPlpeUFbOcDE=
|
github.com/FloatTech/sqlite v1.6.2 h1:FytbExjpvYalZxxITtmSenHiPGLPUvlz47LY/P0SCCw=
|
||||||
github.com/FloatTech/sqlite v1.6.1/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
github.com/FloatTech/sqlite v1.6.2/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
||||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
||||||
|
|||||||
Reference in New Issue
Block a user