diff --git a/backend/global/file.go b/backend/global/file.go index 4078202..0338acd 100644 --- a/backend/global/file.go +++ b/backend/global/file.go @@ -497,7 +497,7 @@ func (f *FileDatabase) DelFile(lstid, uid int, istemp bool) error { if err != nil { return err } - if !user.IsSuper() { + if !user.IsSuper() && !istemp { return ErrInvalidRole } ftable := "" @@ -512,6 +512,9 @@ func (f *FileDatabase) DelFile(lstid, uid int, istemp bool) error { if err != nil { return err } + if istemp && lst.Uploader != uid { + return ErrInvalidRole + } if lst.Path == "" || strings.Contains(lst.Path, "..") { return os.ErrNotExist } diff --git a/backend/global/list.go b/backend/global/list.go index 3977488..055c7bb 100644 --- a/backend/global/list.go +++ b/backend/global/list.go @@ -83,14 +83,20 @@ func (f *FileDatabase) SaveFileToTemp(uploader int, file io.Reader, name string) } // ListUploadedFile will select all file that HasntAnalyzed && IsTemp or !HasntAnalyzed && !IsTemp -func (f *FileDatabase) ListUploadedFile() (lst []*List, err error) { +func (f *FileDatabase) ListUploadedFile(istemp bool) (lst []*List, err error) { + q := "" + if istemp { + q = "WHERE IsTemp ORDER BY UpTime DESC" + } else { + q = "WHERE (HasntAnalyzed AND IsTemp) OR (NOT HasntAnalyzed AND NOT IsTemp) ORDER BY UpTime DESC" + } f.mu.RLock() - lst, err = sql.FindAll[List](&f.db, FileTableList, "WHERE (HasntAnalyzed AND IsTemp) OR (NOT HasntAnalyzed AND NOT IsTemp) ORDER BY UpTime DESC") + lst, err = sql.FindAll[List](&f.db, FileTableList, q) f.mu.RUnlock() return } -func (f *FileDatabase) GetFileInfo(id int) (lst List, err error) { +func (f *FileDatabase) ListFileByID(id int) (lst List, err error) { f.mu.RLock() lst, err = sql.Find[List](&f.db, FileTableList, "WHERE ID="+strconv.Itoa(id)) f.mu.RUnlock() diff --git a/backend/login.go b/backend/login.go index ab6baa1..d16dd2e 100644 --- a/backend/login.go +++ b/backend/login.go @@ -97,7 +97,9 @@ type loginResult struct { } var ( - usertokens = ttl.NewCache[string, *global.User](time.Hour) + usertokens = ttl.NewCacheOn(time.Hour, [4]func(string, *global.User){ + nil, nil, func(t string, _ *global.User) { loginstatus.Delete(t) }, nil, + }) ) func login(username, challenge string) (*loginResult, error) { diff --git a/backend/paper.go b/backend/paper.go index 27c59e9..ececb3d 100644 --- a/backend/paper.go +++ b/backend/paper.go @@ -54,6 +54,7 @@ func init() { writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) return } + istemp := r.URL.Query().Get("permanent") != "true" count := -1 var err error countstr := r.URL.Query().Get("count") @@ -64,7 +65,7 @@ func init() { return } } - lst, err := global.FileDB.ListUploadedFile() + lst, err := global.FileDB.ListUploadedFile(istemp) if err != nil && err != sql.ErrNullResult { writeresult(w, codeError, nil, err.Error(), typeError) return @@ -112,7 +113,7 @@ func init() { writeresult(w, codeError, nil, err.Error(), typeError) return } - lst, err := global.FileDB.GetFileInfo(id) + lst, err := global.FileDB.ListFileByID(id) if err != nil && err != sql.ErrNullResult { writeresult(w, codeError, nil, err.Error(), typeError) return @@ -217,7 +218,8 @@ func init() { writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) return } - if !user.IsSuper() { + istemp := r.URL.Query().Get("permanent") != "true" + if !user.IsSuper() && !istemp { writeresult(w, codeError, nil, errNoDeletePermission.Error(), typeError) return } @@ -231,7 +233,7 @@ func init() { writeresult(w, codeError, nil, err.Error(), typeError) return } - err = global.FileDB.DelFile(id, *user.ID, false) + err = global.FileDB.DelFile(id, *user.ID, istemp) if err != nil { writeresult(w, codeError, nil, err.Error(), typeError) return @@ -245,10 +247,6 @@ func init() { writeresult(w, codeError, nil, errInvalidToken.Error(), typeError) return } - if !user.IsSuper() { - writeresult(w, codeError, nil, errNoDeletePermission.Error(), typeError) - return - } idstr := r.URL.Query().Get("id") if idstr == "" { writeresult(w, codeError, nil, "empty id", typeError) @@ -259,7 +257,7 @@ func init() { writeresult(w, codeError, nil, err.Error(), typeError) return } - lst, err := global.FileDB.GetFileInfo(id) + lst, err := global.FileDB.ListFileByID(id) if err != nil { writeresult(w, codeError, nil, err.Error(), typeError) return diff --git a/frontend/vben/src/api/page/index.ts b/frontend/vben/src/api/page/index.ts index 0b09ee4..e15b896 100644 --- a/frontend/vben/src/api/page/index.ts +++ b/frontend/vben/src/api/page/index.ts @@ -15,8 +15,8 @@ enum Api { /** * @description: Get file list */ -export const getFileList = (count?: number) => { - return defHttp.get({ url: Api.GetFileList, params: { count: count } }) +export const getFileList = (permanent: boolean, count?: number) => { + return defHttp.get({ url: Api.GetFileList, params: { count, permanent } }) } /** @@ -36,8 +36,8 @@ export const getFilePercent = (id: number) => { /** * @description: Get file percent */ -export const delFile = (id: number) => { - return defHttp.get({ url: Api.DelFile, params: { id: id } }) +export const delFile = (id: number, permanent: boolean) => { + return defHttp.get({ url: Api.DelFile, params: { id, permanent } }) } /** diff --git a/frontend/vben/src/locales/lang/zh-CN/routes/templist.ts b/frontend/vben/src/locales/lang/zh-CN/routes/templist.ts new file mode 100644 index 0000000..eb984c9 --- /dev/null +++ b/frontend/vben/src/locales/lang/zh-CN/routes/templist.ts @@ -0,0 +1,4 @@ +export default { + name: '试卷查重', + file: '查重报告', +} diff --git a/frontend/vben/src/router/menus/modules/templist.ts b/frontend/vben/src/router/menus/modules/templist.ts new file mode 100644 index 0000000..fa52ec8 --- /dev/null +++ b/frontend/vben/src/router/menus/modules/templist.ts @@ -0,0 +1,17 @@ +import type { MenuModule } from '/@/router/types' +import { t } from '/@/hooks/web/useI18n' +const menu: MenuModule = { + orderNo: 20, + menu: { + name: t('routes.templist.name'), + path: '/templist', + + children: [ + { + path: 'index', + name: t('routes.templist.name'), + }, + ], + }, +} +export default menu diff --git a/frontend/vben/src/router/routes/modules/filelist.ts b/frontend/vben/src/router/routes/modules/filelist.ts index 8378c41..72c093a 100644 --- a/frontend/vben/src/router/routes/modules/filelist.ts +++ b/frontend/vben/src/router/routes/modules/filelist.ts @@ -1,10 +1,7 @@ import type { AppRouteModule } from '/@/router/types' -import { ExceptionEnum } from '/@/enums/exceptionEnum' import { LAYOUT } from '/@/router/constant' import { t } from '/@/hooks/web/useI18n' -const ExceptionPage = () => import('/@/views/sys/exception/Exception.vue') - const filelist: AppRouteModule = { path: '/filelist', name: 'FileList', @@ -38,17 +35,6 @@ const filelist: AppRouteModule = { hideMenu: true, }, }, - { - path: '404', - name: 'PageNotFound', - component: ExceptionPage, - props: { - status: ExceptionEnum.PAGE_NOT_FOUND, - }, - meta: { - title: '404', - }, - }, ], } diff --git a/frontend/vben/src/router/routes/modules/templist.ts b/frontend/vben/src/router/routes/modules/templist.ts new file mode 100644 index 0000000..2279b6b --- /dev/null +++ b/frontend/vben/src/router/routes/modules/templist.ts @@ -0,0 +1,41 @@ +import type { AppRouteModule } from '/@/router/types' +import { LAYOUT } from '/@/router/constant' +import { t } from '/@/hooks/web/useI18n' + +const templist: AppRouteModule = { + path: '/templist', + name: 'TempList', + component: LAYOUT, + redirect: '/templist/index', + meta: { + hideChildrenInMenu: true, + icon: 'ion:ios-analytics', + title: t('routes.templist.name'), + orderNo: 20, + }, + children: [ + { + path: 'index', + name: 'TempListPage', + component: () => import('/@/views/page/templist/index.vue'), + meta: { + title: t('routes.templist.name'), + icon: 'ion:file-tray-full-outline', + hideMenu: true, + }, + }, + { + path: 'file/:id', + name: 'TempFilePage', + component: () => import('/@/views/page/file/index.vue'), + meta: { + title: t('routes.templist.file'), + carryParam: true, + icon: 'bi:filetype-docx', + hideMenu: true, + }, + }, + ], +} + +export default templist diff --git a/frontend/vben/src/views/page/filelist/data.tsx b/frontend/vben/src/views/page/filelist/data.tsx index 63fd0ad..853e423 100644 --- a/frontend/vben/src/views/page/filelist/data.tsx +++ b/frontend/vben/src/views/page/filelist/data.tsx @@ -34,7 +34,7 @@ export function getListOfPage(pageSize: number, page: number): any[] { async function refreshFileList() { const __cardList: any[] = [] - const lst = (await getFileList()) as getFileListModel + const lst = (await getFileList(true)) as getFileListModel let __totalSize = 0 let __totalQuestions = 0 for (let i = 0; i < lst.length; i++) { diff --git a/frontend/vben/src/views/page/filelist/index.vue b/frontend/vben/src/views/page/filelist/index.vue index 35e0a8f..e215555 100644 --- a/frontend/vben/src/views/page/filelist/index.vue +++ b/frontend/vben/src/views/page/filelist/index.vue @@ -128,7 +128,7 @@ async function deleteFile(item: any) { try { item.delloading = true - const msg = await delFile(item.id) + const msg = await delFile(item.id, true) if (msg) { createMessage.success(msg) setTimeout(() => { diff --git a/frontend/vben/src/views/page/templist/data.tsx b/frontend/vben/src/views/page/templist/data.tsx new file mode 100644 index 0000000..b5a1938 --- /dev/null +++ b/frontend/vben/src/views/page/templist/data.tsx @@ -0,0 +1,115 @@ +import { reactive } from 'vue' +import { getFileList, getFilePercent, getFileInfo } from '/@/api/page' +import { getFileListModel } from '/@/api/page/model/fileListModel' + +export const random = (min: number, max: number) => + Math.floor(Math.random() * (max - min + 1) + min) + +export function refreshFilePercent(item: any) { + return async () => { + const p = await getFilePercent(item.id) + if (p) { + item.percent = p + if (p < 100) { + setTimeout(refreshFilePercent(item), 1000) + } + } else item.hassettimeout = false + } +} + +export function getListOfPage(pageSize: number, page: number): any[] { + const i = page - 1 + let lst: any[] = [] + if (i < cardList._cardList.length / pageSize) + lst = reactive(cardList._cardList.slice(i * pageSize, page * pageSize)) + else lst = reactive(cardList._cardList.slice((cardList._cardList.length / pageSize) * pageSize)) + for (let i = 0; i < lst.length; i++) { + if (!lst[i].hassettimeout && lst[i].percent > 0 && lst[i].percent < 100) { + setTimeout(refreshFilePercent(lst[i]), 1000 + random(0, 1000)) + lst[i].hassettimeout = true + } + } + return lst +} + +async function refreshFileList() { + const __cardList: any[] = [] + const lst = (await getFileList(false)) as getFileListModel + let __totalSize = 0 + let __totalQuestions = 0 + for (let i = 0; i < lst.length; i++) { + __cardList.push({ + id: lst[i].id, + title: lst[i].title, + description: lst[i].description, + size: lst[i].size, + questions: lst[i].questions, + datetime: lst[i].datetime, + icon: 'bi:filetype-docx', + color: '#1890ff', + author: lst[i].author, + percent: lst[i].percent, + hassettimeout: false, + delloading: false, + }) + __totalSize += lst[i].size + __totalQuestions += lst[i].questions + } + return { + _cardList: __cardList, + _totalSize: __totalSize, + _totalQuestions: __totalQuestions, + } +} + +export const cardList = reactive(await refreshFileList()) + +export const pagination = reactive({ + current: 1, + total: cardList._cardList.length, + show: true, + pageSize: 10, + onChange: function (page: number, pageSize: number) { + this.current = page + this.pageSize = pageSize + }, +}) + +export function refreshCardList() { + refreshFileList().then((value) => { + cardList._cardList = value._cardList + cardList._totalQuestions = value._totalQuestions + cardList._totalSize = value._totalSize + pagination.current = 1 + pagination.total = cardList._cardList.length + }) +} + +export function deleteFileByID(id: number) { + cardList._cardList.map((value: any, index: number) => { + if (value.id == id) { + cardList._cardList.splice(index, 1) + cardList._totalSize -= value.size + cardList._totalQuestions -= value.questions + pagination.total = cardList._cardList.length + } + }) +} + +export function refreshFileByID(id: number) { + getFileInfo(id).then((info) => { + cardList._cardList.map((value: any) => { + if (value.id == id) { + cardList._totalSize = cardList._totalSize - value.size + info.size + cardList._totalQuestions = cardList._totalQuestions - value.questions + info.questions + value.title = info.title + value.description = info.description + value.size = info.size + value.questions = info.questions + value.datetime = info.datetime + value.author = info.author + value.percent = info.percent + } + }) + }) +} diff --git a/frontend/vben/src/views/page/templist/index.vue b/frontend/vben/src/views/page/templist/index.vue new file mode 100644 index 0000000..3fea34c --- /dev/null +++ b/frontend/vben/src/views/page/templist/index.vue @@ -0,0 +1,269 @@ + + +