mirror of
https://gitee.com/fit2cloud-feizhiyun/1Panel.git
synced 2024-11-30 02:47:51 +08:00
feat: 增加一键部署网站功能
This commit is contained in:
parent
ef789cdfea
commit
9621d6ea1f
@ -7,7 +7,7 @@ services:
|
||||
- 1panel
|
||||
ports:
|
||||
- ${PANEL_APP_PORT_HTTP}:6379
|
||||
command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
|
||||
command: redis-server --save 20 1 --loglevel warning --requirepass ${PANEL_DB_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- ./data:/data
|
||||
networks:
|
||||
|
@ -7,7 +7,7 @@ services:
|
||||
- 1panel
|
||||
ports:
|
||||
- ${PANEL_APP_PORT_HTTP}:6379
|
||||
command: redis-server --save 20 1 --loglevel warning --requirepass eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
|
||||
command: redis-server --save 20 1 --loglevel warning --requirepass ${PANEL_DB_ROOT_PASSWORD}
|
||||
volumes:
|
||||
- ./data:/data
|
||||
networks:
|
||||
|
@ -70,12 +70,13 @@ func (b *BaseApi) InstallApp(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := appService.Install(req.Name, req.AppDetailId, req.Params); err != nil {
|
||||
install, err := appService.Install(req.Name, req.AppDetailId, req.Params)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
||||
helper.SuccessWithData(c, nil)
|
||||
helper.SuccessWithData(c, install)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteAppBackup(c *gin.Context) {
|
||||
|
@ -7,14 +7,29 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
||||
func (b *BaseApi) PageWebsite(c *gin.Context) {
|
||||
var req dto.WebSiteReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
total, websites, err := websiteService.PageWebSite(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, dto.PageResult{
|
||||
Total: total,
|
||||
Items: websites,
|
||||
})
|
||||
}
|
||||
|
||||
func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
||||
var req dto.WebSiteCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := websiteService.CreateWebsite(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@ -22,3 +37,17 @@ func (b *BaseApi) CreateWebsite(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteWebSite(c *gin.Context) {
|
||||
var req dto.WebSiteDel
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
err := websiteService.DeleteWebSite(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
@ -2,11 +2,12 @@ package v1
|
||||
|
||||
import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func (b *BaseApi) GetGroups(c *gin.Context) {
|
||||
func (b *BaseApi) GetWebGroups(c *gin.Context) {
|
||||
|
||||
list, err := websiteGroupService.GetGroups()
|
||||
if err != nil {
|
||||
@ -15,3 +16,18 @@ func (b *BaseApi) GetGroups(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, list)
|
||||
}
|
||||
|
||||
func (b *BaseApi) CreateWebGroup(c *gin.Context) {
|
||||
|
||||
var req dto.WebSiteGroupCreate
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := websiteGroupService.CreateGroup(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ type AppRequest struct {
|
||||
PageInfo
|
||||
Name string `json:"name"`
|
||||
Tags []string `json:"tags"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type AppInstallRequest struct {
|
||||
|
@ -1,16 +1,43 @@
|
||||
package dto
|
||||
|
||||
type WebPage struct {
|
||||
import "github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
|
||||
type WebSiteReq struct {
|
||||
PageInfo
|
||||
}
|
||||
|
||||
type AppType string
|
||||
|
||||
const (
|
||||
NewApp AppType = "new"
|
||||
InstalledApp AppType = "installed"
|
||||
)
|
||||
|
||||
type WebSiteCreate struct {
|
||||
PrimaryDomain string `json:"primaryDomain"`
|
||||
Type string `json:"type"`
|
||||
Alias string `json:"alias"`
|
||||
Remark string `json:"remark"`
|
||||
Domains []string `json:"domains"`
|
||||
AppType string `json:"appType"`
|
||||
AppInstallID uint `json:"appInstallID"`
|
||||
WebSiteGroupID uint `json:"webSiteGroupID"`
|
||||
PrimaryDomain string `json:"primaryDomain" validate:"required"`
|
||||
Type string `json:"type" validate:"required"`
|
||||
Alias string `json:"alias" validate:"required"`
|
||||
Remark string `json:"remark"`
|
||||
Domains []string `json:"domains"`
|
||||
AppType AppType `json:"appType" validate:"required"`
|
||||
AppInstall NewAppInstall `json:"appInstall"`
|
||||
AppID uint `json:"appID"`
|
||||
AppInstallID uint `json:"appInstallID"`
|
||||
WebSiteGroupID uint `json:"webSiteGroupID" validate:"required"`
|
||||
}
|
||||
|
||||
type NewAppInstall struct {
|
||||
Name string `json:"name"`
|
||||
AppDetailId uint `json:"appDetailID"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
}
|
||||
|
||||
type WebSiteDel struct {
|
||||
ID uint `json:"id"`
|
||||
DeleteApp bool `json:"deleteApp"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
}
|
||||
|
||||
type WebSiteDTO struct {
|
||||
model.WebSite
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package dto
|
||||
|
||||
type WebSiteGroupCreateReq struct {
|
||||
type WebSiteGroupCreate struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
type WebSiteGroupUpdateReq struct {
|
||||
type WebSiteGroupUpdate struct {
|
||||
ID uint
|
||||
Name string
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
@ -70,10 +71,10 @@ func (c *CommonRepo) WithIdsNotIn(ids []uint) DBOption {
|
||||
}
|
||||
|
||||
func getTx(ctx context.Context, opts ...DBOption) *gorm.DB {
|
||||
if ctx == nil || ctx.Value("db") == nil {
|
||||
if ctx == nil || ctx.Value(constant.DB) == nil {
|
||||
return getDb()
|
||||
}
|
||||
tx := ctx.Value("db").(*gorm.DB)
|
||||
tx := ctx.Value(constant.DB).(*gorm.DB)
|
||||
for _, opt := range opts {
|
||||
tx = opt(tx)
|
||||
}
|
||||
|
@ -43,3 +43,7 @@ func (w WebSiteRepo) Create(ctx context.Context, app *model.WebSite) error {
|
||||
func (w WebSiteRepo) Save(ctx context.Context, app *model.WebSite) error {
|
||||
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
||||
}
|
||||
|
||||
func (w WebSiteRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Delete(&model.WebSite{}).Error
|
||||
}
|
||||
|
@ -3,12 +3,18 @@ package repo
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
type WebSiteDomainRepo struct {
|
||||
}
|
||||
|
||||
func (w WebSiteDomainRepo) WithWebSiteId(websiteId uint) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("web_site_id = ?", websiteId)
|
||||
}
|
||||
}
|
||||
func (w WebSiteDomainRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebSiteDomain, error) {
|
||||
var domains []model.WebSiteDomain
|
||||
db := getDb(opts...).Model(&model.WebSiteDomain{})
|
||||
@ -47,3 +53,7 @@ func (w WebSiteDomainRepo) Create(ctx context.Context, app *model.WebSiteDomain)
|
||||
func (w WebSiteDomainRepo) Save(ctx context.Context, app *model.WebSiteDomain) error {
|
||||
return getTx(ctx).Omit(clause.Associations).Save(app).Error
|
||||
}
|
||||
|
||||
func (w WebSiteDomainRepo) DeleteBy(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Delete(&model.WebSiteDomain{}).Error
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ func (a AppService) PageApp(req dto.AppRequest) (interface{}, error) {
|
||||
if req.Name != "" {
|
||||
opts = append(opts, commonRepo.WithLikeName(req.Name))
|
||||
}
|
||||
if req.Type != "" {
|
||||
opts = append(opts, appRepo.WithType(req.Type))
|
||||
}
|
||||
if len(req.Tags) != 0 {
|
||||
tags, err := tagRepo.GetByKeys(req.Tags)
|
||||
if err != nil {
|
||||
@ -212,7 +215,13 @@ func (a AppService) OperateInstall(req dto.AppInstallOperate) error {
|
||||
}
|
||||
install.Status = constant.Running
|
||||
case dto.Delete:
|
||||
return deleteAppInstall(install)
|
||||
tx, ctx := getTxAndContext()
|
||||
if err := deleteAppInstall(ctx, install); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
case dto.Sync:
|
||||
return a.SyncInstalled(install.ID)
|
||||
case dto.Backup:
|
||||
@ -286,36 +295,38 @@ func (a AppService) ChangeAppPort(req dto.PortUpdate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) error {
|
||||
|
||||
|
||||
func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) (*model.AppInstall, error) {
|
||||
|
||||
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%d port is in used", httpPort)
|
||||
return nil, fmt.Errorf("%d port is in used", httpPort)
|
||||
}
|
||||
httpsPort, err := checkPort("PANEL_APP_PORT_HTTPS", params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%d port is in used", httpPort)
|
||||
return nil, fmt.Errorf("%d port is in used", httpPort)
|
||||
}
|
||||
|
||||
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(appDetailId))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkRequiredAndLimit(app); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if err := copyAppData(app.Key, appDetail.Version, name, params); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
paramByte, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
appInstall := model.AppInstall{
|
||||
Name: name,
|
||||
@ -331,7 +342,7 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
||||
|
||||
composeMap := make(map[string]interface{})
|
||||
if err := yaml.Unmarshal([]byte(appDetail.DockerCompose), &composeMap); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
servicesMap := composeMap["services"].(map[string]interface{})
|
||||
changeKeys := make(map[string]string, len(servicesMap))
|
||||
@ -350,27 +361,27 @@ func (a AppService) Install(name string, appDetailId uint, params map[string]int
|
||||
}
|
||||
composeByte, err := yaml.Marshal(composeMap)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
appInstall.DockerCompose = string(composeByte)
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if err := fileOp.WriteFile(appInstall.GetComposePath(), strings.NewReader(string(composeByte)), 0775); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, ctx := getTxAndContext()
|
||||
if err := appInstallRepo.Create(ctx, &appInstall); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if err := createLink(ctx, app, &appInstall, params); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
tx.Commit()
|
||||
go upApp(appInstall.GetComposePath(), appInstall)
|
||||
return nil
|
||||
return &appInstall, nil
|
||||
}
|
||||
|
||||
func (a AppService) SyncAllInstalled() error {
|
||||
|
@ -150,7 +150,7 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteAppInstall(install model.AppInstall) error {
|
||||
func deleteAppInstall(ctx context.Context, install model.AppInstall) error {
|
||||
op := files.NewFileOp()
|
||||
appDir := install.GetPath()
|
||||
dir, _ := os.Stat(appDir)
|
||||
@ -164,20 +164,15 @@ func deleteAppInstall(install model.AppInstall) error {
|
||||
}
|
||||
}
|
||||
|
||||
tx, ctx := getTxAndContext()
|
||||
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := deleteLink(ctx, &install); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := appInstallBackupRepo.Delete(ctx, appInstallBackupRepo.WithAppInstallID(install.ID)); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2,18 +2,13 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DBContext string
|
||||
|
||||
const (
|
||||
DB DBContext = "db"
|
||||
)
|
||||
|
||||
func getTxAndContext() (tx *gorm.DB, ctx context.Context) {
|
||||
tx = global.DB.Begin()
|
||||
ctx = context.WithValue(context.Background(), DB, tx)
|
||||
ctx = context.WithValue(context.Background(), constant.DB, tx)
|
||||
return
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
@ -11,10 +13,22 @@ import (
|
||||
type WebsiteService struct {
|
||||
}
|
||||
|
||||
func (w WebsiteService) PageWebSite(req dto.WebSiteReq) (int64, []dto.WebSiteDTO, error) {
|
||||
var websiteDTOs []dto.WebSiteDTO
|
||||
total, websites, err := websiteRepo.Page(req.Page, req.PageSize)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
for _, web := range websites {
|
||||
websiteDTOs = append(websiteDTOs, dto.WebSiteDTO{
|
||||
WebSite: web,
|
||||
})
|
||||
}
|
||||
return total, websiteDTOs, nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
|
||||
|
||||
defaultDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
|
||||
|
||||
website := &model.WebSite{
|
||||
PrimaryDomain: create.PrimaryDomain,
|
||||
Type: create.Type,
|
||||
@ -26,6 +40,14 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
|
||||
WebSiteGroupID: create.WebSiteGroupID,
|
||||
}
|
||||
|
||||
if create.AppType == dto.NewApp {
|
||||
install, err := ServiceGroupApp.Install(create.AppInstall.Name, create.AppInstall.AppDetailId, create.AppInstall.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website.AppInstallID = install.ID
|
||||
}
|
||||
|
||||
tx, ctx := getTxAndContext()
|
||||
if err := websiteRepo.Create(ctx, website); err != nil {
|
||||
return err
|
||||
@ -50,7 +72,7 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := configDefaultNginx(*website, domains); err != nil {
|
||||
if err := configDefaultNginx(website, domains); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
@ -58,3 +80,38 @@ func (w WebsiteService) CreateWebsite(create dto.WebSiteCreate) error {
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w WebsiteService) DeleteWebSite(req dto.WebSiteDel) error {
|
||||
|
||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := delNginxConfig(website); err != nil {
|
||||
return err
|
||||
}
|
||||
tx, ctx := getTxAndContext()
|
||||
|
||||
if req.DeleteApp {
|
||||
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
if !reflect.DeepEqual(model.AppInstall{}, appInstall) {
|
||||
if err := deleteAppInstall(ctx, appInstall); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO 删除备份
|
||||
if err := websiteRepo.DeleteBy(ctx, commonRepo.WithByID(req.ID)); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := websiteDomainRepo.DeleteBy(ctx, websiteDomainRepo.WithWebSiteId(req.ID)); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
type WebsiteGroupService struct {
|
||||
}
|
||||
|
||||
func (w WebsiteGroupService) CreateGroup(create dto.WebSiteGroupCreateReq) error {
|
||||
func (w WebsiteGroupService) CreateGroup(create dto.WebSiteGroupCreate) error {
|
||||
return websiteGroupRepo.Create(&model.WebSiteGroup{
|
||||
Name: create.Name,
|
||||
})
|
||||
@ -18,7 +18,7 @@ func (w WebsiteGroupService) GetGroups() ([]model.WebSiteGroup, error) {
|
||||
return websiteGroupRepo.GetBy()
|
||||
}
|
||||
|
||||
func (w WebsiteGroupService) UpdateGroup(update dto.WebSiteGroupUpdateReq) error {
|
||||
func (w WebsiteGroupService) UpdateGroup(update dto.WebSiteGroupUpdate) error {
|
||||
return websiteGroupRepo.Save(&model.WebSiteGroup{
|
||||
BaseModel: model.BaseModel{
|
||||
ID: update.ID,
|
||||
|
@ -5,10 +5,12 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
|
||||
"github.com/1Panel-dev/1Panel/cmd/server/nginx_conf"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -21,6 +23,7 @@ func getDomain(domainStr string, websiteID uint) (model.WebSiteDomain, error) {
|
||||
domainArray := strings.Split(domainStr, ":")
|
||||
if len(domainArray) == 1 {
|
||||
domain.Domain = domainArray[0]
|
||||
domain.Port = 80
|
||||
return domain, nil
|
||||
}
|
||||
if len(domainArray) > 1 {
|
||||
@ -36,7 +39,7 @@ func getDomain(domainStr string, websiteID uint) (model.WebSiteDomain, error) {
|
||||
return model.WebSiteDomain{}, nil
|
||||
}
|
||||
|
||||
func configDefaultNginx(website model.WebSite, domains []model.WebSiteDomain) error {
|
||||
func configDefaultNginx(website *model.WebSite, domains []model.WebSiteDomain) error {
|
||||
|
||||
nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx"))
|
||||
if err != nil {
|
||||
@ -67,7 +70,7 @@ func configDefaultNginx(website model.WebSite, domains []model.WebSiteDomain) er
|
||||
server.UpdateListen(string(rune(domain.Port)), false)
|
||||
}
|
||||
server.UpdateServerName(serverNames)
|
||||
proxy := fmt.Sprintf("%s:%d", appInstall.ServiceName, appInstall.HttpPort)
|
||||
proxy := fmt.Sprintf("http://%s:%d", appInstall.ServiceName, appInstall.HttpPort)
|
||||
server.UpdateRootProxy([]string{proxy})
|
||||
|
||||
config.FilePath = configPath
|
||||
@ -90,3 +93,34 @@ func opNginx(containerName, operate string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func delNginxConfig(website model.WebSite) error {
|
||||
|
||||
nginxApp, err := appRepo.GetFirst(appRepo.WithKey("nginx"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nginxInstall, err := appInstallRepo.GetFirst(appInstallRepo.WithAppId(nginxApp.ID))
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
nginxFileName := website.PrimaryDomain + ".conf"
|
||||
configPath := path.Join(constant.AppInstallDir, "nginx", nginxInstall.Name, "conf", "conf.d", nginxFileName)
|
||||
fileOp := files.NewFileOp()
|
||||
|
||||
if !fileOp.Stat(configPath) {
|
||||
return nil
|
||||
}
|
||||
if err := fileOp.DeleteFile(configPath); err != nil {
|
||||
return err
|
||||
}
|
||||
return opNginx(nginxInstall.ContainerName, "reload")
|
||||
}
|
||||
|
||||
func delApp() error {
|
||||
return nil
|
||||
}
|
||||
|
7
backend/constant/common.go
Normal file
7
backend/constant/common.go
Normal file
@ -0,0 +1,7 @@
|
||||
package constant
|
||||
|
||||
type DBContext string
|
||||
|
||||
const (
|
||||
DB DBContext = "db"
|
||||
)
|
@ -16,5 +16,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
groupRouter.POST("", baseApi.CreateWebsite)
|
||||
groupRouter.POST("/search", baseApi.PageWebsite)
|
||||
groupRouter.POST("/del", baseApi.DeleteWebSite)
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ func (a *WebsiteGroupRouter) InitWebsiteGroupRouter(Router *gin.RouterGroup) {
|
||||
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
groupRouter.GET("", baseApi.GetGroups)
|
||||
groupRouter.GET("", baseApi.GetWebGroups)
|
||||
//groupRouter.GET("", baseApi.GetGroups)
|
||||
}
|
||||
}
|
||||
|
@ -39,8 +39,9 @@ export namespace App {
|
||||
}
|
||||
|
||||
export interface AppReq extends ReqPage {
|
||||
name: string;
|
||||
tags: string[];
|
||||
name?: string;
|
||||
tags?: string[];
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface AppParams {
|
||||
|
@ -1,6 +1,35 @@
|
||||
import { CommonModel } from '.';
|
||||
import { CommonModel, ReqPage } from '.';
|
||||
|
||||
export namespace WebSite {
|
||||
export interface WebSite extends CommonModel {
|
||||
primaryDomain: string;
|
||||
type: string;
|
||||
alias: string;
|
||||
remark: string;
|
||||
domains: string[];
|
||||
appType: string;
|
||||
appInstallID?: number;
|
||||
webSiteGroupID: number;
|
||||
otherDomains: string;
|
||||
appinstall?: NewAppInstall;
|
||||
}
|
||||
|
||||
export interface NewAppInstall {
|
||||
name: string;
|
||||
appDetailID: number;
|
||||
params: any;
|
||||
}
|
||||
|
||||
export interface WebSiteSearch extends ReqPage {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface WebSiteDel {
|
||||
id: number;
|
||||
deleteApp: boolean;
|
||||
deleteBackup: boolean;
|
||||
}
|
||||
|
||||
export interface WebSiteCreateReq {
|
||||
primaryDomain: string;
|
||||
type: string;
|
||||
@ -15,5 +44,6 @@ export namespace WebSite {
|
||||
|
||||
export interface Group extends CommonModel {
|
||||
name: string;
|
||||
default: boolean;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,19 @@
|
||||
import http from '@/api';
|
||||
import { ResPage } from '../interface';
|
||||
import { WebSite } from '../interface/website';
|
||||
|
||||
export const listGroups = () => {
|
||||
export const SearchWebSites = (req: WebSite.WebSiteSearch) => {
|
||||
return http.post<ResPage<WebSite.WebSite>>(`/websites/search`, req);
|
||||
};
|
||||
|
||||
export const ListGroups = () => {
|
||||
return http.get<WebSite.Group[]>(`/websites/groups`);
|
||||
};
|
||||
|
||||
export const CreateWebsite = (req: WebSite.WebSiteCreateReq) => {
|
||||
return http.post<any>(`/websites`, req);
|
||||
};
|
||||
|
||||
export const DeleteWebsite = (req: WebSite.WebSiteDel) => {
|
||||
return http.post<any>(`/websites/del`, req);
|
||||
};
|
||||
|
@ -633,6 +633,7 @@ export default {
|
||||
description: '一个现代化的 Linux 面板工具',
|
||||
},
|
||||
app: {
|
||||
app: '应用',
|
||||
installed: '已安装',
|
||||
all: '全部',
|
||||
version: '版本',
|
||||
@ -676,5 +677,8 @@ export default {
|
||||
app_new: '新装应用',
|
||||
app_installed: '已装应用',
|
||||
create: '创建网站',
|
||||
delete: '删除网站',
|
||||
deleteApp: '删除应用',
|
||||
deleteBackup: '删除备份',
|
||||
},
|
||||
};
|
||||
|
@ -54,7 +54,7 @@
|
||||
import { GetApp, GetAppDetail } from '@/api/modules/app';
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import Install from './install.vue';
|
||||
import Install from './install/index.vue';
|
||||
|
||||
interface OperateProps {
|
||||
id: number;
|
||||
|
@ -4,26 +4,7 @@
|
||||
<el-form-item :label="$t('app.name')" prop="NAME">
|
||||
<el-input v-model="form['NAME']"></el-input>
|
||||
</el-form-item>
|
||||
<div v-for="(f, index) in installData.params?.formFields" :key="index">
|
||||
<el-form-item :label="f.labelZh" :prop="f.envKey">
|
||||
<el-input v-model="form[f.envKey]" v-if="f.type == 'text'" :type="f.type"></el-input>
|
||||
<el-input v-model.number="form[f.envKey]" v-if="f.type == 'number'" :type="f.type"></el-input>
|
||||
<el-input
|
||||
v-model="form[f.envKey]"
|
||||
v-if="f.type == 'password'"
|
||||
:type="f.type"
|
||||
show-password
|
||||
></el-input>
|
||||
<el-select v-model="form[f.envKey]" v-if="f.type == 'service'">
|
||||
<el-option
|
||||
v-for="service in services"
|
||||
:key="service.label"
|
||||
:value="service.value"
|
||||
:label="service.label"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<Params v-model:form="form" v-model:params="installData.params" v-model:rules="rules"></Params>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
@ -38,12 +19,12 @@
|
||||
|
||||
<script lang="ts" setup name="appInstall">
|
||||
import { App } from '@/api/interface/app';
|
||||
import { InstallApp, GetAppService } from '@/api/modules/app';
|
||||
import { InstallApp } from '@/api/modules/app';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
import { FormInstance, FormRules } from 'element-plus';
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import Params from '../params/index.vue';
|
||||
const router = useRouter();
|
||||
|
||||
interface InstallRrops {
|
||||
@ -55,8 +36,8 @@ const installData = ref<InstallRrops>({
|
||||
appDetailId: 0,
|
||||
});
|
||||
let open = ref(false);
|
||||
let form = reactive<{ [key: string]: any }>({});
|
||||
let rules = reactive<FormRules>({
|
||||
let form = ref<{ [key: string]: any }>({});
|
||||
let rules = ref<FormRules>({
|
||||
NAME: [Rules.requiredInput],
|
||||
});
|
||||
let loading = false;
|
||||
@ -66,7 +47,6 @@ const req = reactive({
|
||||
params: {},
|
||||
name: '',
|
||||
});
|
||||
let services = ref();
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
@ -89,35 +69,9 @@ const resetForm = () => {
|
||||
|
||||
const acceptParams = (props: InstallRrops): void => {
|
||||
installData.value = props;
|
||||
const params = installData.value.params;
|
||||
if (params?.formFields != undefined) {
|
||||
for (const p of params?.formFields) {
|
||||
if (p.default == 'random') {
|
||||
form[p.envKey] = getRandomStr(6);
|
||||
} else {
|
||||
form[p.envKey] = p.default;
|
||||
}
|
||||
if (p.required) {
|
||||
rules[p.envKey] = [Rules.requiredInput];
|
||||
}
|
||||
if (p.key) {
|
||||
form[p.envKey] = '';
|
||||
getServices(p.envKey, p.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const getServices = async (envKey: string, key: string | undefined) => {
|
||||
await GetAppService(key).then((res) => {
|
||||
services.value = res.data;
|
||||
if (services.value != null) {
|
||||
form[envKey] = services.value[0].value;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
@ -125,8 +79,8 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
return;
|
||||
}
|
||||
req.appDetailId = installData.value.appDetailId;
|
||||
req.params = form;
|
||||
req.name = form['NAME'];
|
||||
req.params = form.value;
|
||||
req.name = form.value['NAME'];
|
||||
InstallApp(req).then(() => {
|
||||
handleClose();
|
||||
router.push({ path: '/apps/installed' });
|
133
frontend/src/views/app-store/detail/params/index.vue
Normal file
133
frontend/src/views/app-store/detail/params/index.vue
Normal file
@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div v-for="(p, index) in paramObjs" :key="index">
|
||||
<el-form-item :label="p.labelZh" :prop="p.prop">
|
||||
<el-input v-model="form[p.envKey]" v-if="p.type == 'text'" :type="p.type" @change="updateParam"></el-input>
|
||||
<el-input
|
||||
v-model.number="form[p.envKey]"
|
||||
v-if="p.type == 'number'"
|
||||
:type="p.type"
|
||||
@change="updateParam"
|
||||
></el-input>
|
||||
<el-input
|
||||
v-model="form[p.envKey]"
|
||||
v-if="p.type == 'password'"
|
||||
:type="p.type"
|
||||
show-password
|
||||
@change="updateParam"
|
||||
></el-input>
|
||||
<el-select v-model="form[p.envKey]" v-if="p.type == 'service'" @change="updateParam">
|
||||
<el-option
|
||||
v-for="service in p.services"
|
||||
:key="service.label"
|
||||
:value="service.value"
|
||||
:label="service.label"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
import { GetAppService } from '@/api/modules/app';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { App } from '@/api/interface/app';
|
||||
|
||||
interface ParamObj extends App.FromField {
|
||||
services: App.AppService[];
|
||||
prop: string;
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:form', 'update:rules']);
|
||||
|
||||
const props = defineProps({
|
||||
form: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
propStart: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const form = reactive({});
|
||||
let rules = reactive({});
|
||||
const params = computed({
|
||||
get() {
|
||||
return props.params;
|
||||
},
|
||||
set() {},
|
||||
});
|
||||
const propStart = computed({
|
||||
get() {
|
||||
return props.propStart;
|
||||
},
|
||||
set() {},
|
||||
});
|
||||
const paramObjs = ref<ParamObj[]>([]);
|
||||
|
||||
const updateParam = () => {
|
||||
emit('update:form', form);
|
||||
};
|
||||
|
||||
const handleParams = () => {
|
||||
rules = props.rules;
|
||||
|
||||
if (params.value != undefined && params.value.formFields != undefined) {
|
||||
for (const p of params.value.formFields) {
|
||||
const pObj = p;
|
||||
pObj.prop = propStart.value + p.envKey;
|
||||
paramObjs.value.push(pObj);
|
||||
if (p.default == 'random') {
|
||||
form[p.envKey] = getRandomStr(6);
|
||||
} else {
|
||||
form[p.envKey] = p.default;
|
||||
}
|
||||
if (p.required) {
|
||||
if (p.type === 'service') {
|
||||
rules[p.envKey] = [Rules.requiredSelect];
|
||||
} else {
|
||||
rules[p.envKey] = [Rules.requiredInput];
|
||||
}
|
||||
}
|
||||
if (p.key) {
|
||||
form[p.envKey] = '';
|
||||
getServices(p.envKey, p.key, pObj);
|
||||
}
|
||||
emit('update:rules', rules);
|
||||
updateParam();
|
||||
}
|
||||
console.log(rules);
|
||||
console.log(paramObjs);
|
||||
}
|
||||
};
|
||||
|
||||
const getServices = async (envKey: string, key: string | undefined, pObj: ParamObj) => {
|
||||
await GetAppService(key).then((res) => {
|
||||
pObj.services = res.data;
|
||||
if (res.data.length > 0) {
|
||||
form[envKey] = res.data[0].value;
|
||||
updateParam();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleParams();
|
||||
});
|
||||
</script>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('website.create')" width="40%" :before-close="handleClose">
|
||||
<el-form ref="websiteForm" label-position="right" :model="website" label-width="100px" :rules="rules">
|
||||
<el-form ref="websiteForm" label-position="right" :model="website" label-width="130px" :rules="rules">
|
||||
<el-form-item :label="$t('website.type')" prop="type">
|
||||
<el-select v-model="website.type">
|
||||
<el-option :label="$t('website.deployment')" value="deployment"></el-option>
|
||||
@ -19,7 +19,7 @@
|
||||
</el-form-item>
|
||||
<div v-if="website.type === 'deployment'">
|
||||
<el-form-item prop="appType">
|
||||
<el-radio-group v-model="website.appType">
|
||||
<el-radio-group v-model="website.appType" @change="changeAppType(website.appType)">
|
||||
<el-radio :label="'installed'" :value="'installed'">
|
||||
{{ $t('website.app_installed') }}
|
||||
</el-radio>
|
||||
@ -42,6 +42,45 @@
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<div v-if="website.appType == 'new'">
|
||||
<el-form-item :label="$t('app.app')" prop="appinstall.appID">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-select v-model="website.appinstall.appID" @change="getApp()">
|
||||
<el-option
|
||||
v-for="(app, index) in apps"
|
||||
:key="index"
|
||||
:label="app.name"
|
||||
:value="app.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-select
|
||||
v-model="website.appinstall.version"
|
||||
@change="getAppDetail(website.appinstall.version)"
|
||||
>
|
||||
<el-option
|
||||
v-for="(version, index) in appVersions"
|
||||
:key="index"
|
||||
:label="version"
|
||||
:value="version"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('app.name')" prop="appinstall.name">
|
||||
<el-input v-model="website.appinstall.name"></el-input>
|
||||
</el-form-item>
|
||||
<Params
|
||||
:key="paramKey"
|
||||
v-model:form="website.appinstall.params"
|
||||
v-model:rules="rules.appinstall.params"
|
||||
:params="appParams"
|
||||
:propStart="'appinstall.params.'"
|
||||
></Params>
|
||||
</div>
|
||||
</div>
|
||||
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
||||
<el-input v-model="website.primaryDomain"></el-input>
|
||||
@ -59,7 +98,7 @@
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit(websiteForm)" :disabled="loading">
|
||||
<el-button type="primary" @click="submit(websiteForm)" :loading="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
@ -70,53 +109,125 @@
|
||||
<script lang="ts" setup name="CreateWebSite">
|
||||
import { App } from '@/api/interface/app';
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
import { SearchAppInstalled } from '@/api/modules/app';
|
||||
import { CreateWebsite, listGroups } from '@/api/modules/website';
|
||||
import { GetApp, GetAppDetail, SearchApp, SearchAppInstalled } from '@/api/modules/app';
|
||||
import { CreateWebsite, ListGroups } from '@/api/modules/website';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { FormRules, ElDialog, ElForm, FormInstance } from 'element-plus';
|
||||
import i18n from '@/lang';
|
||||
import { ElDialog, ElForm, FormInstance, ElMessage } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import Params from '@/views/app-store/detail/params/index.vue';
|
||||
|
||||
const websiteForm = ref<FormInstance>();
|
||||
const website = reactive({
|
||||
const website = ref({
|
||||
primaryDomain: '',
|
||||
type: 'deployment',
|
||||
alias: '',
|
||||
remark: '',
|
||||
domains: [],
|
||||
appType: 'installed',
|
||||
appInstallID: 0,
|
||||
appInstallID: null,
|
||||
webSiteGroupID: 1,
|
||||
otherDomains: '',
|
||||
appinstall: {
|
||||
appID: null,
|
||||
name: '',
|
||||
appDetailID: null,
|
||||
params: {},
|
||||
version: '',
|
||||
},
|
||||
});
|
||||
let rules = reactive<FormRules>({
|
||||
let rules = ref({
|
||||
primaryDomain: [Rules.requiredInput],
|
||||
alias: [Rules.requiredInput],
|
||||
type: [Rules.requiredInput],
|
||||
webSiteGroupID: [Rules.requiredInput],
|
||||
appInstallID: [Rules.requiredInput],
|
||||
appType: [Rules.requiredInput],
|
||||
appinstall: {
|
||||
name: [Rules.requiredInput],
|
||||
appID: [Rules.requiredInput],
|
||||
params: {},
|
||||
},
|
||||
});
|
||||
|
||||
let open = ref(false);
|
||||
let loading = ref(false);
|
||||
let groups = ref<WebSite.Group[]>([]);
|
||||
let appInstalles = ref<App.AppInstalled[]>([]);
|
||||
let appReq = reactive({
|
||||
type: 'website',
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
});
|
||||
let apps = ref<App.App[]>([]);
|
||||
let appVersions = ref<string[]>([]);
|
||||
let appDetail = ref<App.AppDetail>();
|
||||
let appParams = ref<App.AppParams>();
|
||||
let paramKey = ref(1);
|
||||
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const searchAppInstalled = () => {
|
||||
SearchAppInstalled({ type: 'website' }).then((res) => {
|
||||
appInstalles.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
website.value.appInstallID = res.data[0].id;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const searchApp = () => {
|
||||
SearchApp(appReq).then((res) => {
|
||||
apps.value = res.data.items;
|
||||
if (res.data.items.length > 0) {
|
||||
website.value.appinstall.appID = res.data.items[0].id;
|
||||
getApp();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getApp = () => {
|
||||
GetApp(website.value.appinstall.appID).then((res) => {
|
||||
appVersions.value = res.data.versions;
|
||||
if (res.data.versions.length > 0) {
|
||||
website.value.appinstall.version = res.data.versions[0];
|
||||
getAppDetail(res.data.versions[0]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getAppDetail = (version: string) => {
|
||||
GetAppDetail(website.value.appinstall.appID, version).then((res) => {
|
||||
website.value.appinstall.appDetailID = res.data.id;
|
||||
appDetail.value = res.data;
|
||||
appParams.value = res.data.params;
|
||||
paramKey.value++;
|
||||
});
|
||||
};
|
||||
|
||||
const acceptParams = async () => {
|
||||
await listGroups().then((res) => {
|
||||
if (websiteForm.value) {
|
||||
websiteForm.value.resetFields();
|
||||
}
|
||||
|
||||
await ListGroups().then((res) => {
|
||||
groups.value = res.data;
|
||||
open.value = true;
|
||||
});
|
||||
await SearchAppInstalled({ type: 'website' }).then((res) => {
|
||||
appInstalles.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
website.appInstallID = res.data[0].id;
|
||||
}
|
||||
});
|
||||
searchAppInstalled();
|
||||
};
|
||||
|
||||
const changeAppType = (type: string) => {
|
||||
if (type === 'installed') {
|
||||
searchAppInstalled();
|
||||
} else {
|
||||
searchApp();
|
||||
}
|
||||
};
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
@ -125,7 +236,15 @@ const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
CreateWebsite(website).then(() => {});
|
||||
loading.value = true;
|
||||
CreateWebsite(website.value)
|
||||
.then(() => {
|
||||
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
||||
handleClose();
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
65
frontend/src/views/website/project/delete/index.vue
Normal file
65
frontend/src/views/website/project/delete/index.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<el-dialog v-model="open" :title="$t('website.delete')" width="40%" :before-close="handleClose">
|
||||
<div style="text-align: center">
|
||||
<el-checkbox v-model="deleteReq.deleteApp" :label="$t('website.deleteApp')" />
|
||||
<el-checkbox v-model="deleteReq.deleteBackup" :label="$t('website.deleteBackup')" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submit()" :disabled="loading" :loading="loading">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { DeleteWebsite } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
|
||||
// interface DeleteProps {
|
||||
// id: number;
|
||||
// }
|
||||
// const deleteData = ref<DeleteProps>({
|
||||
// id: 0,
|
||||
// });
|
||||
|
||||
let open = ref(false);
|
||||
let loading = ref(false);
|
||||
let deleteReq = reactive({
|
||||
id: 0,
|
||||
deleteApp: false,
|
||||
deleteBackup: false,
|
||||
});
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', false);
|
||||
};
|
||||
|
||||
const acceptParams = async (id: number) => {
|
||||
deleteReq.id = id;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = () => {
|
||||
loading.value = true;
|
||||
DeleteWebsite(deleteReq)
|
||||
.then(() => {
|
||||
handleClose();
|
||||
ElMessage.success(i18n.global.t('commons.msg.deleteSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -23,29 +23,42 @@
|
||||
fix
|
||||
/>
|
||||
</ComplexTable>
|
||||
<CreateWebSite ref="createRef"></CreateWebSite>
|
||||
<CreateWebSite ref="createRef" @close="search"></CreateWebSite>
|
||||
<DeleteWebsite ref="deleteRef" @close="search"></DeleteWebsite>
|
||||
</LayoutContent>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import LayoutContent from '@/layout/layout-content.vue';
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import { onMounted, ref } from '@vue/runtime-core';
|
||||
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
||||
import router from '@/routers';
|
||||
import CreateWebSite from './create/index.vue';
|
||||
import DeleteWebsite from './delete/index.vue';
|
||||
import { SearchWebSites } from '@/api/modules/website';
|
||||
import i18n from '@/lang';
|
||||
import { WebSite } from '@/api/interface/website';
|
||||
|
||||
const createRef = ref();
|
||||
const deleteRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const data = ref();
|
||||
const search = async () => {
|
||||
data.value = [
|
||||
{
|
||||
primaryDomain: 'www.baicu.com',
|
||||
status: 'Running',
|
||||
backup: '1',
|
||||
remark: '主网站',
|
||||
},
|
||||
];
|
||||
const req = {
|
||||
name: '',
|
||||
page: paginationConfig.currentPage,
|
||||
pageSize: paginationConfig.pageSize,
|
||||
};
|
||||
|
||||
SearchWebSites(req).then((res) => {
|
||||
data.value = res.data.items;
|
||||
});
|
||||
};
|
||||
|
||||
const openConfig = () => {
|
||||
@ -57,8 +70,18 @@ const buttons = [
|
||||
label: '设置',
|
||||
click: open,
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('app.delete'),
|
||||
click: function (row: WebSite.WebSite) {
|
||||
openDelete(row.id);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const openDelete = (id: number) => {
|
||||
deleteRef.value.acceptParams(id);
|
||||
};
|
||||
|
||||
const openCreate = () => {
|
||||
createRef.value.acceptParams();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user