From d15bd1d6b48960e87ea710f30698550dde97dc56 Mon Sep 17 00:00:00 2001 From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com> Date: Wed, 1 Nov 2023 18:30:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20PHP=20=E8=BF=90=E8=A1=8C=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E5=A2=9E=E5=8A=A0=E6=97=A5=E5=BF=97=20(#2764)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs https://github.com/1Panel-dev/1Panel/issues/2761 --- backend/app/api/v1/file.go | 24 +++ backend/app/dto/request/file.go | 6 + backend/app/dto/response/file.go | 6 + backend/router/ro_file.go | 1 + cmd/server/docs/docs.go | 53 +++++- cmd/server/docs/swagger.json | 49 ++++++ cmd/server/docs/swagger.yaml | 31 ++++ frontend/src/api/interface/file.ts | 6 + frontend/src/api/modules/files.ts | 4 + .../src/views/website/runtime/php/index.vue | 12 ++ .../views/website/runtime/php/log/index.vue | 160 ++++++++++++++++++ 11 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 frontend/src/views/website/runtime/php/log/index.vue diff --git a/backend/app/api/v1/file.go b/backend/app/api/v1/file.go index c13426489..b33defdea 100644 --- a/backend/app/api/v1/file.go +++ b/backend/app/api/v1/file.go @@ -683,3 +683,27 @@ func (b *BaseApi) Keys(c *gin.Context) { res.Keys = keys helper.SuccessWithData(c, res) } + +// @Tags File +// @Summary Read file by Line +// @Description 按行读取文件 +// @Param request body request.FileReadByLineReq true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /files/read [post] +func (b *BaseApi) ReadFileByLine(c *gin.Context) { + var req request.FileReadByLineReq + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + lines, end, err := files.ReadFileByLine(req.Path, req.Page, req.PageSize) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + } + res := response.FileLineContent{ + End: end, + } + res.Path = req.Path + res.Content = strings.Join(lines, "\n") + helper.SuccessWithData(c, res) +} diff --git a/backend/app/dto/request/file.go b/backend/app/dto/request/file.go index b97bf890f..02e7b4056 100644 --- a/backend/app/dto/request/file.go +++ b/backend/app/dto/request/file.go @@ -109,6 +109,12 @@ type FileRoleUpdate struct { Sub bool `json:"sub" validate:"required"` } +type FileReadByLineReq struct { + Path string `json:"path" validate:"required"` + Page int `json:"page" validate:"required"` + PageSize int `json:"pageSize" validate:"required"` +} + type FileExistReq struct { Name string `json:"name" validate:"required"` Dir string `json:"dir" validate:"required"` diff --git a/backend/app/dto/response/file.go b/backend/app/dto/response/file.go index 12c45911b..43b5017e6 100644 --- a/backend/app/dto/response/file.go +++ b/backend/app/dto/response/file.go @@ -33,6 +33,12 @@ type FileWgetRes struct { Key string `json:"key"` } +type FileLineContent struct { + Content string `json:"content"` + End bool `json:"end"` + Path string `json:"path"` +} + type FileExist struct { Exist bool `json:"exist"` } diff --git a/backend/router/ro_file.go b/backend/router/ro_file.go index ab510cf51..0daa98dab 100644 --- a/backend/router/ro_file.go +++ b/backend/router/ro_file.go @@ -37,6 +37,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) { fileRouter.POST("/size", baseApi.Size) fileRouter.GET("/ws", baseApi.Ws) fileRouter.GET("/keys", baseApi.Keys) + fileRouter.POST("/read", baseApi.ReadFileByLine) fileRouter.POST("/recycle/search", baseApi.SearchRecycleBinFile) fileRouter.POST("/recycle/reduce", baseApi.ReduceRecycleBinFile) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index bc74b1a2a..17eff60cc 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1,5 +1,5 @@ -// Code generated by swaggo/swag. DO NOT EDIT. - +// Package docs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag package docs import "github.com/swaggo/swag" @@ -5666,6 +5666,36 @@ const docTemplate = `{ } } }, + "/files/read": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "按行读取文件", + "tags": [ + "File" + ], + "summary": "Read file by Line", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.FileReadByLineReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/files/recycle/clear": { "post": { "security": [ @@ -16955,6 +16985,25 @@ const docTemplate = `{ } } }, + "request.FileReadByLineReq": { + "type": "object", + "required": [ + "page", + "pageSize", + "path" + ], + "properties": { + "page": { + "type": "integer" + }, + "pageSize": { + "type": "integer" + }, + "path": { + "type": "string" + } + } + }, "request.FileRename": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 6df145e71..85314b859 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -5659,6 +5659,36 @@ } } }, + "/files/read": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "按行读取文件", + "tags": [ + "File" + ], + "summary": "Read file by Line", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.FileReadByLineReq" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/files/recycle/clear": { "post": { "security": [ @@ -16948,6 +16978,25 @@ } } }, + "request.FileReadByLineReq": { + "type": "object", + "required": [ + "page", + "pageSize", + "path" + ], + "properties": { + "page": { + "type": "integer" + }, + "pageSize": { + "type": "integer" + }, + "path": { + "type": "string" + } + } + }, "request.FileRename": { "type": "object", "required": [ diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 47a6d0044..e0fe5e23e 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -2998,6 +2998,19 @@ definitions: required: - path type: object + request.FileReadByLineReq: + properties: + page: + type: integer + pageSize: + type: integer + path: + type: string + required: + - page + - pageSize + - path + type: object request.FileRename: properties: newName: @@ -7955,6 +7968,24 @@ paths: formatEN: Change owner [paths] => [user]/[group] formatZH: 修改用户/组 [paths] => [user]/[group] paramKeys: [] + /files/read: + post: + description: 按行读取文件 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/request.FileReadByLineReq' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Read file by Line + tags: + - File /files/recycle/clear: post: consumes: diff --git a/frontend/src/api/interface/file.ts b/frontend/src/api/interface/file.ts index 768ce5e34..de3760ba9 100644 --- a/frontend/src/api/interface/file.ts +++ b/frontend/src/api/interface/file.ts @@ -164,6 +164,12 @@ export namespace File { name: string; } + export interface FileReadByLine { + path: string; + page: number; + pageSize: number; + } + export interface Favorite extends CommonModel { path: string; isDir: boolean; diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index b5089a0ed..aa0658d56 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -109,6 +109,10 @@ export const AddFavorite = (path: string) => { return http.post('files/favorite', { path: path }); }; +export const ReadByLine = (req: File.FileReadByLine) => { + return http.post('files/read', req); +}; + export const RemoveFavorite = (id: number) => { return http.post('files/favorite/del', { id: id }); }; diff --git a/frontend/src/views/website/runtime/php/index.vue b/frontend/src/views/website/runtime/php/index.vue index 5bf75372f..4e19d79d1 100644 --- a/frontend/src/views/website/runtime/php/index.vue +++ b/frontend/src/views/website/runtime/php/index.vue @@ -39,6 +39,11 @@ + + + + @@ -74,6 +80,7 @@ import CreateRuntime from '@/views/website/runtime/php/create/index.vue'; import Status from '@/components/status/index.vue'; import i18n from '@/lang'; import RouterMenu from '../index.vue'; +import Log from '@/views/website/runtime/php/log/index.vue'; const paginationConfig = reactive({ cacheSizeKey: 'runtime-page-size', @@ -89,6 +96,7 @@ let req = reactive({ }); let timer: NodeJS.Timer | null = null; const opRef = ref(); +const logRef = ref(); const buttons = [ { @@ -133,6 +141,10 @@ const openDetail = (row: Runtime.Runtime) => { createRef.value.acceptParams({ type: row.type, mode: 'edit', id: row.id, appID: row.appID }); }; +const openLog = (row: Runtime.RuntimeDTO) => { + logRef.value.acceptParams({ path: row.path + '/' + 'build.log' }); +}; + const openDelete = async (row: Runtime.Runtime) => { opRef.value.acceptParams({ title: i18n.global.t('commons.msg.deleteTitle'), diff --git a/frontend/src/views/website/runtime/php/log/index.vue b/frontend/src/views/website/runtime/php/log/index.vue new file mode 100644 index 000000000..338532304 --- /dev/null +++ b/frontend/src/views/website/runtime/php/log/index.vue @@ -0,0 +1,160 @@ + +