From 9f0d957145eae9c222cf3402ccaa0494b19b2095 Mon Sep 17 00:00:00 2001
From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com>
Date: Fri, 25 Aug 2023 23:42:14 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BD=91=E7=AB=99=E6=97=A5=E5=BF=97?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AF=BB=E5=8F=96=2010M=20=E4=BB=A5=E4=B8=8A?=
=?UTF-8?q?=E6=96=87=E4=BB=B6=20(#2072)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
backend/app/dto/request/website.go | 8 +-
backend/app/dto/response/website.go | 1 +
backend/app/service/website.go | 13 +---
backend/utils/files/utils.go | 34 ++++++++
frontend/src/api/interface/website.ts | 3 +
.../website/config/log/log-fiile/index.vue | 77 ++++++++++++++-----
6 files changed, 103 insertions(+), 33 deletions(-)
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(() => {