feat: 网站增加启动 停止功能

This commit is contained in:
zhengkunwang223 2022-12-26 16:09:21 +08:00 committed by zhengkunwang223
parent 3c5ab1c68a
commit 9ce02b14c8
13 changed files with 149 additions and 5 deletions

View file

@ -1 +0,0 @@
站点创建成功

View file

@ -0,0 +1,33 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>抱歉,站点已暂停</title>
<style>
html,body,div,h1,*{margin:0;padding:0;}
body{
background-color:#fefefe;
color:#333
}
.box{
width:580px;
margin:0 auto;
}
h1{
font-size:20px;
text-align:center;
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAQAAABpN6lAAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAH+UlEQVR42uyde3AV1RnAfyFpTCBpFIVoaxUpSQSEAezwMDUJRK11DOTDAjJTtPRBBx1bK/VRO7T1VdFCRx6j6DgjltaamcIJWBpICRg0MFjGio6BRGKp4iOUMtBEkiBJ+ocxzQ17957de3bv3WY//mDYc75zzve73549z4+Ubga2DCIEEAIIAYQAQgAhgBBACCAEEAIIAYQAQgAhgBBACCAEEAIIAYQAQgADR9L8q0pyGUM+BRRwIVlkk00mp2ilhRaaaaCBRupVs78AUrzfF5ChlFBKKQVa2RuooYaX1fH/AwCSgfAdrnHxonWxneeoVO2BBSBj+BHzODeuQk5QwSpVHzgAMo6l3GSog+1iAw+ptwIDQPJZRjkpRgvtRnGfeifpAUgGP+NezvHkp+rgMR413ycYBCDX8hRf9bTHOsRt6q9JCUDSeJQlhh3f+mVYzv3qTJIBkIup4Crfxi6vcrP6IIkAyNVs5AJfh2/HmK1eSZK5gJRR7bP5cAHb5MakACC3sJGMBMxhMlGyIOEAZBHr/JxO9ZvGPS8/SGgfILPYQGpC57KdzFabEwRACtmeEOePlDZK1Z4EAJBR7GVoUqxoHGeKOuRzHyDpVCSJ+TCUFyXd707wN0wieeRKHvP1FZCZbCLZpEz92ScAkkMDuZqZD7CTowxnBpc7fK+3cJghTKBE00ebKVAn3X1NncrDmuYf4YfqL33Gi09zkZbeaR5kuero0cvjaaZraOXyAHf64AEygX1a3/5/UKzej9AcSS0Xx9Rrp1xti9BLZR3f1qjxDJPcrBs57QTXaJl/mvJI80G9yzy6Ymr+ONJ8UJ0s5G9avrzG86+AfJNCrYxPqDfPfqh281wMvT3qGQu9M+gNeYvkWq894OdaubpYFSVlZQzN31o/VvupMdg+twCkRPP3fyPacoV6iw9t3+KtUdNe0qq5WAq99ID7NfO9bpP2d5u0g6o1atpeoz7qBoCMRPcNO+YyrdllWl+5Xi7xygNu0c6Z6jJtkEu9iM86CzwBIE4KHm6TNsx2MOOuTLc/lCMPKGSkdpmTbTB+zUbvcsmJmjZVu/Z8meoFgHIHZY6WvKhmnG/bljIj9Zd7AaDEkV/dFeX5T2LoLRHL9sg0rnZQ+3TjAORcJjoCsEgstknkOubE0JvAEgu9DJ51tj4gXzTtAUUOR4yD+FP/10DG8gcNzV/Lt/rppVPBGEe1p1JkGoDj8RUXUSdzJeXzzk/ms0tr+ySNP8ojktkH28vMdFy7g/ZqTYdlk4tGfDYp3sG/GEYpIxzptVDFYQYziWmuNlwrlZhdEMnHnVzG91zpZTOXeCTfqAdIKqdIJ0jSwWDVZa4PuDRg5sM5XGqyExxO8GSYSQBZAQSQbRJAdgABZA10DzAKICOAADJNAmgLIIA2kwBaAwigdaADaAk9wCCAowEEcNQkgH9yOmDmd/CeQQCqk3cDBqBJdyqkuyDSGDAADtqrtx5wwOWCSKR8yiEOUE89H9HS8yeNLIYwhGxGkMco8hitP4iJKgdNA6iLqzndvMk2tlKnrPqSEz1/1/asPqQzjRmUMpkvuK7xVf2sektiORx3eZ6siSd5QX3sXFGGcSvf17xqFymdDFX/MQoAZB9XOm7IVlZTpeI6jy9F/NRmu8RaXlNTTL8CsNMhgD0sie8Ia88XaBe7ZDKro2+3WcgOJzXoOnalo2HobRSaML8HwmtM5Q4HUzJHpxi1T4lJk+b26H7meHHBTcayWasFjcpRv6F/TnA9v9TItYV56pOoRgxiFOP4Cl8il8FkkM6ntNPOMT7iQw7ytjoV1Q/elilU2e4ufya/cwZW3wNG0hTbW5mjOi21x3MD32Ayg231u2ikhmq2W4OQ86hlXIxP7gj1nicAQKpjHJLZw/TPT3j20cplIQsc7u59wibWU332gFZGsM92i71K3eCRB4CUsNMm+QTj+x+OlIncw02uBzSHWcva/ieAZS4VNjpfV3WeAQCps7kdeKda2a/TWkb8N7tOsorHI0+P2XhirSpxWoGz8d0jNvPvtX2aOESeYD8mLrblsJSmfvfDfuWifWY8wMYHHlf39ua5it9zmeGv4FYW/m9ALfWMtsjziipyXrDTEf7tWPby9J4NlbuoNW4+XM9+uab3X82WM4Db3RTsEIB6g6csE4oBJE2eYYVHNwmHUyWLACTFcvt7jbsgC25ujDRabpfOYgsvxLmvH1vuZgVLeeCs565vjJi7M9TN+1yC9/IBX7Z4OlO95K44F7N8tZnVVih9MR9L81e6Nd/ttbm7bU99+y2vc497Zbc3R/PYy3lJYX4ibo6Ceocy2pPA/DbK4jE/juvzqo75dCXY/E7mq93xFRFH/ABVyWIS+V+UdLNYxX2HNc4YInIrzyYohMIZvqvWx19M3EFUZCYVCThD0sY8958+owBAithou0hhXpIpigyoXUxgt4/m72aiKfMNhdRURyhmhU8d33KK1RFzBZqMJXYdT3ocS6yJxaZjiRkMqqqquYKHPTtM0cFDXGHafC/iCRawjFnG4wlWcp/y5JSCNxElx/MLZhuC0M0GHgxQRMleCGO5g5vJiauQk7wYyJiivRAyERYyw1VU2RrWsTHAUWX7YDif6ZQyQ/MiSyM17GCn+rc/g4oU/2YzciFjKOiNLJ1FNpm00UIrLXxMIw00UO/mNElAACSnhNHlQwAhgBBACCAEEAIIAYQAQgAhgBDAgJT/DgDyxCJjaj0UmAAAAABJRU5ErkJggg==) no-repeat top center;
padding-top:160px;
margin-top:30%;
font-weight:normal;
}
</style>
</head>
<body>
<div class="box">
<h1>抱歉!该站点已经被管理员停止运行,请联系管理员了解详情!</h1>
</div>
</body>
</html>

View file

@ -49,6 +49,20 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) OpWebsite(c *gin.Context) {
var req request.WebsiteOp
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
err := websiteService.OpWebsite(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) BackupWebsite(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {

View file

@ -45,6 +45,11 @@ type WebsiteDelete struct {
ForceDelete bool `json:"forceDelete"`
}
type WebsiteOp struct {
ID uint `json:"id" validate:"required"`
Operate string `json:"operate"`
}
type WebsiteWafReq struct {
WebsiteID uint `json:"websiteId" validate:"required"`
Key string `json:"key" validate:"required"`

View file

@ -29,6 +29,7 @@ type WebsiteService struct {
type IWebsiteService interface {
PageWebsite(req request.WebsiteSearch) (int64, []response.WebsiteDTO, error)
CreateWebsite(create request.WebsiteCreate) error
OpWebsite(req request.WebsiteOp) error
GetWebsiteOptions() ([]string, error)
Backup(id uint) error
Recover(req request.WebsiteRecover) error
@ -113,6 +114,7 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) error {
return err
}
appInstall = &install
website.AppInstallID = 0
}
}
@ -153,6 +155,17 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) error {
return nil
}
func (w WebsiteService) OpWebsite(req request.WebsiteOp) error {
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
if err != nil {
return err
}
if err := opWebsite(&website, req.Operate); err != nil {
return err
}
return websiteRepo.Save(context.Background(), &website)
}
func (w WebsiteService) GetWebsiteOptions() ([]string, error) {
webs, err := websiteRepo.GetBy()
if err != nil {

View file

@ -162,7 +162,6 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
_ = deleteWebsiteFolder(nginxInstall, website)
return err
}
return nil
}
@ -567,3 +566,47 @@ func deleteWebsiteFolder(nginxInstall model.AppInstall, website *model.Website)
}
return nil
}
func opWebsite(website *model.Website, operate string) error {
nginxInstall, err := getNginxFull(website)
if err != nil {
return err
}
config := nginxInstall.SiteConfig.Config
servers := config.FindServers()
if len(servers) == 0 {
return errors.New("nginx config is not valid")
}
server := servers[0]
if operate == constant.StopWeb {
if website.Type != constant.Static {
server.RemoveDirective("location", []string{"/"})
}
server.UpdateRoot("/usr/share/nginx/html/stop")
website.Status = constant.WebStopped
}
if operate == constant.StartWeb {
switch website.Type {
case constant.Deployment:
server.RemoveDirective("root", nil)
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
if err != nil {
return err
}
proxy := fmt.Sprintf("http://127.0.0.1:%d", appInstall.HttpPort)
server.UpdateRootProxy([]string{proxy})
case constant.Static:
server.UpdateRoot(path.Join("/www/sites", website.Alias, "index"))
server.UpdateRootLocation()
case constant.Proxy:
server.RemoveDirective("root", nil)
server.UpdateRootProxy([]string{website.Proxy})
}
website.Status = constant.WebRunning
}
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return err
}
return nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName)
}

View file

@ -25,4 +25,7 @@ const (
DnsManual = "dnsManual"
Http = "http"
Manual = "manual"
StartWeb = "start"
StopWeb = "stop"
)

View file

@ -17,6 +17,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
{
groupRouter.POST("/search", baseApi.PageWebsite)
groupRouter.POST("", baseApi.CreateWebsite)
groupRouter.POST("/operate", baseApi.OpWebsite)
groupRouter.POST("/check", baseApi.CreateWebsiteCheck)
groupRouter.GET("/options", baseApi.GetWebsiteOptions)
groupRouter.POST("/update", baseApi.UpdateWebsite)

View file

@ -68,6 +68,11 @@ export namespace Website {
webSiteGroupId: number;
}
export interface WebSiteOp {
id: number;
operate: string;
}
export interface Group extends CommonModel {
name: string;
default: boolean;

View file

@ -11,6 +11,10 @@ export const CreateWebsite = (req: Website.WebSiteCreateReq) => {
return http.post<any>(`/websites`, req);
};
export const OpWebsite = (req: Website.WebSiteOp) => {
return http.post<any>(`/websites/operate`, req);
};
export const BackupWebsite = (req: Website.BackupReq) => {
return http.post(`/websites/backup`, req);
};

View file

@ -26,6 +26,7 @@ const { switchDark } = useTheme();
const loadDataFromDB = async () => {
const res = await getSettingInfo();
i18n.locale.value = res.data.language;
i18n.warnHtmlMessage = false;
globalStore.updateLanguage(res.data.language);
globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme });
globalStore.setThemeConfig({ ...themeConfig.value, panelName: res.data.panelName });

View file

@ -906,6 +906,8 @@ export default {
videoSite: '视频',
errLog: '错误日志',
accessLog: '网站日志',
stopHelper: '停止站点后将无法正常访问用户访问会显示当前站点停止页面是否继续操作',
startHelper: '启用站点后用户可以正常访问网站内容是否继续操作',
},
nginx: {
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',

View file

@ -32,7 +32,17 @@
</el-table-column>
<el-table-column :label="$t('commons.table.status')" prop="status">
<template #default="{ row }">
<Status :key="row.status" :status="row.status"></Status>
<el-button
v-if="row.status === 'Running'"
link
type="success"
@click="opWebsite('stop', row.id)"
>
{{ $t('commons.status.running') }}
</el-button>
<el-button v-else link type="danger" @click="opWebsite('start', row.id)">
{{ $t('commons.status.stopped') }}
</el-button>
</template>
</el-table-column>
<el-table-column :label="$t('website.remark')" prop="remark"></el-table-column>
@ -83,16 +93,16 @@ import { onMounted, reactive, ref } from '@vue/runtime-core';
import CreateWebSite from './create/index.vue';
import DeleteWebsite from './delete/index.vue';
import WebSiteGroup from './group/index.vue';
import { SearchWebsites } from '@/api/modules/website';
import { OpWebsite, SearchWebsites } from '@/api/modules/website';
import { Website } from '@/api/interface/website';
import AppStatus from '@/components/app-status/index.vue';
import NginxConfig from './nginx/index.vue';
import { dateFromat } from '@/utils/util';
import Status from '@/components/status/index.vue';
import i18n from '@/lang';
import router from '@/routers';
import { App } from '@/api/interface/app';
import { ElMessage, ElMessageBox } from 'element-plus';
const loading = ref(false);
@ -190,6 +200,17 @@ const checkExist = (data: App.CheckInstalled) => {
installPath.value = data.installPath;
};
const opWebsite = (op: string, id: number) => {
ElMessageBox.confirm(i18n.global.t('website.' + op + 'Helper'), i18n.global.t('cronjob.changeStatus'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
}).then(async () => {
await OpWebsite({ id: id, operate: op });
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
search();
});
};
onMounted(() => {
search();
});