Skip to content

Commit

Permalink
feat: complete the docking system settings page to view the log infor…
Browse files Browse the repository at this point in the history
…mation in real time. #9
  • Loading branch information
PBK-B committed Apr 9, 2023
1 parent c5af9fa commit 485a0e9
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 16 deletions.
15 changes: 15 additions & 0 deletions controllers/apis/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (
"errors"
"fmt"
"gpt-zmide-server/helper"
"gpt-zmide-server/helper/logger"
"gpt-zmide-server/models"
"net/url"
"os"
"strconv"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -141,6 +143,19 @@ func (ctl *Config) ConfigInfoSave(c *gin.Context) {
ctl.Success(c, "ok!")
}

func (ctl *Config) GetSystemLogs(c *gin.Context) {
log := ""
_, err := os.Stat(logger.LOG_FILE_PATH)
if err == nil {
// 文件存在,读取配置文件
content, err := os.ReadFile(logger.LOG_FILE_PATH)
if err == nil {
log = string(content)
}
}
ctl.Success(c, log)
}

// 配置站点
func (ctl *Config) siteConfig(data string) error {
type SiteConfig struct {
Expand Down
4 changes: 3 additions & 1 deletion helper/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"gopkg.in/natefinch/lumberjack.v2"
)

var LOG_FILE_PATH = "./debug.log"

var (
_logger *zap.Logger
once sync.Once
Expand Down Expand Up @@ -74,7 +76,7 @@ func getEncoder() zapcore.Encoder {

func getWriteSync() zapcore.WriteSyncer {
loggerFileWriter := lumberjack.Logger{
Filename: "./debug.log", // 日志文件路径
Filename: LOG_FILE_PATH, // 日志文件路径
MaxSize: 50, // 每个日志文件保存的最大尺寸 单位:M
MaxBackups: 1, // 日志文件最多保存多少个备份
MaxAge: 30, // 文件最多保存多少天
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
},
"dependencies": {
"@arco-design/web-react": "^2.46.0",
"@monaco-editor/react": "^4.5.0",
"axios": "^1.3.4",
"axios-hooks": "^4.0.0",
"monaco-editor": "^0.37.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.9.0"
Expand Down
1 change: 1 addition & 0 deletions routers/routers.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func BuildRouter(r *gin.Engine) *gin.Engine {
adminConfig.GET("/ping/openai", apisCtlConfig.PingOpenAI)
adminConfig.GET("/system/config", apisCtlConfig.ConfigInfo)
adminConfig.POST("/system/config", apisCtlConfig.ConfigInfoSave)
adminConfig.GET("/system/log", apisCtlConfig.GetSystemLogs)

// 后台管理应用接口
adminApp := adminApis.Group("/application")
Expand Down
87 changes: 87 additions & 0 deletions src/pages/admin/screens/system/Logs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* @Author: Bin
* @Date: 2023-04-09
* @FilePath: /gpt-zmide-server/src/pages/admin/screens/system/Logs.tsx
*/
import React, { useRef, useEffect } from 'react'

import { MonacoLanguageLog } from '@/pages/admin/utils';
import Editor, { Monaco, OnMount } from '@monaco-editor/react';
import { editor as MonacoEditor } from 'monaco-editor';
import useAxios from 'axios-hooks';

export default function Logs(props: any) {
const [{ data, error, loading }, refresh] = useAxios("/api/admin/config/system/log")

const refreshRuntime = useRef<any>(null)
useEffect(() => {
if (refreshRuntime.current === null) {
refreshRuntime.current = setInterval(() => {
refresh()
}, 2000)
}
return () => {
clearInterval(refreshRuntime.current)
refreshRuntime.current = undefined
}
}, [])

const monacoEditor = useRef<MonacoEditor.IStandaloneCodeEditor>()
const handleEditorWillMount = (monaco: Monaco) => {
MonacoLanguageLog(monaco)
}

const handleEditorDidMount: OnMount = (editor, monaco) => {
monacoEditor.current = editor
listenScrollRefreshEvent(editor)
}

// 滚动刷新
const enableScrollingRefresh = useRef(true)
const autoScrollRefresh = useRef(false)
const scrollToRefresh = () => {
if (!monacoEditor.current || !enableScrollingRefresh) { return }
const editor = monacoEditor.current
const lineCount = editor.getModel()?.getLineCount() || 0
autoScrollRefresh.current = true
editor.revealLine(lineCount)
}
const listenScrollRefreshEvent = (editor: MonacoEditor.IStandaloneCodeEditor) => {
if (!editor) { return }
editor.onDidScrollChange((e) => {
const eViewHeight = editor.getDomNode()?.clientHeight || 0
if (e.scrollTop > 0) {
if (!autoScrollRefresh.current) {
if (eViewHeight + e.scrollTop === e.scrollHeight) {
enableScrollingRefresh.current = true
} else {
enableScrollingRefresh.current = false
}
}
autoScrollRefresh.current = false
// console.log("enableScrollingRefresh", enableScrollingRefresh.current);
}
})
}

useEffect(() => {
if (data?.data && enableScrollingRefresh.current) {
scrollToRefresh()
}
}, [data, enableScrollingRefresh.current])

return <Editor
width="70vw"
height="80vh"
theme="logview"
defaultLanguage="log"
value={data?.data || ''}
options={{
scrollBeyondLastLine: false,
automaticLayout: true,
readOnly: true
}}
beforeMount={handleEditorWillMount}
onMount={handleEditorDidMount}
/>
}
56 changes: 41 additions & 15 deletions src/pages/admin/screens/system/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,30 @@
* @Date: 2023-03-27
* @FilePath: /gpt-zmide-server/src/pages/admin/screens/system/index.tsx
*/
import React, { ReactElement, useEffect } from 'react'
import { Tabs, Form, Input, Button, Spin, Message } from '@arco-design/web-react';
import React, { ReactElement, useEffect, useMemo, useRef } from 'react'
import useAxios from 'axios-hooks';

import { Tabs, Form, Input, Button, Spin, Message } from '@arco-design/web-react';

import { axios } from '@/apis';

import SystemLogs from './Logs';

const TabPane = Tabs.TabPane;
const FormItem = Form.Item;

type FormViewProps = {
fromData?: any,
setFromData?: (data: any) => void,
}

type TabsViewProps = {
label: string,
key: string,
view: ((props: FormViewProps) => JSX.Element) | ReactElement<any, any>,
style?: 'form' | 'view'
}

export default function index() {

const [{ data: configData, loading: configLoading, error: infoError }] = useAxios({
Expand All @@ -20,10 +36,7 @@ export default function index() {
const [tabsIndex, setTabsIndex] = React.useState(1)
const [tabsFromData, setTabsFromData] = React.useState<any[]>([])

type FormViewProps = {
fromData?: any,
setFromData?: (data: any) => void,
}


// 获取表单数据
const tabsFromDataConfig = React.useMemo<any>(() => {
Expand All @@ -47,7 +60,7 @@ export default function index() {
[tabsIndex],
)

const tabsView: { label: string, key: string, view: ((props: FormViewProps) => JSX.Element) | ReactElement<any, any> }[] = [
const tabsView: TabsViewProps[] = useMemo(() => [
{
label: '站点信息配置',
key: 'site_config',
Expand Down Expand Up @@ -142,7 +155,18 @@ export default function index() {
</Form>
}
},
]
{
label: '系统日志信息',
key: 'system_logs',
style: 'view',
view: (props: any) => {
return <>
<p style={{ marginBottom: 10 }}>系统日志</p>
<SystemLogs {...props} />
</>
}
},
], [])

const selectTabsView = React.useMemo(() => tabsView[tabsIndex].view, [tabsIndex])

Expand Down Expand Up @@ -248,12 +272,13 @@ export default function index() {
<Tabs defaultActiveTab={tabsView[0].key} tabPosition='left' onChange={(key) => {
setTabsIndex(tabsView.findIndex((item) => item.key == key))
}}>
{tabsView.map((item, index) =>
<TabPane key={item.key} title={item.label}>
{(typeof selectTabsView === "function" ? selectTabsView({
fromData: { ...tabsFromDataConfig },
setFromData: setTabsFromDataConfig,
}) : selectTabsView)}
{tabsView.map((item, index) => <TabPane key={item.key} title={item.label}>
{index === tabsIndex && (typeof selectTabsView === "function" ? selectTabsView({
fromData: { ...tabsFromDataConfig },
setFromData: setTabsFromDataConfig,
}) : selectTabsView)}

{item.style !== "view" && (
<Button
type="primary"
onClick={() => onClickSubmitConfig(tabsIndex, tabsFromData)}
Expand All @@ -262,7 +287,8 @@ export default function index() {
>
保存
</Button>
</TabPane>
)}
</TabPane>
)}
</Tabs>
) : ""}
Expand Down
Loading

0 comments on commit 485a0e9

Please sign in to comment.