diff --git a/backend/app/dto/request/website.go b/backend/app/dto/request/website.go index f87a32c90..379e185a0 100644 --- a/backend/app/dto/request/website.go +++ b/backend/app/dto/request/website.go @@ -141,9 +141,11 @@ type WebsiteNginxUpdate struct { } type WebsiteLogReq struct { - ID uint `json:"id" validate:"required"` - Operate string `json:"operate" validate:"required"` - LogType string `json:"logType" validate:"required"` + ID uint `json:"id" validate:"required"` + Operate string `json:"operate" validate:"required"` + LogType string `json:"logType" validate:"required"` + Page int `json:"page"` + PageSize int `json:"pageSize"` } type WebsiteDefaultUpdate struct { diff --git a/backend/app/dto/response/website.go b/backend/app/dto/response/website.go index e2d8f77ff..66ed28de8 100644 --- a/backend/app/dto/response/website.go +++ b/backend/app/dto/response/website.go @@ -41,6 +41,7 @@ type WebsiteHTTPS struct { type WebsiteLog struct { Enable bool `json:"enable"` Content string `json:"content"` + End bool `json:"end"` } type PHPConfig struct { diff --git a/backend/app/service/website.go b/backend/app/service/website.go index c624c998f..638ef078a 100644 --- a/backend/app/service/website.go +++ b/backend/app/service/website.go @@ -931,19 +931,12 @@ func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.Websi } } filePath := path.Join(sitePath, "log", req.LogType) - fileInfo, err := os.Stat(filePath) + lines, end, err := files.ReadFileByLine(filePath, req.Page, req.PageSize) if err != nil { return nil, err } - if fileInfo.Size() > 20<<20 { - return nil, buserr.New(constant.ErrFileToLarge) - } - fileInfo.Size() - content, err := os.ReadFile(filePath) - if err != nil { - return nil, err - } - res.Content = string(content) + res.End = end + res.Content = strings.Join(lines, "\n") return res, nil case constant.DisableLog: key := "access_log" diff --git a/backend/utils/files/utils.go b/backend/utils/files/utils.go index 6dc4d84de..899195eec 100644 --- a/backend/utils/files/utils.go +++ b/backend/utils/files/utils.go @@ -1,6 +1,7 @@ package files import ( + "bufio" "github.com/spf13/afero" "net/http" "os" @@ -75,3 +76,36 @@ const dotCharacter = 46 func IsHidden(path string) bool { return path[0] == dotCharacter } + +func ReadFileByLine(filename string, page, pageSize int) ([]string, bool, error) { + file, err := os.Open(filename) + if err != nil { + return nil, false, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + + var lines []string + currentLine := 0 + startLine := (page - 1) * pageSize + endLine := startLine + pageSize + + for scanner.Scan() { + if currentLine >= startLine && currentLine < endLine { + lines = append(lines, scanner.Text()) + } + currentLine++ + if currentLine >= endLine { + break + } + } + + if err := scanner.Err(); err != nil { + return nil, false, err + } + + isEndOfFile := currentLine < endLine + + return lines, isEndOfFile, nil +} diff --git a/frontend/src/api/interface/website.ts b/frontend/src/api/interface/website.ts index f89dcc1bb..a09556e95 100644 --- a/frontend/src/api/interface/website.ts +++ b/frontend/src/api/interface/website.ts @@ -82,11 +82,14 @@ export namespace Website { id: number; operate: string; logType: string; + page?: number; + pageSize?: number; } export interface WebSiteLog { enable: boolean; content: string; + end: boolean; } export interface Domain { diff --git a/frontend/src/views/website/website/config/log/log-fiile/index.vue b/frontend/src/views/website/website/config/log/log-fiile/index.vue index dc739fb2a..a27bc7492 100644 --- a/frontend/src/views/website/website/config/log/log-fiile/index.vue +++ b/frontend/src/views/website/website/config/log/log-fiile/index.vue @@ -23,6 +23,7 @@
@@ -43,7 +44,7 @@ import { Codemirror } from 'vue-codemirror'; import { javascript } from '@codemirror/lang-javascript'; import { oneDark } from '@codemirror/theme-one-dark'; -import { computed, nextTick, onMounted, onUnmounted, ref, shallowRef } from 'vue'; +import { computed, nextTick, onMounted, onUnmounted, reactive, ref, shallowRef } from 'vue'; import { OpWebsiteLog } from '@/api/modules/website'; import { dateFormatForName, downloadWithContent } from '@/utils/util'; import { useDeleteData } from '@/hooks/use-delete-data'; @@ -74,31 +75,52 @@ const tailLog = ref(false); let timer: NodeJS.Timer | null = null; const view = shallowRef(); +const editorContainer = ref(null); const handleReady = (payload) => { view.value = payload.view; + editorContainer.value = payload.container; }; +const content = ref(''); +const end = ref(false); +const lastContent = ref(''); + +const readReq = reactive({ + id: id.value, + operate: 'get', + logType: logType.value, + page: 0, + pageSize: 500, +}); const getContent = () => { - const req = { - id: id.value, - operate: 'get', - logType: logType.value, - }; - loading.value = true; - OpWebsiteLog(req) - .then((res) => { - data.value = res.data; - nextTick(() => { - const state = view.value.state; - view.value.dispatch({ - selection: { anchor: state.doc.length, head: state.doc.length }, - scrollIntoView: true, - }); + if (!end.value) { + readReq.page += 1; + } + OpWebsiteLog(readReq).then((res) => { + if (!end.value && res.data.end) { + lastContent.value = content.value; + } + data.value = res.data; + if (res.data.content != '') { + if (end.value) { + content.value = lastContent.value + '\n' + res.data.content; + } else { + if (content.value == '') { + content.value = res.data.content; + } else { + content.value = content.value + '\n' + res.data.content; + } + } + } + end.value = res.data.end; + nextTick(() => { + const state = view.value.state; + view.value.dispatch({ + selection: { anchor: state.doc.length, head: state.doc.length }, }); - }) - .finally(() => { - loading.value = false; + view.value.focus(); }); + }); }; const changeTail = () => { @@ -152,8 +174,23 @@ const onCloseLog = async () => { timer = null; }; +function isScrolledToBottom(element: HTMLElement): boolean { + return element.scrollTop + element.clientHeight === element.scrollHeight; +} + onMounted(() => { getContent(); + nextTick(() => { + let editorElement = editorContainer.value.querySelector('.cm-editor'); + let scrollerElement = editorElement.querySelector('.cm-scroller') as HTMLElement; + if (scrollerElement) { + scrollerElement.addEventListener('scroll', function () { + if (isScrolledToBottom(scrollerElement)) { + getContent(); + } + }); + } + }); }); onUnmounted(() => {