mirror of https://github.com/1Panel-dev/1Panel
feat: 网站增加启动 停止功能
parent
3c5ab1c68a
commit
9ce02b14c8
|
@ -1 +0,0 @@
|
|||
站点创建成功
|
|
@ -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,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) no-repeat top center;
|
||||
padding-top:160px;
|
||||
margin-top:30%;
|
||||
font-weight:normal;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="box">
|
||||
<h1>抱歉!该站点已经被管理员停止运行,请联系管理员了解详情!</h1>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -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 {
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -25,4 +25,7 @@ const (
|
|||
DnsManual = "dnsManual"
|
||||
Http = "http"
|
||||
Manual = "manual"
|
||||
|
||||
StartWeb = "start"
|
||||
StopWeb = "stop"
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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 });
|
||||
|
|
|
@ -906,6 +906,8 @@ export default {
|
|||
videoSite: '视频',
|
||||
errLog: '错误日志',
|
||||
accessLog: '网站日志',
|
||||
stopHelper: '停止站点后将无法正常访问,用户访问会显示当前站点停止页面,是否继续操作?',
|
||||
startHelper: '启用站点后,用户可以正常访问网站内容,是否继续操作?',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue