mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-03-19 05:39:26 +08:00
feat: 网站日志页面优化
This commit is contained in:
parent
48054b05ce
commit
28de822917
@ -320,3 +320,17 @@ func (b *BaseApi) UpdateWebsiteNginxConfig(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) OpWebsiteLog(c *gin.Context) {
|
||||||
|
var req request.WebsiteLogReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := websiteService.OpWebsiteLog(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, res)
|
||||||
|
}
|
||||||
|
@ -116,3 +116,9 @@ type WebsiteNginxUpdate struct {
|
|||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
Content string `json:"content" validate:"required"`
|
Content string `json:"content" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteLogReq struct {
|
||||||
|
ID uint `json:"id" validate:"required"`
|
||||||
|
Operate string `json:"operate" validate:"required"`
|
||||||
|
LogType string `json:"logType" validate:"required"`
|
||||||
|
}
|
||||||
|
@ -36,3 +36,8 @@ type WebsiteHTTPS struct {
|
|||||||
SSLProtocol []string `json:"SSLProtocol"`
|
SSLProtocol []string `json:"SSLProtocol"`
|
||||||
Algorithm string `json:"algorithm"`
|
Algorithm string `json:"algorithm"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsiteLog struct {
|
||||||
|
Enable bool `json:"enable"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
@ -16,6 +16,8 @@ type Website struct {
|
|||||||
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
||||||
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
||||||
Proxy string `gorm:"type:varchar(128);not null" json:"proxy"`
|
Proxy string `gorm:"type:varchar(128);not null" json:"proxy"`
|
||||||
|
ErrorLog bool `json:"errorLog"`
|
||||||
|
AccessLog bool `json:"accessLog"`
|
||||||
Domains []WebsiteDomain `json:"domains"`
|
Domains []WebsiteDomain `json:"domains"`
|
||||||
WebsiteSSL WebsiteSSL `json:"webSiteSSL"`
|
WebsiteSSL WebsiteSSL `json:"webSiteSSL"`
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,6 @@ func getNginxParamsByKeys(scope string, keys []string, website *model.Website) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateNginxConfig(scope string, params []dto.NginxParam, website *model.Website) error {
|
func updateNginxConfig(scope string, params []dto.NginxParam, website *model.Website) error {
|
||||||
|
|
||||||
nginxFull, err := getNginxFull(website)
|
nginxFull, err := getNginxFull(website)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -49,6 +49,8 @@ type IWebsiteService interface {
|
|||||||
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
|
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
|
||||||
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
|
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
|
||||||
UpdateWafConfig(req request.WebsiteWafUpdate) error
|
UpdateWafConfig(req request.WebsiteWafUpdate) error
|
||||||
|
UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error
|
||||||
|
OpWebsiteLog(req request.WebsiteLogReq) (*response.WebsiteLog, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebsiteService() IWebsiteService {
|
func NewWebsiteService() IWebsiteService {
|
||||||
@ -707,3 +709,71 @@ func (w WebsiteService) UpdateNginxConfigFile(req request.WebsiteNginxUpdate) er
|
|||||||
}
|
}
|
||||||
return nginxCheckAndReload(nginxFull.SiteConfig.OldContent, filePath, nginxFull.Install.ContainerName)
|
return nginxCheckAndReload(nginxFull.SiteConfig.OldContent, filePath, nginxFull.Install.ContainerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w WebsiteService) OpWebsiteLog(req request.WebsiteLogReq) (*response.WebsiteLog, error) {
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nginx, err := getNginxFull(&website)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sitePath := path.Join(nginx.SiteDir, "sites", website.Alias)
|
||||||
|
res := &response.WebsiteLog{
|
||||||
|
Content: "",
|
||||||
|
}
|
||||||
|
switch req.Operate {
|
||||||
|
case constant.GetLog:
|
||||||
|
switch req.LogType {
|
||||||
|
case constant.AccessLog:
|
||||||
|
res.Enable = website.AccessLog
|
||||||
|
if !website.AccessLog {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
case constant.ErrorLog:
|
||||||
|
res.Enable = website.ErrorLog
|
||||||
|
if !website.ErrorLog {
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content, err := os.ReadFile(path.Join(sitePath, "log", req.LogType))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.Content = string(content)
|
||||||
|
return res, nil
|
||||||
|
case constant.DisableLog:
|
||||||
|
key := "access_log"
|
||||||
|
switch req.LogType {
|
||||||
|
case constant.AccessLog:
|
||||||
|
website.AccessLog = false
|
||||||
|
case constant.ErrorLog:
|
||||||
|
key = "error_log"
|
||||||
|
website.ErrorLog = false
|
||||||
|
}
|
||||||
|
if err := deleteNginxConfig(constant.NginxScopeServer, []string{key}, &website); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := websiteRepo.Save(context.Background(), &website); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case constant.EnableLog:
|
||||||
|
key := "access_log"
|
||||||
|
logPath := path.Join("/www", "sites", website.Alias, "log", req.LogType)
|
||||||
|
switch req.LogType {
|
||||||
|
case constant.AccessLog:
|
||||||
|
website.AccessLog = true
|
||||||
|
case constant.ErrorLog:
|
||||||
|
key = "error_log"
|
||||||
|
website.ErrorLog = true
|
||||||
|
}
|
||||||
|
if err := updateNginxConfig(constant.NginxScopeServer, []dto.NginxParam{{Name: key, Params: []string{logPath}}}, &website); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := websiteRepo.Save(context.Background(), &website); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
@ -32,4 +32,11 @@ const (
|
|||||||
HTTPSOnly = "HTTPSOnly"
|
HTTPSOnly = "HTTPSOnly"
|
||||||
HTTPAlso = "HTTPAlso"
|
HTTPAlso = "HTTPAlso"
|
||||||
HTTPToHTTPS = "HTTPToHTTPS"
|
HTTPToHTTPS = "HTTPToHTTPS"
|
||||||
|
|
||||||
|
GetLog = "get"
|
||||||
|
DisableLog = "disable"
|
||||||
|
EnableLog = "enable"
|
||||||
|
|
||||||
|
AccessLog = "access.log"
|
||||||
|
ErrorLog = "error.log"
|
||||||
)
|
)
|
||||||
|
@ -18,6 +18,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
|||||||
groupRouter.POST("/search", baseApi.PageWebsite)
|
groupRouter.POST("/search", baseApi.PageWebsite)
|
||||||
groupRouter.POST("", baseApi.CreateWebsite)
|
groupRouter.POST("", baseApi.CreateWebsite)
|
||||||
groupRouter.POST("/operate", baseApi.OpWebsite)
|
groupRouter.POST("/operate", baseApi.OpWebsite)
|
||||||
|
groupRouter.POST("/log", baseApi.OpWebsiteLog)
|
||||||
groupRouter.POST("/check", baseApi.CreateWebsiteCheck)
|
groupRouter.POST("/check", baseApi.CreateWebsiteCheck)
|
||||||
groupRouter.GET("/options", baseApi.GetWebsiteOptions)
|
groupRouter.GET("/options", baseApi.GetWebsiteOptions)
|
||||||
groupRouter.POST("/update", baseApi.UpdateWebsite)
|
groupRouter.POST("/update", baseApi.UpdateWebsite)
|
||||||
|
@ -76,6 +76,17 @@ export namespace Website {
|
|||||||
operate: string;
|
operate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WebSiteOpLog {
|
||||||
|
id: number;
|
||||||
|
operate: string;
|
||||||
|
logType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebSiteLog {
|
||||||
|
enable: boolean;
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Group extends CommonModel {
|
export interface Group extends CommonModel {
|
||||||
name: string;
|
name: string;
|
||||||
default: boolean;
|
default: boolean;
|
||||||
|
@ -15,6 +15,10 @@ export const OpWebsite = (req: Website.WebSiteOp) => {
|
|||||||
return http.post<any>(`/websites/operate`, req);
|
return http.post<any>(`/websites/operate`, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const OpWebsiteLog = (req: Website.WebSiteOpLog) => {
|
||||||
|
return http.post<Website.WebSiteLog>(`/websites/log`, req);
|
||||||
|
};
|
||||||
|
|
||||||
export const BackupWebsite = (req: Website.BackupReq) => {
|
export const BackupWebsite = (req: Website.BackupReq) => {
|
||||||
return http.post(`/websites/backup`, req);
|
return http.post(`/websites/backup`, req);
|
||||||
};
|
};
|
||||||
|
@ -952,6 +952,7 @@ export default {
|
|||||||
ever: '永久',
|
ever: '永久',
|
||||||
nextYear: '一年后',
|
nextYear: '一年后',
|
||||||
allGroup: '所有分组',
|
allGroup: '所有分组',
|
||||||
|
noLog: '当前没有日志...',
|
||||||
},
|
},
|
||||||
nginx: {
|
nginx: {
|
||||||
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',
|
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-tabs tab-position="left" type="border-card" v-model="index">
|
<el-tabs tab-position="left" type="border-card" v-model="index">
|
||||||
<el-tab-pane :label="$t('website.accessLog')" name="0">
|
<el-tab-pane :label="$t('website.accessLog')" name="0">
|
||||||
<LogFile :path="website.accessLogPath" v-if="index == '0'"></LogFile>
|
<LogFile :id="id" :log-type="'access.log'" v-if="index == '0'"></LogFile>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="$t('website.errLog')" name="1">
|
<el-tab-pane :label="$t('website.errLog')" name="1">
|
||||||
<LogFile :path="website.errorLogPath" v-if="index == '1'"></LogFile>
|
<LogFile :id="id" :log-type="'error.log'" v-if="index == '1'"></LogFile>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { GetWebsite } from '@/api/modules/website';
|
import { computed, ref } from 'vue';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
|
||||||
import LogFile from './log-fiile/index.vue';
|
import LogFile from './log-fiile/index.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -24,23 +23,5 @@ const id = computed(() => {
|
|||||||
return props.id;
|
return props.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
let loading = ref(false);
|
let index = ref('0');
|
||||||
let website = ref();
|
|
||||||
let index = ref('-1');
|
|
||||||
|
|
||||||
const getWebsite = () => {
|
|
||||||
loading.value = true;
|
|
||||||
GetWebsite(id.value)
|
|
||||||
.then((res) => {
|
|
||||||
website.value = res.data;
|
|
||||||
index.value = '0';
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
getWebsite();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,46 +1,81 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-loading="loading">
|
<div v-loading="loading">
|
||||||
|
<el-form-item prop="enable" :label="$t('website.enable')">
|
||||||
|
<el-switch v-model="data.enable" @change="updateEnable"></el-switch>
|
||||||
|
</el-form-item>
|
||||||
<codemirror
|
<codemirror
|
||||||
|
style="max-height: 500px; width: 100%; min-height: 200px"
|
||||||
:autofocus="true"
|
:autofocus="true"
|
||||||
placeholder="None data"
|
:placeholder="$t('website.noLog')"
|
||||||
:indent-with-tab="true"
|
:indent-with-tab="true"
|
||||||
:tabSize="4"
|
:tabSize="4"
|
||||||
style="margin-top: 10px; max-height: 500px"
|
|
||||||
:lineWrapping="true"
|
:lineWrapping="true"
|
||||||
:matchBrackets="true"
|
:matchBrackets="true"
|
||||||
theme="cobalt"
|
theme="cobalt"
|
||||||
:styleActiveLine="true"
|
:styleActiveLine="true"
|
||||||
:extensions="extensions"
|
:extensions="extensions"
|
||||||
v-model="content"
|
v-model="data.content"
|
||||||
:readOnly="true"
|
:readOnly="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Codemirror } from 'vue-codemirror';
|
import { Codemirror } from 'vue-codemirror';
|
||||||
import { GetFileContent } from '@/api/modules/files';
|
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { oneDark } from '@codemirror/theme-one-dark';
|
import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
import { OpWebsiteLog } from '@/api/modules/website';
|
||||||
|
|
||||||
const extensions = [javascript(), oneDark];
|
const extensions = [javascript(), oneDark];
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
path: {
|
logType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const path = computed(() => {
|
const logType = computed(() => {
|
||||||
return props.path;
|
return props.logType;
|
||||||
|
});
|
||||||
|
const id = computed(() => {
|
||||||
|
return props.id;
|
||||||
});
|
});
|
||||||
let loading = ref(false);
|
let loading = ref(false);
|
||||||
let content = ref('');
|
let data = ref({
|
||||||
|
enable: false,
|
||||||
|
content: '',
|
||||||
|
});
|
||||||
|
|
||||||
const getContent = () => {
|
const getContent = () => {
|
||||||
|
const req = {
|
||||||
|
id: id.value,
|
||||||
|
operate: 'get',
|
||||||
|
logType: logType.value,
|
||||||
|
};
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
GetFileContent({ path: path.value, expand: false, page: 1, pageSize: 1 })
|
OpWebsiteLog(req)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
content.value = res.data.content;
|
data.value = res.data;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateEnable = () => {
|
||||||
|
const operate = data.value.enable ? 'enable' : 'disable';
|
||||||
|
const req = {
|
||||||
|
id: id.value,
|
||||||
|
operate: operate,
|
||||||
|
logType: logType.value,
|
||||||
|
};
|
||||||
|
loading.value = true;
|
||||||
|
OpWebsiteLog(req)
|
||||||
|
.then(() => {
|
||||||
|
getContent();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user