From a72afdbb5ea6d22e4d74a149a28c38508a3418b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Thu, 16 Mar 2023 14:03:58 +0800 Subject: [PATCH] front: finish docx & back: init --- .gitignore | 2 + backend/api/main.go | 15 ++ backend/file/provider.go | 26 +++ backend/global/base.go | 36 +++ backend/utils/method.go | 27 +++ frontend/vben/.env.development | 4 +- frontend/vben/.env.production | 2 +- frontend/vben/mock/demo/account.ts | 6 +- frontend/vben/mock/demo/api-cascader.ts | 2 +- frontend/vben/mock/demo/select-demo.ts | 2 +- frontend/vben/mock/demo/system.ts | 14 +- frontend/vben/mock/demo/table-demo.ts | 2 +- frontend/vben/mock/demo/tree-demo.ts | 2 +- frontend/vben/mock/page/file.ts | 19 ++ frontend/vben/mock/page/filelist.ts | 8 +- frontend/vben/mock/sys/menu.ts | 2 +- frontend/vben/mock/sys/user.ts | 14 +- frontend/vben/package.json | 1 + frontend/vben/src/api/page/index.ts | 9 + frontend/vben/src/api/page/model/fileModel.ts | 3 + .../src/locales/lang/zh-CN/routes/filelist.ts | 1 + .../src/router/routes/modules/filelist.ts | 26 ++- frontend/vben/src/views/page/file/index.vue | 206 ++++++++++++++++++ go.mod | 4 + go.sum | 15 ++ main.go | 36 ++- 26 files changed, 453 insertions(+), 31 deletions(-) create mode 100644 backend/api/main.go create mode 100644 backend/file/provider.go create mode 100644 backend/global/base.go create mode 100644 backend/utils/method.go create mode 100644 frontend/vben/mock/page/file.ts create mode 100644 frontend/vben/src/api/page/model/fileModel.ts create mode 100644 frontend/vben/src/views/page/file/index.vue create mode 100644 go.sum diff --git a/.gitignore b/.gitignore index 1b3a47d..75af933 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ # MacOS storage file .DS_Store + +/data diff --git a/backend/api/main.go b/backend/api/main.go new file mode 100644 index 0000000..c023f95 --- /dev/null +++ b/backend/api/main.go @@ -0,0 +1,15 @@ +package api + +import ( + "net/http" + + "github.com/fumiama/paper-manager/backend/utils" +) + +// Handler serves all backend /api call +func Handler(w http.ResponseWriter, r *http.Request) { + if !utils.IsMethod("GET", w, r) { + return + } + http.Error(w, "404 Not Found", http.StatusNotFound) +} diff --git a/backend/file/provider.go b/backend/file/provider.go new file mode 100644 index 0000000..d7c51fc --- /dev/null +++ b/backend/file/provider.go @@ -0,0 +1,26 @@ +package file + +import ( + "net/http" + "strings" + + "github.com/fumiama/paper-manager/backend/global" + "github.com/fumiama/paper-manager/backend/utils" + "github.com/sirupsen/logrus" +) + +// Handler serves contents in global.FileFolder +func Handler(w http.ResponseWriter, r *http.Request) { + if !utils.IsMethod("GET", w, r) { + return + } + i := strings.LastIndex(r.URL.Path, "/") + fn := r.URL.Path[i+1:] + if fn == "" { + http.Error(w, "400 Bad Request: empty path", http.StatusBadRequest) + return + } + name := global.FileFolder + fn + logrus.Infoln("[file.Handler]\t serve", name) + http.ServeFile(w, r, name) +} diff --git a/backend/global/base.go b/backend/global/base.go new file mode 100644 index 0000000..8ca9d22 --- /dev/null +++ b/backend/global/base.go @@ -0,0 +1,36 @@ +package global + +import ( + "os" + "runtime" + + "github.com/sirupsen/logrus" +) + +const ( + // DataFolder stores all backend data in + DataFolder = "./data/" + // FileFolder stores all blob files + FileFolder = DataFolder + "file/" +) + +func init() { + initdir(DataFolder) + initdir(FileFolder) +} + +func initdir(folder string) { + err := os.MkdirAll(folder, 0755) + if err != nil { + logrus.Errorln("[os.MkdirAll]\t", err) + os.Exit(line()) + } +} + +func line() int { + _, _, fileLine, ok := runtime.Caller(2) + if ok { + return fileLine + } + return -1 +} diff --git a/backend/utils/method.go b/backend/utils/method.go new file mode 100644 index 0000000..f25248a --- /dev/null +++ b/backend/utils/method.go @@ -0,0 +1,27 @@ +package utils + +import ( + "net/http" + + "github.com/sirupsen/logrus" +) + +// IP gets ip from r.Header's X-FORWARDED-FOR or r.RemoteAddr +func IP(r *http.Request) string { + forwarded := r.Header.Get("X-FORWARDED-FOR") + if forwarded != "" { + return forwarded + } + return r.RemoteAddr +} + +// IsMethod check if the method meets the requirement +// and response 405 Method Not Allowed if not matched +func IsMethod(m string, w http.ResponseWriter, r *http.Request) bool { + logrus.Infoln("[utils.IsMethod]\t accept", IP(r), r.Method, r.URL) + if r.Method != m { + http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed) + return false + } + return true +} diff --git a/frontend/vben/.env.development b/frontend/vben/.env.development index 85af123..ae9eea9 100644 --- a/frontend/vben/.env.development +++ b/frontend/vben/.env.development @@ -6,14 +6,14 @@ VITE_PUBLIC_PATH = / # Cross-domain proxy, you can configure multiple # Please note that no line breaks -VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","http://localhost:3000/upload"]] +VITE_PROXY = [["/api","http://localhost:3000/api"],["/file","http://localhost:3000/file"],["/upload","http://localhost:3000/upload"]] # VITE_PROXY=[["/api","https://vvbin.cn/test"]] # Delete console VITE_DROP_CONSOLE = false # Basic interface address SPA -VITE_GLOB_API_URL=/basic-api +VITE_GLOB_API_URL=/api # File upload address, optional VITE_GLOB_UPLOAD_URL=/upload diff --git a/frontend/vben/.env.production b/frontend/vben/.env.production index 9785c06..40548cd 100644 --- a/frontend/vben/.env.production +++ b/frontend/vben/.env.production @@ -16,7 +16,7 @@ VITE_BUILD_COMPRESS = 'none' VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false # Basic interface address SPA -VITE_GLOB_API_URL=/basic-api +VITE_GLOB_API_URL=/api # File upload address, optional # It can be forwarded by nginx or write the actual address directly diff --git a/frontend/vben/mock/demo/account.ts b/frontend/vben/mock/demo/account.ts index 56f4174..4974e10 100644 --- a/frontend/vben/mock/demo/account.ts +++ b/frontend/vben/mock/demo/account.ts @@ -45,7 +45,7 @@ const userInfo = { export default [ { - url: '/basic-api/account/getAccountInfo', + url: '/api/account/getAccountInfo', timeout: 1000, method: 'get', response: () => { @@ -53,7 +53,7 @@ export default [ }, }, { - url: '/basic-api/user/sessionTimeout', + url: '/api/user/sessionTimeout', method: 'post', statusCode: 401, response: () => { @@ -61,7 +61,7 @@ export default [ }, }, { - url: '/basic-api/user/tokenExpired', + url: '/api/user/tokenExpired', method: 'post', statusCode: 200, response: () => { diff --git a/frontend/vben/mock/demo/api-cascader.ts b/frontend/vben/mock/demo/api-cascader.ts index dcaf322..0830ea3 100644 --- a/frontend/vben/mock/demo/api-cascader.ts +++ b/frontend/vben/mock/demo/api-cascader.ts @@ -311,7 +311,7 @@ const areaList: any[] = [ ] export default [ { - url: '/basic-api/cascader/getAreaRecord', + url: '/api/cascader/getAreaRecord', timeout: 1000, method: 'post', response: ({ body }) => { diff --git a/frontend/vben/mock/demo/select-demo.ts b/frontend/vben/mock/demo/select-demo.ts index fcff452..0404133 100644 --- a/frontend/vben/mock/demo/select-demo.ts +++ b/frontend/vben/mock/demo/select-demo.ts @@ -16,7 +16,7 @@ const demoList = (keyword: string, count = 20) => { export default [ { - url: '/basic-api/select/getDemoOptions', + url: '/api/select/getDemoOptions', timeout: 1000, method: 'get', response: ({ query }) => { diff --git a/frontend/vben/mock/demo/system.ts b/frontend/vben/mock/demo/system.ts index 5ae7b13..671af63 100644 --- a/frontend/vben/mock/demo/system.ts +++ b/frontend/vben/mock/demo/system.ts @@ -136,7 +136,7 @@ const menuList = (() => { export default [ { - url: '/basic-api/system/getAccountList', + url: '/api/system/getAccountList', timeout: 100, method: 'get', response: ({ query }) => { @@ -145,7 +145,7 @@ export default [ }, }, { - url: '/basic-api/system/getRoleListByPage', + url: '/api/system/getRoleListByPage', timeout: 100, method: 'get', response: ({ query }) => { @@ -154,7 +154,7 @@ export default [ }, }, { - url: '/basic-api/system/setRoleStatus', + url: '/api/system/setRoleStatus', timeout: 500, method: 'post', response: ({ query }) => { @@ -163,7 +163,7 @@ export default [ }, }, { - url: '/basic-api/system/getAllRoleList', + url: '/api/system/getAllRoleList', timeout: 100, method: 'get', response: () => { @@ -171,7 +171,7 @@ export default [ }, }, { - url: '/basic-api/system/getDeptList', + url: '/api/system/getDeptList', timeout: 100, method: 'get', response: () => { @@ -179,7 +179,7 @@ export default [ }, }, { - url: '/basic-api/system/getMenuList', + url: '/api/system/getMenuList', timeout: 100, method: 'get', response: () => { @@ -187,7 +187,7 @@ export default [ }, }, { - url: '/basic-api/system/accountExist', + url: '/api/system/accountExist', timeout: 500, method: 'post', response: ({ body }) => { diff --git a/frontend/vben/mock/demo/table-demo.ts b/frontend/vben/mock/demo/table-demo.ts index 5ae19a3..61f324a 100644 --- a/frontend/vben/mock/demo/table-demo.ts +++ b/frontend/vben/mock/demo/table-demo.ts @@ -41,7 +41,7 @@ const demoList = (() => { export default [ { - url: '/basic-api/table/getDemoList', + url: '/api/table/getDemoList', timeout: 100, method: 'get', response: ({ query }) => { diff --git a/frontend/vben/mock/demo/tree-demo.ts b/frontend/vben/mock/demo/tree-demo.ts index a65c03e..67609b2 100644 --- a/frontend/vben/mock/demo/tree-demo.ts +++ b/frontend/vben/mock/demo/tree-demo.ts @@ -26,7 +26,7 @@ const demoTreeList = (keyword: string) => { export default [ { - url: '/basic-api/tree/getDemoOptions', + url: '/api/tree/getDemoOptions', timeout: 1000, method: 'get', response: ({ query }) => { diff --git a/frontend/vben/mock/page/file.ts b/frontend/vben/mock/page/file.ts new file mode 100644 index 0000000..1df2265 --- /dev/null +++ b/frontend/vben/mock/page/file.ts @@ -0,0 +1,19 @@ +import { MockMethod } from 'vite-plugin-mock' +import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util' + +export default [ + { + url: '/api/dlFile', + timeout: 1000, + method: 'get', + response: (request: requestParams) => { + const token = getRequestToken(request) + if (!token) return resultError('Invalid token') + const id = Number(request.query.id) + if (!id || id < 0) return resultError('Invalid id') + return resultSuccess({ + url: '/file/' + id + '.docx', + }) + }, + }, +] as MockMethod[] diff --git a/frontend/vben/mock/page/filelist.ts b/frontend/vben/mock/page/filelist.ts index 989500f..b842a3c 100644 --- a/frontend/vben/mock/page/filelist.ts +++ b/frontend/vben/mock/page/filelist.ts @@ -26,7 +26,7 @@ function createFileList() { export default [ // mock get filelist { - url: '/basic-api/getFileList', + url: '/api/getFileList', timeout: 200, method: 'get', response: (request: requestParams) => { @@ -42,7 +42,7 @@ export default [ }, }, { - url: '/basic-api/getFilePercent', + url: '/api/getFilePercent', timeout: 200, method: 'get', response: (request: requestParams) => { @@ -71,7 +71,7 @@ export default [ }, }, { - url: '/basic-api/delFile', + url: '/api/delFile', timeout: 200, method: 'get', response: (request: requestParams) => { @@ -86,7 +86,7 @@ export default [ }, }, { - url: '/basic-api/analyzeFile', + url: '/api/analyzeFile', timeout: 1000, method: 'get', response: (request: requestParams) => { diff --git a/frontend/vben/mock/sys/menu.ts b/frontend/vben/mock/sys/menu.ts index 1df2a22..21d0cb0 100644 --- a/frontend/vben/mock/sys/menu.ts +++ b/frontend/vben/mock/sys/menu.ts @@ -227,7 +227,7 @@ const linkRoute = { export default [ { - url: '/basic-api/getMenuList', + url: '/api/getMenuList', timeout: 1000, method: 'get', response: (request: requestParams) => { diff --git a/frontend/vben/mock/sys/user.ts b/frontend/vben/mock/sys/user.ts index f5d75a5..71e5874 100644 --- a/frontend/vben/mock/sys/user.ts +++ b/frontend/vben/mock/sys/user.ts @@ -62,7 +62,7 @@ const fakeCodeList: any = { export default [ // mock user login { - url: '/basic-api/login', + url: '/api/login', timeout: 200, method: 'post', response: ({ body }) => { @@ -86,7 +86,7 @@ export default [ }, // mock reset password { - url: '/basic-api/resetPassword', + url: '/api/resetPassword', timeout: 200, method: 'post', response: ({ body }) => { @@ -98,7 +98,7 @@ export default [ }, // mock register { - url: '/basic-api/register', + url: '/api/register', timeout: 200, method: 'post', response: ({ body }) => { @@ -109,7 +109,7 @@ export default [ }, }, { - url: '/basic-api/getUserInfo', + url: '/api/getUserInfo', method: 'get', response: (request: requestParams) => { const token = getRequestToken(request) @@ -122,7 +122,7 @@ export default [ }, }, { - url: '/basic-api/getPermCode', + url: '/api/getPermCode', timeout: 200, method: 'get', response: (request: requestParams) => { @@ -138,7 +138,7 @@ export default [ }, }, { - url: '/basic-api/logout', + url: '/api/logout', timeout: 200, method: 'get', response: (request: requestParams) => { @@ -152,7 +152,7 @@ export default [ }, }, { - url: '/basic-api/testRetry', + url: '/api/testRetry', statusCode: 405, method: 'get', response: () => { diff --git a/frontend/vben/package.json b/frontend/vben/package.json index f2523ff..8d8baf5 100644 --- a/frontend/vben/package.json +++ b/frontend/vben/package.json @@ -49,6 +49,7 @@ "cropperjs": "^1.5.12", "crypto-js": "^4.1.1", "dayjs": "^1.11.1", + "docx-preview": "^0.1.15", "echarts": "^5.3.2", "intro.js": "^5.1.0", "lodash-es": "^4.17.21", diff --git a/frontend/vben/src/api/page/index.ts b/frontend/vben/src/api/page/index.ts index 87edb12..e26f9b3 100644 --- a/frontend/vben/src/api/page/index.ts +++ b/frontend/vben/src/api/page/index.ts @@ -1,11 +1,13 @@ import { defHttp } from '/@/utils/http/axios' import { getFileListModel, FilePercent, DelFile, AnalyzeFile } from './model/fileListModel' +import { DownloadFile } from './model/fileModel' enum Api { GetFileList = '/getFileList', GetFilePercent = '/getFilePercent', DelFile = '/delFile', AnalyzeFile = '/analyzeFile', + DlFile = '/dlFile', } /** @@ -35,3 +37,10 @@ export const delFile = (id: number) => { export const analyzeFile = (id: number) => { return defHttp.get({ url: Api.AnalyzeFile, params: { id: id } }) } + +/** + * @description: Download file + */ +export const downloadFile = (id: number) => { + return defHttp.get({ url: Api.DlFile, params: { id: id } }) +} diff --git a/frontend/vben/src/api/page/model/fileModel.ts b/frontend/vben/src/api/page/model/fileModel.ts new file mode 100644 index 0000000..8c72af1 --- /dev/null +++ b/frontend/vben/src/api/page/model/fileModel.ts @@ -0,0 +1,3 @@ +export interface DownloadFile { + url: string +} diff --git a/frontend/vben/src/locales/lang/zh-CN/routes/filelist.ts b/frontend/vben/src/locales/lang/zh-CN/routes/filelist.ts index 47617c3..6779135 100644 --- a/frontend/vben/src/locales/lang/zh-CN/routes/filelist.ts +++ b/frontend/vben/src/locales/lang/zh-CN/routes/filelist.ts @@ -1,3 +1,4 @@ export default { name: '试卷库', + file: '试卷解析', } diff --git a/frontend/vben/src/router/routes/modules/filelist.ts b/frontend/vben/src/router/routes/modules/filelist.ts index e8f04e5..8378c41 100644 --- a/frontend/vben/src/router/routes/modules/filelist.ts +++ b/frontend/vben/src/router/routes/modules/filelist.ts @@ -1,8 +1,10 @@ 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', @@ -25,6 +27,28 @@ const filelist: AppRouteModule = { hideMenu: true, }, }, + { + path: 'file/:id', + name: 'FilePage', + component: () => import('/@/views/page/file/index.vue'), + meta: { + title: t('routes.filelist.file'), + carryParam: true, + icon: 'bi:filetype-docx', + hideMenu: true, + }, + }, + { + path: '404', + name: 'PageNotFound', + component: ExceptionPage, + props: { + status: ExceptionEnum.PAGE_NOT_FOUND, + }, + meta: { + title: '404', + }, + }, ], } diff --git a/frontend/vben/src/views/page/file/index.vue b/frontend/vben/src/views/page/file/index.vue new file mode 100644 index 0000000..4315632 --- /dev/null +++ b/frontend/vben/src/views/page/file/index.vue @@ -0,0 +1,206 @@ + + + diff --git a/go.mod b/go.mod index ce39840..4d5a863 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,7 @@ module github.com/fumiama/paper-manager go 1.20 + +require github.com/sirupsen/logrus v1.9.0 + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ed65537 --- /dev/null +++ b/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 7905807..97b118b 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,39 @@ package main -func main() { +import ( + "flag" + "net" + "net/http" + "os" + "runtime" + "github.com/sirupsen/logrus" + + "github.com/fumiama/paper-manager/backend/api" + "github.com/fumiama/paper-manager/backend/file" +) + +func line() int { + _, _, fileLine, ok := runtime.Caller(1) + if ok { + return fileLine + } + return -1 +} + +func main() { + addr := flag.String("l", "[::]:3000", "listen addr") + flag.Parse() + l, err := net.Listen("tcp", *addr) + if err != nil { + logrus.Errorln("[net.Listen]\t", err) + os.Exit(line()) + } + + http.HandleFunc("/api/", api.Handler) + http.HandleFunc("/file/", file.Handler) + + logrus.Infoln("[http.Serve]\t start at", l.Addr()) + logrus.Errorln("[http.Serve]\t", http.Serve(l, nil)) + os.Exit(line()) }