mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-27 20:49:03 +08:00
feat: 网站子目录绑定域名 (#6098)
Refs https://github.com/1Panel-dev/1Panel/issues/2336 Refs https://github.com/1Panel-dev/1Panel/issues/6024
This commit is contained in:
parent
e0f628c59f
commit
c7c5f75d17
@ -52,9 +52,13 @@ func (b *BaseApi) GetWebsites(c *gin.Context) {
|
||||
// @Description 获取网站列表
|
||||
// @Success 200 {array} string
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /websites/options [get]
|
||||
// @Router /websites/options [post]
|
||||
func (b *BaseApi) GetWebsiteOptions(c *gin.Context) {
|
||||
websites, err := websiteService.GetWebsiteOptions()
|
||||
var req request.WebsiteOptionReq
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
websites, err := websiteService.GetWebsiteOptions(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
@ -27,8 +27,9 @@ type WebsiteCreate struct {
|
||||
AppID uint `json:"appID"`
|
||||
AppInstallID uint `json:"appInstallID"`
|
||||
|
||||
RuntimeID uint `json:"runtimeID"`
|
||||
TaskID string `json:"taskID"`
|
||||
RuntimeID uint `json:"runtimeID"`
|
||||
TaskID string `json:"taskID"`
|
||||
ParentWebsiteID uint `json:"parentWebsiteID"`
|
||||
|
||||
RuntimeConfig
|
||||
FtpConfig
|
||||
@ -36,6 +37,10 @@ type WebsiteCreate struct {
|
||||
SSLConfig
|
||||
}
|
||||
|
||||
type WebsiteOptionReq struct {
|
||||
Types []string `json:"types"`
|
||||
}
|
||||
|
||||
type RuntimeConfig struct {
|
||||
ProxyType string `json:"proxyType"`
|
||||
Port int `json:"port"`
|
||||
|
@ -32,6 +32,7 @@ type WebsiteRes struct {
|
||||
SSLExpireDate time.Time `json:"sslExpireDate"`
|
||||
SSLStatus string `json:"sslStatus"`
|
||||
AppInstallID uint `json:"appInstallId"`
|
||||
ChildSites []string `json:"childSites"`
|
||||
}
|
||||
|
||||
type WebsiteOption struct {
|
||||
|
@ -4,32 +4,33 @@ import "time"
|
||||
|
||||
type Website struct {
|
||||
BaseModel
|
||||
Protocol string `gorm:"type:varchar;not null" json:"protocol"`
|
||||
PrimaryDomain string `gorm:"type:varchar;not null" json:"primaryDomain"`
|
||||
Type string `gorm:"type:varchar;not null" json:"type"`
|
||||
Alias string `gorm:"type:varchar;not null" json:"alias"`
|
||||
Remark string `gorm:"type:longtext;" json:"remark"`
|
||||
Status string `gorm:"type:varchar;not null" json:"status"`
|
||||
HttpConfig string `gorm:"type:varchar;not null" json:"httpConfig"`
|
||||
Protocol string `gorm:"not null" json:"protocol"`
|
||||
PrimaryDomain string `gorm:"not null" json:"primaryDomain"`
|
||||
Type string `gorm:"not null" json:"type"`
|
||||
Alias string `gorm:"not null" json:"alias"`
|
||||
Remark string `json:"remark"`
|
||||
Status string `gorm:"not null" json:"status"`
|
||||
HttpConfig string `gorm:"not null" json:"httpConfig"`
|
||||
ExpireDate time.Time `json:"expireDate"`
|
||||
|
||||
Proxy string `gorm:"type:varchar;" json:"proxy"`
|
||||
ProxyType string `gorm:"type:varchar;" json:"proxyType"`
|
||||
SiteDir string `gorm:"type:varchar;" json:"siteDir"`
|
||||
Proxy string `json:"proxy"`
|
||||
ProxyType string `json:"proxyType"`
|
||||
SiteDir string `json:"siteDir"`
|
||||
ErrorLog bool `json:"errorLog"`
|
||||
AccessLog bool `json:"accessLog"`
|
||||
DefaultServer bool `json:"defaultServer"`
|
||||
IPV6 bool `json:"IPV6"`
|
||||
Rewrite string `gorm:"type:varchar" json:"rewrite"`
|
||||
Rewrite string `json:"rewrite"`
|
||||
|
||||
WebsiteGroupID uint `gorm:"type:integer" json:"webSiteGroupId"`
|
||||
WebsiteSSLID uint `gorm:"type:integer" json:"webSiteSSLId"`
|
||||
RuntimeID uint `gorm:"type:integer" json:"runtimeID"`
|
||||
AppInstallID uint `gorm:"type:integer" json:"appInstallId"`
|
||||
FtpID uint `gorm:"type:integer" json:"ftpId"`
|
||||
WebsiteGroupID uint `json:"webSiteGroupId"`
|
||||
WebsiteSSLID uint `json:"webSiteSSLId"`
|
||||
RuntimeID uint `json:"runtimeID"`
|
||||
AppInstallID uint `json:"appInstallId"`
|
||||
FtpID uint `json:"ftpId"`
|
||||
ParentWebsiteID uint `json:"parentWebsiteID"`
|
||||
|
||||
User string `gorm:"type:varchar;" json:"user"`
|
||||
Group string `gorm:"type:varchar;" json:"group"`
|
||||
User string `json:"user"`
|
||||
Group string `json:"group"`
|
||||
|
||||
DbType string `json:"dbType"`
|
||||
DbID uint `json:"dbID"`
|
||||
|
@ -19,6 +19,9 @@ type IWebsiteRepo interface {
|
||||
WithDomainLike(domain string) DBOption
|
||||
WithRuntimeID(runtimeID uint) DBOption
|
||||
WithIDs(ids []uint) DBOption
|
||||
WithTypes(types []string) DBOption
|
||||
WithParentID(websiteID uint) DBOption
|
||||
|
||||
Page(page, size int, opts ...DBOption) (int64, []model.Website, error)
|
||||
List(opts ...DBOption) ([]model.Website, error)
|
||||
GetFirst(opts ...DBOption) (model.Website, error)
|
||||
@ -49,6 +52,12 @@ func (w *WebsiteRepo) WithIDs(ids []uint) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebsiteRepo) WithTypes(types []string) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("type in (?)", types)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebsiteRepo) WithRuntimeID(runtimeID uint) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("runtime_id = ?", runtimeID)
|
||||
@ -79,6 +88,12 @@ func (w *WebsiteRepo) WithWebsiteSSLID(sslId uint) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebsiteRepo) WithParentID(websiteID uint) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("parent_website_id = ?", websiteID)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WebsiteRepo) WithGroupID(groupId uint) DBOption {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
return db.Where("website_group_id = ?", groupId)
|
||||
|
@ -59,7 +59,7 @@ type IWebsiteService interface {
|
||||
GetWebsites() ([]response.WebsiteDTO, error)
|
||||
CreateWebsite(create request.WebsiteCreate) error
|
||||
OpWebsite(req request.WebsiteOp) error
|
||||
GetWebsiteOptions() ([]response.WebsiteOption, error)
|
||||
GetWebsiteOptions(req request.WebsiteOptionReq) ([]response.WebsiteOption, error)
|
||||
UpdateWebsite(req request.WebsiteUpdate) error
|
||||
DeleteWebsite(req request.WebsiteDelete) error
|
||||
GetWebsite(id uint) (response.WebsiteDTO, error)
|
||||
@ -170,7 +170,7 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
|
||||
}
|
||||
sitePath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "www", "sites", web.Alias)
|
||||
|
||||
websiteDTOs = append(websiteDTOs, response.WebsiteRes{
|
||||
siteDTO := response.WebsiteRes{
|
||||
ID: web.ID,
|
||||
CreatedAt: web.CreatedAt,
|
||||
Protocol: web.Protocol,
|
||||
@ -186,7 +186,15 @@ func (w WebsiteService) PageWebsite(req request.WebsiteSearch) (int64, []respons
|
||||
RuntimeName: runtimeName,
|
||||
SitePath: sitePath,
|
||||
AppInstallID: appInstallID,
|
||||
})
|
||||
}
|
||||
|
||||
sites, _ := websiteRepo.List(websiteRepo.WithParentID(web.ID))
|
||||
if len(sites) > 0 {
|
||||
for _, site := range sites {
|
||||
siteDTO.ChildSites = append(siteDTO.ChildSites, site.PrimaryDomain)
|
||||
}
|
||||
}
|
||||
websiteDTOs = append(websiteDTOs, siteDTO)
|
||||
}
|
||||
return total, websiteDTOs, nil
|
||||
}
|
||||
@ -198,9 +206,10 @@ func (w WebsiteService) GetWebsites() ([]response.WebsiteDTO, error) {
|
||||
return nil, err
|
||||
}
|
||||
for _, web := range websites {
|
||||
websiteDTOs = append(websiteDTOs, response.WebsiteDTO{
|
||||
res := response.WebsiteDTO{
|
||||
Website: web,
|
||||
})
|
||||
}
|
||||
websiteDTOs = append(websiteDTOs, res)
|
||||
}
|
||||
return websiteDTOs, nil
|
||||
}
|
||||
@ -364,37 +373,47 @@ func (w WebsiteService) CreateWebsite(create request.WebsiteCreate) (err error)
|
||||
return err
|
||||
}
|
||||
website.RuntimeID = runtime.ID
|
||||
if runtime.Type == constant.RuntimePHP {
|
||||
var (
|
||||
req request.AppInstallCreate
|
||||
install *model.AppInstall
|
||||
)
|
||||
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
|
||||
req.Name = reg.ReplaceAllString(strings.ToLower(alias), "")
|
||||
req.AppDetailId = create.AppInstall.AppDetailId
|
||||
req.Params = create.AppInstall.Params
|
||||
req.Params["IMAGE_NAME"] = runtime.Image
|
||||
req.AppContainerConfig = create.AppInstall.AppContainerConfig
|
||||
req.Params["PANEL_WEBSITE_DIR"] = path.Join(nginxInstall.GetPath(), "/www")
|
||||
install, err = NewIAppService().Install(req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
switch runtime.Type {
|
||||
case constant.RuntimePHP:
|
||||
if runtime.Resource == constant.ResourceAppstore {
|
||||
var (
|
||||
req request.AppInstallCreate
|
||||
install *model.AppInstall
|
||||
)
|
||||
reg, _ := regexp.Compile(`[^a-z0-9_-]+`)
|
||||
req.Name = reg.ReplaceAllString(strings.ToLower(alias), "")
|
||||
req.AppDetailId = create.AppInstall.AppDetailId
|
||||
req.Params = create.AppInstall.Params
|
||||
req.Params["IMAGE_NAME"] = runtime.Image
|
||||
req.AppContainerConfig = create.AppInstall.AppContainerConfig
|
||||
req.Params["PANEL_WEBSITE_DIR"] = path.Join(nginxInstall.GetPath(), "/www")
|
||||
install, err = NewIAppService().Install(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website.AppInstallID = install.ID
|
||||
appInstall = install
|
||||
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
|
||||
} else {
|
||||
website.ProxyType = create.ProxyType
|
||||
if website.ProxyType == constant.RuntimeProxyUnix {
|
||||
proxy = fmt.Sprintf("unix:%s", path.Join("/www/sites", website.Alias, "php-pool", "php-fpm.sock"))
|
||||
}
|
||||
if website.ProxyType == constant.RuntimeProxyTcp {
|
||||
proxy = fmt.Sprintf("127.0.0.1:%d", create.Port)
|
||||
}
|
||||
website.Proxy = proxy
|
||||
}
|
||||
website.AppInstallID = install.ID
|
||||
appInstall = install
|
||||
website.Proxy = fmt.Sprintf("127.0.0.1:%d", appInstall.HttpPort)
|
||||
} else {
|
||||
website.ProxyType = create.ProxyType
|
||||
if website.ProxyType == constant.RuntimeProxyUnix {
|
||||
proxy = fmt.Sprintf("unix:%s", path.Join("/www/sites", website.Alias, "php-pool", "php-fpm.sock"))
|
||||
}
|
||||
if website.ProxyType == constant.RuntimeProxyTcp {
|
||||
proxy = fmt.Sprintf("127.0.0.1:%d", create.Port)
|
||||
}
|
||||
website.Proxy = proxy
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
|
||||
}
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
|
||||
website.Proxy = fmt.Sprintf("127.0.0.1:%d", runtime.Port)
|
||||
case constant.Subsite:
|
||||
parentWebsite, err := websiteRepo.GetFirst(commonRepo.WithByID(create.ParentWebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website.ParentWebsiteID = parentWebsite.ID
|
||||
}
|
||||
|
||||
if len(create.FtpUser) != 0 && len(create.FtpPassword) != 0 {
|
||||
@ -489,8 +508,12 @@ func (w WebsiteService) OpWebsite(req request.WebsiteOp) error {
|
||||
return websiteRepo.Save(context.Background(), &website)
|
||||
}
|
||||
|
||||
func (w WebsiteService) GetWebsiteOptions() ([]response.WebsiteOption, error) {
|
||||
webs, err := websiteRepo.List()
|
||||
func (w WebsiteService) GetWebsiteOptions(req request.WebsiteOptionReq) ([]response.WebsiteOption, error) {
|
||||
var options []repo.DBOption
|
||||
if len(req.Types) > 0 {
|
||||
options = append(options, websiteRepo.WithTypes(req.Types))
|
||||
}
|
||||
webs, err := websiteRepo.List(options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -556,6 +579,16 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if website.Type != constant.Subsite {
|
||||
parentWebsites, _ := websiteRepo.List(websiteRepo.WithParentID(website.ID))
|
||||
if len(parentWebsites) > 0 {
|
||||
var names []string
|
||||
for _, site := range parentWebsites {
|
||||
names = append(names, site.PrimaryDomain)
|
||||
}
|
||||
return buserr.WithName("ErrParentWebsite", strings.Join(names, ","))
|
||||
}
|
||||
}
|
||||
if err = delNginxConfig(website, req.ForceDelete); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -2759,7 +2792,7 @@ func (w WebsiteService) LoadWebsiteDirConfig(req request.WebsiteCommonReq) (*res
|
||||
}
|
||||
res.Dirs = []string{"/"}
|
||||
for _, file := range indexFiles {
|
||||
if !file.IsDir() {
|
||||
if !file.IsDir() || file.Name() == "node_modules" || file.Name() == "vendor" {
|
||||
continue
|
||||
}
|
||||
res.Dirs = append(res.Dirs, fmt.Sprintf("/%s", file.Name()))
|
||||
|
@ -231,12 +231,9 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
case constant.RuntimePHP:
|
||||
server.UpdateDirective("error_page", []string{"404", "/404.html"})
|
||||
if runtime.Resource == constant.ResourceLocal {
|
||||
switch runtime.Type {
|
||||
case constant.RuntimePHP:
|
||||
server.UpdateRoot(rootIndex)
|
||||
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
}
|
||||
server.UpdateRoot(rootIndex)
|
||||
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
} else {
|
||||
server.UpdateRoot(rootIndex)
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, "")
|
||||
@ -245,6 +242,34 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
||||
proxy := fmt.Sprintf("http://127.0.0.1:%d", runtime.Port)
|
||||
server.UpdateRootProxy([]string{proxy})
|
||||
}
|
||||
case constant.Subsite:
|
||||
parentWebsite, err := websiteRepo.GetFirst(commonRepo.WithByID(website.ParentWebsiteID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website.Proxy = parentWebsite.Proxy
|
||||
rootIndex = path.Join("/www/sites", parentWebsite.Alias, "index", website.SiteDir)
|
||||
server.UpdateDirective("error_page", []string{"404", "/404.html"})
|
||||
if parentWebsite.Type == constant.Runtime {
|
||||
parentRuntime, err := runtimeRepo.GetFirst(commonRepo.WithByID(parentWebsite.RuntimeID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
website.RuntimeID = parentRuntime.ID
|
||||
if parentRuntime.Type == constant.RuntimePHP {
|
||||
if parentRuntime.Resource == constant.ResourceLocal {
|
||||
server.UpdateRoot(rootIndex)
|
||||
localPath := path.Join(nginxInstall.GetPath(), rootIndex, "index.php")
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
|
||||
} else {
|
||||
server.UpdateRoot(rootIndex)
|
||||
server.UpdatePHPProxy([]string{website.Proxy}, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
if parentWebsite.Type == constant.Static {
|
||||
server.UpdateRoot(rootIndex)
|
||||
}
|
||||
}
|
||||
|
||||
config.FilePath = configPath
|
||||
|
@ -14,6 +14,7 @@ const (
|
||||
Static = "static"
|
||||
Proxy = "proxy"
|
||||
Runtime = "runtime"
|
||||
Subsite = "subsite"
|
||||
|
||||
SSLExisted = "existed"
|
||||
SSLAuto = "auto"
|
||||
|
@ -94,6 +94,7 @@ ErrPathPermission: 'A folder with non-1000:1000 permissions was detected in the
|
||||
ErrDomainIsUsed: "Domain is already used by website {{ .name }}"
|
||||
ErrDomainFormat: "{{ .name }} domain format error"
|
||||
ErrDefaultAlias: "default is a reserved code name, please use another code name"
|
||||
ErrParentWebsite: "You need to delete the subsite(s) {{ .name }} first"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "The certificate {{ .name }} is being used by the website and cannot be removed"
|
||||
|
@ -94,6 +94,7 @@ ErrPathPermission: 'index 目錄下偵測到非 1000:1000 權限資料夾,可
|
||||
ErrDomainIsUsed: "域名已被網站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正確"
|
||||
ErrDefaultAlias: "default 為保留代號,請使用其他代號"
|
||||
ErrParentWebsite: "需要先刪除子網站 {{ .name }}"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 證書正在被網站使用,無法刪除"
|
||||
|
@ -94,6 +94,7 @@ ErrPathPermission: 'index 目录下检测到非 1000:1000 权限文件夹,可
|
||||
ErrDomainIsUsed: "域名已被网站【{{ .name }}】使用"
|
||||
ErrDomainFormat: "{{ .name }} 域名格式不正确"
|
||||
ErrDefaultAlias: "default 为保留代号,请使用其他代号"
|
||||
ErrParentWebsite: "需要先删除子网站 {{ .name }}"
|
||||
|
||||
#ssl
|
||||
ErrSSLCannotDelete: "{{ .name }} 证书正在被网站使用,无法删除"
|
||||
|
@ -290,7 +290,7 @@ var AddTask = &gormigrate.Migration{
|
||||
}
|
||||
|
||||
var UpdateWebsite = &gormigrate.Migration{
|
||||
ID: "20240807-update-website",
|
||||
ID: "20240812-update-website",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
return tx.AutoMigrate(
|
||||
&model.Website{})
|
||||
|
@ -19,7 +19,7 @@ func (a *WebsiteRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
websiteRouter.POST("/operate", baseApi.OpWebsite)
|
||||
websiteRouter.POST("/log", baseApi.OpWebsiteLog)
|
||||
websiteRouter.POST("/check", baseApi.CreateWebsiteCheck)
|
||||
websiteRouter.GET("/options", baseApi.GetWebsiteOptions)
|
||||
websiteRouter.POST("/options", baseApi.GetWebsiteOptions)
|
||||
websiteRouter.POST("/update", baseApi.UpdateWebsite)
|
||||
websiteRouter.GET("/:id", baseApi.GetWebsite)
|
||||
websiteRouter.POST("/del", baseApi.DeleteWebsite)
|
||||
|
@ -17,4 +17,5 @@ type System struct {
|
||||
Entrance string `mapstructure:"entrance"`
|
||||
IsDemo bool `mapstructure:"is_demo"`
|
||||
ChangeUserInfo string `mapstructure:"change_user_info"`
|
||||
DbPath string `mapstructure:"db_path"`
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ export namespace Website {
|
||||
IPV6: boolean;
|
||||
accessLog?: boolean;
|
||||
errorLog?: boolean;
|
||||
childSites?: string[];
|
||||
}
|
||||
|
||||
export interface WebsiteDTO extends Website {
|
||||
@ -111,6 +112,10 @@ export namespace Website {
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export interface OptionReq {
|
||||
types?: string[];
|
||||
}
|
||||
|
||||
export interface WebSiteLog {
|
||||
enable: boolean;
|
||||
content: string;
|
||||
|
@ -38,8 +38,8 @@ export const GetWebsite = (id: number) => {
|
||||
return http.get<Website.WebsiteDTO>(`/websites/${id}`);
|
||||
};
|
||||
|
||||
export const GetWebsiteOptions = () => {
|
||||
return http.get<Array<string>>(`/websites/options`);
|
||||
export const GetWebsiteOptions = (req: Website.OptionReq) => {
|
||||
return http.post<any>(`/websites/options`, req);
|
||||
};
|
||||
|
||||
export const GetWebsiteConfig = (id: number, type: string) => {
|
||||
|
@ -2134,6 +2134,10 @@ const message = {
|
||||
domainSSLHelper:
|
||||
'Enabling SSL on a non-443 port will cause the 443 port to stop listening. If you need the 443 port to continue listening, please add the domain:443',
|
||||
global: 'Global',
|
||||
subsite: 'Subsite',
|
||||
subsiteHelper: 'A subsite can select an existing PHP or static website directory as the main directory.',
|
||||
parentWbeiste: 'Parent Website',
|
||||
deleteSubsite: 'To delete the current website, you must first delete the subsite(s) {0}',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: 'Short tag support',
|
||||
|
@ -1983,6 +1983,10 @@ const message = {
|
||||
generateDomain: '生成',
|
||||
domainSSLHelper: '非 443 端口開啟 SSL 會導致 443 端口移除監聽,如需 443 端口繼續監聽,請添加域名:443',
|
||||
global: '全局',
|
||||
subsite: '子網站',
|
||||
subsiteHelper: '子網站可以選擇已存在的 PHP 和靜態網站的目錄作為主目錄。',
|
||||
parentWbeiste: '父級網站',
|
||||
deleteSubsite: '刪除當前網站需要先刪除子網站 {0}',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短標簽支持',
|
||||
|
@ -1985,6 +1985,10 @@ const message = {
|
||||
generateDomain: '生成',
|
||||
domainSSLHelper: '非 443 端口开启 SSL 会导致 443 端口去掉监听,如需 443 端口继续监听,请添加域名:443',
|
||||
global: '全局',
|
||||
subsite: '子网站',
|
||||
subsiteHelper: '子网站可以选择已存在的 PHP 和静态网站的目录作为主目录',
|
||||
parentWbeiste: '父级网站',
|
||||
deleteSubsite: '删除当前网站需要先删除子网站 {0}',
|
||||
},
|
||||
php: {
|
||||
short_open_tag: '短标签支持',
|
||||
|
@ -632,7 +632,7 @@ const loadAppInstalls = async () => {
|
||||
};
|
||||
|
||||
const loadWebsites = async () => {
|
||||
const res = await GetWebsiteOptions();
|
||||
const res = await GetWebsiteOptions({});
|
||||
websiteOptions.value = res.data || [];
|
||||
};
|
||||
|
||||
|
@ -161,17 +161,10 @@ const initData = () => {
|
||||
dirs.value = [];
|
||||
};
|
||||
|
||||
function filterDirectories(directories: any[]) {
|
||||
return directories.filter((dir) => {
|
||||
return dir !== '/node_modules' && dir !== '/vendor';
|
||||
});
|
||||
}
|
||||
|
||||
const getDirConfig = async () => {
|
||||
try {
|
||||
const res = await GetDirConfig({ id: props.id });
|
||||
dirs.value = res.data.dirs;
|
||||
dirs.value = filterDirectories(dirs.value);
|
||||
dirConfig.value = res.data;
|
||||
} catch (error) {}
|
||||
};
|
||||
|
@ -21,6 +21,10 @@
|
||||
label: i18n.global.t('website.static'),
|
||||
value: 'static',
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('website.subsite'),
|
||||
value: 'subsite',
|
||||
},
|
||||
]"
|
||||
:key="item.value"
|
||||
>
|
||||
@ -62,6 +66,12 @@
|
||||
type="info"
|
||||
:closable="false"
|
||||
/>
|
||||
<el-alert
|
||||
v-if="website.type == 'subsite'"
|
||||
:title="$t('website.subsiteHelper')"
|
||||
type="info"
|
||||
:closable="false"
|
||||
/>
|
||||
<br />
|
||||
<el-form
|
||||
ref="websiteForm"
|
||||
@ -147,6 +157,28 @@
|
||||
></Params>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="website.type === 'subsite'">
|
||||
<el-form-item :label="$t('website.parentWbeiste')" prop="parentWebsiteID">
|
||||
<el-select v-model="website.parentWebsiteID" @change="getDirConfig(website.parentWebsiteID)">
|
||||
<el-option
|
||||
v-for="(site, index) in parentWebsites"
|
||||
:key="index"
|
||||
:label="site.primaryDomain"
|
||||
:value="site.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('website.runDir')" prop="siteDir">
|
||||
<el-select v-model="website.siteDir" filterable class="p-w-200">
|
||||
<el-option
|
||||
v-for="(item, index) in dirs"
|
||||
:label="item"
|
||||
:value="item"
|
||||
:key="index"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-if="website.type === 'runtime'">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
@ -496,7 +528,14 @@
|
||||
<script lang="ts" setup name="CreateWebSite">
|
||||
import { App } from '@/api/interface/app';
|
||||
import { GetApp, GetAppDetail, SearchApp, GetAppInstalled, GetAppDetailByID } from '@/api/modules/app';
|
||||
import { CreateWebsite, ListSSL, PreCheck, SearchAcmeAccount } from '@/api/modules/website';
|
||||
import {
|
||||
CreateWebsite,
|
||||
GetWebsiteOptions,
|
||||
ListSSL,
|
||||
PreCheck,
|
||||
SearchAcmeAccount,
|
||||
GetDirConfig,
|
||||
} from '@/api/modules/website';
|
||||
import { Rules, checkNumberRange } from '@/global/form-rules';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm, FormInstance } from 'element-plus';
|
||||
@ -565,6 +604,8 @@ const initData = () => ({
|
||||
websiteSSLID: undefined,
|
||||
acmeAccountID: undefined,
|
||||
domains: [],
|
||||
parentWebsiteID: undefined,
|
||||
siteDir: '',
|
||||
});
|
||||
const website = ref(initData());
|
||||
const rules = ref<any>({
|
||||
@ -594,6 +635,8 @@ const rules = ref<any>({
|
||||
dbPassword: [Rules.requiredInput, Rules.paramComplexity],
|
||||
dbHost: [Rules.requiredSelect],
|
||||
websiteSSLID: [Rules.requiredSelect],
|
||||
parentWebsiteID: [Rules.requiredSelect],
|
||||
siteDir: [Rules.requiredSelect],
|
||||
});
|
||||
|
||||
const open = ref(false);
|
||||
@ -626,6 +669,8 @@ const taskLog = ref();
|
||||
const dbServices = ref();
|
||||
const ssls = ref();
|
||||
const websiteSSL = ref();
|
||||
const parentWebsites = ref();
|
||||
const dirs = ref([]);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
@ -656,6 +701,9 @@ const changeType = (type: string) => {
|
||||
website.value.proxyAddress = '';
|
||||
searchAppInstalled('proxy');
|
||||
break;
|
||||
case 'subsite':
|
||||
listWebsites();
|
||||
break;
|
||||
default:
|
||||
website.value.appInstallId = undefined;
|
||||
break;
|
||||
@ -885,6 +933,27 @@ const changeAlias = (value: string) => {
|
||||
website.value.alias = domain;
|
||||
};
|
||||
|
||||
const listWebsites = async () => {
|
||||
try {
|
||||
const res = await GetWebsiteOptions({ types: ['static', 'runtime'] });
|
||||
parentWebsites.value = res.data;
|
||||
if (res.data.length > 0) {
|
||||
website.value.parentWebsiteID = res.data[0].id;
|
||||
getDirConfig(res.data[0].id);
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const getDirConfig = async (websiteID: number) => {
|
||||
try {
|
||||
const res = await GetDirConfig({ id: websiteID });
|
||||
dirs.value = res.data.dirs;
|
||||
if (res.data.dirs.length > 0) {
|
||||
website.value.siteDir = res.data.dirs[0];
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
|
@ -23,16 +23,22 @@
|
||||
<span class="input-help">
|
||||
{{ $t('website.deleteAppHelper') }}
|
||||
</span>
|
||||
<span class="input-help" style="color: red" v-if="runtimeApp">
|
||||
<span class="input-help text-red-500" v-if="runtimeApp">
|
||||
{{ $t('website.deleteRuntimeHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="deleteReq.deleteBackup" :label="$t('website.deleteBackup')" />
|
||||
<span class="input-help">
|
||||
{{ $t('website.deleteBackupHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="subSites != ''">
|
||||
<span class="input-help text-red-500">
|
||||
{{ $t('website.deleteSubsite', [subSites]) }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<span v-html="deleteHelper"></span>
|
||||
<el-input v-model="deleteInfo" :placeholder="websiteName" />
|
||||
@ -74,6 +80,7 @@ const deleteInfo = ref('');
|
||||
const websiteName = ref('');
|
||||
const deleteHelper = ref('');
|
||||
const runtimeApp = ref(false);
|
||||
const subSites = ref('');
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
@ -87,10 +94,14 @@ const acceptParams = async (website: Website.Website) => {
|
||||
deleteBackup: false,
|
||||
forceDelete: false,
|
||||
};
|
||||
subSites.value = '';
|
||||
if (website.type === 'runtime' && website.appInstallId > 0) {
|
||||
runtimeApp.value = true;
|
||||
deleteReq.value.deleteApp = true;
|
||||
}
|
||||
if (website.childSites && website.childSites.length > 0) {
|
||||
subSites.value = website.childSites.join(',');
|
||||
}
|
||||
deleteInfo.value = '';
|
||||
deleteReq.value.id = website.id;
|
||||
websiteName.value = website.primaryDomain;
|
||||
|
Loading…
Reference in New Issue
Block a user